3933625c39ed6702c4f303defcfb52a90eb30665
1 #define __NR_ARENA_GLYPHS_C__
3 /*
4 * RGBA display list system for inkscape
5 *
6 * Author:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * Copyright (C) 2002 Lauris Kaplinski
10 *
11 * Released under GNU GPL
12 *
13 */
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
19 #include <libnr/nr-blit.h>
20 #include <libnr/nr-path.h>
21 #include <libnr/n-art-bpath.h>
22 #include <libnr/nr-matrix-ops.h>
23 #include <libnr/nr-matrix-fns.h>
24 #include "../style.h"
25 #include "nr-arena.h"
26 #include "nr-arena-glyphs.h"
27 #include <cairo.h>
28 #include "inkscape-cairo.h"
30 #ifdef test_glyph_liv
31 #include "../display/canvas-bpath.h"
32 #include <libnrtype/font-instance.h>
33 #include <libnrtype/raster-glyph.h>
34 #include <libnrtype/RasterFont.h>
36 // defined in nr-arena-shape.cpp
37 void nr_pixblock_render_shape_mask_or(NRPixBlock &m, Shape *theS);
38 #endif
40 static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass);
41 static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs);
42 static void nr_arena_glyphs_finalize(NRObject *object);
44 static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
45 static guint nr_arena_glyphs_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
46 static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, NR::Point p, double delta, unsigned int sticky);
48 static NRArenaItemClass *glyphs_parent_class;
50 NRType
51 nr_arena_glyphs_get_type(void)
52 {
53 static NRType type = 0;
54 if (!type) {
55 type = nr_object_register_type(NR_TYPE_ARENA_ITEM,
56 "NRArenaGlyphs",
57 sizeof(NRArenaGlyphsClass),
58 sizeof(NRArenaGlyphs),
59 (void (*)(NRObjectClass *)) nr_arena_glyphs_class_init,
60 (void (*)(NRObject *)) nr_arena_glyphs_init);
61 }
62 return type;
63 }
65 static void
66 nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass)
67 {
68 NRObjectClass *object_class;
69 NRArenaItemClass *item_class;
71 object_class = (NRObjectClass *) klass;
72 item_class = (NRArenaItemClass *) klass;
74 glyphs_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
76 object_class->finalize = nr_arena_glyphs_finalize;
77 object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>;
79 item_class->update = nr_arena_glyphs_update;
80 item_class->clip = nr_arena_glyphs_clip;
81 item_class->pick = nr_arena_glyphs_pick;
82 }
84 static void
85 nr_arena_glyphs_init(NRArenaGlyphs *glyphs)
86 {
87 glyphs->style = NULL;
88 nr_matrix_set_identity(&glyphs->g_transform);
89 glyphs->font = NULL;
90 glyphs->glyph = 0;
92 glyphs->rfont = NULL;
93 glyphs->sfont = NULL;
94 glyphs->x = glyphs->y = 0.0;
95 }
97 static void
98 nr_arena_glyphs_finalize(NRObject *object)
99 {
100 NRArenaGlyphs *glyphs = static_cast<NRArenaGlyphs *>(object);
102 if (glyphs->rfont) {
103 glyphs->rfont->Unref();
104 glyphs->rfont=NULL;
105 }
106 if (glyphs->sfont) {
107 glyphs->sfont->Unref();
108 glyphs->sfont=NULL;
109 }
111 if (glyphs->font) {
112 glyphs->font->Unref();
113 glyphs->font=NULL;
114 }
116 if (glyphs->style) {
117 sp_style_unref(glyphs->style);
118 glyphs->style = NULL;
119 }
121 ((NRObjectClass *) glyphs_parent_class)->finalize(object);
122 }
124 static guint
125 nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
126 {
127 NRArenaGlyphs *glyphs;
128 raster_font *rfont;
130 glyphs = NR_ARENA_GLYPHS(item);
132 if (!glyphs->font || !glyphs->style)
133 return NR_ARENA_ITEM_STATE_ALL;
134 if ((glyphs->style->fill.isNone()) && (glyphs->style->stroke.isNone()))
135 return NR_ARENA_ITEM_STATE_ALL;
137 NRRect bbox;
138 bbox.x0 = bbox.y0 = NR_HUGE;
139 bbox.x1 = bbox.y1 = -NR_HUGE;
141 float const scale = NR_MATRIX_DF_EXPANSION(&gc->transform);
143 if (!glyphs->style->fill.isNone()) {
144 NRMatrix t;
145 nr_matrix_multiply(&t, &glyphs->g_transform, &gc->transform);
146 glyphs->x = t.c[4];
147 glyphs->y = t.c[5];
148 t.c[4]=0;
149 t.c[5]=0;
150 rfont = glyphs->font->RasterFont(t, 0);
151 if (glyphs->rfont) glyphs->rfont->Unref();
152 glyphs->rfont = rfont;
154 if (glyphs->style->stroke.isNone() || fabs(glyphs->style->stroke_width.computed * scale) <= 0.01) { // Optimization: do fill bbox only if there's no stroke
155 NRRect narea;
156 if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea);
157 bbox.x0 = narea.x0 + glyphs->x;
158 bbox.y0 = narea.y0 + glyphs->y;
159 bbox.x1 = narea.x1 + glyphs->x;
160 bbox.y1 = narea.y1 + glyphs->y;
161 }
162 }
164 if (!glyphs->style->stroke.isNone()) {
165 /* Build state data */
166 NRMatrix t;
167 nr_matrix_multiply(&t, &glyphs->g_transform, &gc->transform);
168 glyphs->x = t.c[4];
169 glyphs->y = t.c[5];
170 t.c[4]=0;
171 t.c[5]=0;
173 if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
174 font_style nstyl;
175 nstyl.transform = t;
176 nstyl.stroke_width=MAX(0.125, glyphs->style->stroke_width.computed * scale);
177 if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight;
178 if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round;
179 if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square;
180 if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy;
181 if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round;
182 if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight;
183 nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value;
184 nstyl.nbDash=0;
185 nstyl.dashes=NULL;
186 if ( glyphs->style->stroke_dash.n_dash > 0 ) {
187 nstyl.nbDash=glyphs->style->stroke_dash.n_dash;
188 nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double));
189 for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale;
190 }
191 rfont = glyphs->font->RasterFont( nstyl);
192 if ( nstyl.dashes ) free(nstyl.dashes);
193 if (glyphs->sfont) glyphs->sfont->Unref();
194 glyphs->sfont = rfont;
196 NRRect narea;
197 if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea);
198 narea.x0-=nstyl.stroke_width;
199 narea.y0-=nstyl.stroke_width;
200 narea.x1+=nstyl.stroke_width;
201 narea.y1+=nstyl.stroke_width;
202 bbox.x0 = narea.x0 + glyphs->x;
203 bbox.y0 = narea.y0 + glyphs->y;
204 bbox.x1 = narea.x1 + glyphs->x;
205 bbox.y1 = narea.y1 + glyphs->y;
206 }
207 }
208 if (nr_rect_d_test_empty(&bbox)) return NR_ARENA_ITEM_STATE_ALL;
210 item->bbox.x0 = (gint32)(bbox.x0 - 1.0);
211 item->bbox.y0 = (gint32)(bbox.y0 - 1.0);
212 item->bbox.x1 = (gint32)(bbox.x1 + 1.0);
213 item->bbox.y1 = (gint32)(bbox.y1 + 1.0);
214 nr_arena_request_render_rect(item->arena, &item->bbox);
216 return NR_ARENA_ITEM_STATE_ALL;
217 }
219 static guint
220 nr_arena_glyphs_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
221 {
222 NRArenaGlyphs *glyphs;
224 glyphs = NR_ARENA_GLYPHS(item);
226 if (!glyphs->font ) return item->state;
228 /* TODO : render to greyscale pixblock provided for clipping */
230 return item->state;
231 }
233 static NRArenaItem *
234 nr_arena_glyphs_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
235 {
236 NRArenaGlyphs *glyphs;
238 glyphs = NR_ARENA_GLYPHS(item);
240 if (!glyphs->font ) return NULL;
241 if (!glyphs->style) return NULL;
243 double const x = p[NR::X];
244 double const y = p[NR::Y];
245 /* With text we take a simple approach: pick if the point is in a characher bbox */
246 if ((x >= item->bbox.x0) && (y >= item->bbox.y0) && (x <= item->bbox.x1) && (y <= item->bbox.y1)) return item;
248 return NULL;
249 }
251 void
252 nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve *curve, unsigned int lieutenant, font_instance *font, gint glyph, NRMatrix const *transform)
253 {
254 nr_return_if_fail(glyphs != NULL);
255 nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));
257 nr_arena_item_request_render(NR_ARENA_ITEM(glyphs));
259 if (transform) {
260 glyphs->g_transform = *transform;
261 } else {
262 nr_matrix_set_identity(&glyphs->g_transform);
263 }
265 if (font) font->Ref();
266 if (glyphs->font) glyphs->font->Unref();
267 glyphs->font=font;
268 glyphs->glyph = glyph;
270 nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
271 }
273 void
274 nr_arena_glyphs_set_style(NRArenaGlyphs *glyphs, SPStyle *style)
275 {
276 nr_return_if_fail(glyphs != NULL);
277 nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));
279 if (style) sp_style_ref(style);
280 if (glyphs->style) sp_style_unref(glyphs->style);
281 glyphs->style = style;
283 nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
284 }
286 static guint
287 nr_arena_glyphs_fill_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
288 {
289 /* fixme: area == m->area, so merge these */
291 NRArenaItem *item = NR_ARENA_ITEM(glyphs);
293 if (glyphs->rfont && nr_rect_l_test_intersect(area, &item->bbox)) {
294 raster_glyph *g = glyphs->rfont->GetGlyph(glyphs->glyph);
295 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y), *m);
296 }
298 return item->state;
299 }
301 static guint
302 nr_arena_glyphs_stroke_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
303 {
304 NRArenaItem *item = NR_ARENA_ITEM(glyphs);
305 if (glyphs->sfont && nr_rect_l_test_intersect(area, &item->bbox)) {
306 raster_glyph *g=glyphs->sfont->GetGlyph(glyphs->glyph);
307 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
308 }
310 return item->state;
311 }
313 static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass);
314 static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group);
315 static void nr_arena_glyphs_group_finalize(NRObject *object);
317 static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
318 static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
319 static unsigned int nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
320 static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky);
322 static NRArenaGroupClass *group_parent_class;
324 NRType
325 nr_arena_glyphs_group_get_type(void)
326 {
327 static NRType type = 0;
328 if (!type) {
329 type = nr_object_register_type(NR_TYPE_ARENA_GROUP,
330 "NRArenaGlyphsGroup",
331 sizeof(NRArenaGlyphsGroupClass),
332 sizeof(NRArenaGlyphsGroup),
333 (void (*)(NRObjectClass *)) nr_arena_glyphs_group_class_init,
334 (void (*)(NRObject *)) nr_arena_glyphs_group_init);
335 }
336 return type;
337 }
339 static void
340 nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass)
341 {
342 NRObjectClass *object_class;
343 NRArenaItemClass *item_class;
345 object_class = (NRObjectClass *) klass;
346 item_class = (NRArenaItemClass *) klass;
348 group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;
350 object_class->finalize = nr_arena_glyphs_group_finalize;
351 object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;
353 item_class->update = nr_arena_glyphs_group_update;
354 item_class->render = nr_arena_glyphs_group_render;
355 item_class->clip = nr_arena_glyphs_group_clip;
356 item_class->pick = nr_arena_glyphs_group_pick;
357 }
359 static void
360 nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group)
361 {
362 group->style = NULL;
363 group->paintbox.x0 = group->paintbox.y0 = 0.0F;
364 group->paintbox.x1 = group->paintbox.y1 = 1.0F;
366 group->fill_painter = NULL;
367 group->stroke_painter = NULL;
368 }
370 static void
371 nr_arena_glyphs_group_finalize(NRObject *object)
372 {
373 NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
375 if (group->fill_painter) {
376 sp_painter_free(group->fill_painter);
377 group->fill_painter = NULL;
378 }
380 if (group->stroke_painter) {
381 sp_painter_free(group->stroke_painter);
382 group->stroke_painter = NULL;
383 }
385 if (group->style) {
386 sp_style_unref(group->style);
387 group->style = NULL;
388 }
390 ((NRObjectClass *) group_parent_class)->finalize(object);
391 }
393 static guint
394 nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
395 {
396 NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item);
398 if (group->fill_painter) {
399 sp_painter_free(group->fill_painter);
400 group->fill_painter = NULL;
401 }
403 if (group->stroke_painter) {
404 sp_painter_free(group->stroke_painter);
405 group->stroke_painter = NULL;
406 }
408 item->render_opacity = TRUE;
409 if (group->style->fill.isPaintserver()) {
410 group->fill_painter = sp_paint_server_painter_new(SP_STYLE_FILL_SERVER(group->style),
411 NR::Matrix(&gc->transform), NR::Matrix(&gc->parent->transform),
412 &group->paintbox);
413 item->render_opacity = FALSE;
414 }
416 if (group->style->stroke.isPaintserver()) {
417 group->stroke_painter = sp_paint_server_painter_new(SP_STYLE_STROKE_SERVER(group->style),
418 NR::Matrix(&gc->transform), NR::Matrix(&gc->parent->transform),
419 &group->paintbox);
420 item->render_opacity = FALSE;
421 }
423 if ( item->render_opacity == TRUE && !group->style->stroke.isNone() && !group->style->fill.isNone() ) {
424 item->render_opacity=FALSE;
425 }
427 if (((NRArenaItemClass *) group_parent_class)->update)
428 return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset);
430 return NR_ARENA_ITEM_STATE_ALL;
431 }
434 static unsigned int
435 nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
436 {
437 NRArenaItem *child;
439 NRArenaGroup *group = NR_ARENA_GROUP(item);
440 NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item);
441 SPStyle const *style = ggroup->style;
443 guint ret = item->state;
445 if (item->arena->rendermode == RENDERMODE_OUTLINE) {
447 if (!ct)
448 return item->state;
450 guint32 rgba = item->arena->outlinecolor;
451 // FIXME: we use RGBA buffers but cairo writes BGRA (on i386), so we must cheat
452 // by setting color channels in the "wrong" order
453 cairo_set_source_rgba(ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba));
454 cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode
456 for (child = group->children; child != NULL; child = child->next) {
457 NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);
459 NArtBpath *bpath = (NArtBpath *) g->font->ArtBPath(g->glyph);
461 cairo_new_path(ct);
462 NR::Matrix g_t(g->g_transform);
463 feed_curve_to_cairo (ct, bpath, g_t * group->ctm, (pb->area).upgrade(), false, 0);
464 cairo_fill(ct);
465 pb->empty = FALSE;
466 }
468 return ret;
469 }
473 /* Fill */
474 if (!style->fill.isNone() || item->arena->rendermode == RENDERMODE_OUTLINE) {
475 NRPixBlock m;
476 nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
478 // if memory allocation failed, abort
479 if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
480 nr_pixblock_release (&m);
481 return (item->state);
482 }
484 m.visible_area = pb->visible_area;
486 /* Render children fill mask */
487 for (child = group->children; child != NULL; child = child->next) {
488 ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, &m);
489 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
490 nr_pixblock_release(&m);
491 return ret;
492 }
493 }
495 /* Composite into buffer */
496 if (style->fill.isPaintserver()) {
497 if (ggroup->fill_painter) {
498 nr_arena_render_paintserver_fill(pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT(style->fill_opacity.value), &m);
499 }
500 } else if (style->fill.isColor() || item->arena->rendermode == RENDERMODE_OUTLINE) {
501 guint32 rgba;
502 if (item->arena->rendermode == RENDERMODE_OUTLINE) {
503 // In outline mode, render fill only, using outlinecolor
504 rgba = item->arena->outlinecolor;
505 } else if ( item->render_opacity ) {
506 rgba = sp_color_get_rgba32_falpha(&style->fill.value.color,
507 SP_SCALE24_TO_FLOAT(style->fill_opacity.value) *
508 SP_SCALE24_TO_FLOAT(style->opacity.value));
509 } else {
510 rgba = sp_color_get_rgba32_falpha(&style->fill.value.color, SP_SCALE24_TO_FLOAT(style->fill_opacity.value));
511 }
512 nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
513 pb->empty = FALSE;
514 }
516 nr_pixblock_release(&m);
517 }
519 /* Stroke */
520 if (!style->stroke.isNone() && !(item->arena->rendermode == RENDERMODE_OUTLINE)) {
521 NRPixBlock m;
522 guint32 rgba;
523 nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
525 // if memory allocation failed, abort
526 if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
527 nr_pixblock_release (&m);
528 return (item->state);
529 }
531 m.visible_area = pb->visible_area;
532 /* Render children stroke mask */
533 for (child = group->children; child != NULL; child = child->next) {
534 ret = nr_arena_glyphs_stroke_mask(NR_ARENA_GLYPHS(child), area, &m);
535 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
536 nr_pixblock_release(&m);
537 return ret;
538 }
539 }
540 /* Composite into buffer */
541 if (style->stroke.isPaintserver()) {
542 if (ggroup->stroke_painter) {
543 nr_arena_render_paintserver_fill(pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value), &m);
544 }
545 } else if (style->stroke.isColor()) {
546 if ( item->render_opacity ) {
547 rgba = sp_color_get_rgba32_falpha(&style->stroke.value.color,
548 SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) *
549 SP_SCALE24_TO_FLOAT(style->opacity.value));
550 } else {
551 rgba = sp_color_get_rgba32_falpha(&style->stroke.value.color,
552 SP_SCALE24_TO_FLOAT(style->stroke_opacity.value));
553 }
554 nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
555 pb->empty = FALSE;
556 } else {
557 // nothing
558 }
559 nr_pixblock_release(&m);
560 }
562 return ret;
563 }
565 static unsigned int
566 nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
567 {
568 NRArenaGroup *group = NR_ARENA_GROUP(item);
570 guint ret = item->state;
572 /* Render children fill mask */
573 for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
574 ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, pb);
575 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret;
576 }
578 return ret;
579 }
581 static NRArenaItem *
582 nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
583 {
584 NRArenaItem *picked = NULL;
586 if (((NRArenaItemClass *) group_parent_class)->pick)
587 picked = ((NRArenaItemClass *) group_parent_class)->pick(item, p, delta, sticky);
589 if (picked) picked = item;
591 return picked;
592 }
594 void
595 nr_arena_glyphs_group_clear(NRArenaGlyphsGroup *sg)
596 {
597 NRArenaGroup *group = NR_ARENA_GROUP(sg);
599 nr_arena_item_request_render(NR_ARENA_ITEM(group));
601 while (group->children) {
602 nr_arena_item_remove_child(NR_ARENA_ITEM(group), group->children);
603 }
604 }
606 void
607 nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, NRMatrix const *transform)
608 {
609 NRArenaGroup *group;
610 NRBPath bpath;
612 group = NR_ARENA_GROUP(sg);
614 bpath.path = ( font
615 ? (NArtBpath *) font->ArtBPath(glyph)
616 : NULL );
617 if ( bpath.path ) {
619 nr_arena_item_request_render(NR_ARENA_ITEM(group));
621 NRArenaItem *new_arena = NRArenaGlyphs::create(group->arena);
622 nr_arena_item_append_child(NR_ARENA_ITEM(group), new_arena);
623 nr_arena_item_unref(new_arena);
624 nr_arena_glyphs_set_path(NR_ARENA_GLYPHS(new_arena), NULL, FALSE, font, glyph, transform);
625 nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(new_arena), sg->style);
626 }
627 }
629 void
630 nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style)
631 {
632 nr_return_if_fail(sg != NULL);
633 nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(sg));
635 NRArenaGroup *group = NR_ARENA_GROUP(sg);
637 if (style) sp_style_ref(style);
638 if (sg->style) sp_style_unref(sg->style);
639 sg->style = style;
641 for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
642 nr_return_if_fail(NR_IS_ARENA_GLYPHS(child));
643 nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(child), sg->style);
644 }
646 nr_arena_item_request_update(NR_ARENA_ITEM(sg), NR_ARENA_ITEM_STATE_ALL, FALSE);
647 }
649 void
650 nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox)
651 {
652 nr_return_if_fail(gg != NULL);
653 nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg));
654 nr_return_if_fail(pbox != NULL);
656 if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
657 gg->paintbox.x0 = pbox->x0;
658 gg->paintbox.y0 = pbox->y0;
659 gg->paintbox.x1 = pbox->x1;
660 gg->paintbox.y1 = pbox->y1;
661 } else {
662 /* fixme: We kill warning, although not sure what to do here (Lauris) */
663 gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
664 gg->paintbox.x1 = gg->paintbox.y1 = 256.0F;
665 }
667 nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE);
668 }
671 /*
672 Local Variables:
673 mode:c++
674 c-file-style:"stroustrup"
675 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
676 indent-tabs-mode:nil
677 fill-column:99
678 End:
679 */
680 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :