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 "../style.h"
22 #include "nr-arena.h"
23 #include "nr-arena-glyphs.h"
25 #ifdef test_glyph_liv
26 #include "../display/canvas-bpath.h"
27 #include <libnrtype/font-instance.h>
28 #include <libnrtype/raster-glyph.h>
29 #include <libnrtype/RasterFont.h>
31 // defined in nr-arena-shape.cpp
32 void nr_pixblock_render_shape_mask_or (NRPixBlock &m,Shape* theS);
33 #endif
35 static void nr_arena_glyphs_class_init (NRArenaGlyphsClass *klass);
36 static void nr_arena_glyphs_init (NRArenaGlyphs *glyphs);
37 static void nr_arena_glyphs_finalize (NRObject *object);
39 static guint nr_arena_glyphs_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
40 static guint nr_arena_glyphs_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
41 static NRArenaItem *nr_arena_glyphs_pick (NRArenaItem *item, NR::Point p, double delta, unsigned int sticky);
43 static NRArenaItemClass *glyphs_parent_class;
45 NRType
46 nr_arena_glyphs_get_type (void)
47 {
48 static NRType type = 0;
49 if (!type) {
50 type = nr_object_register_type (NR_TYPE_ARENA_ITEM,
51 "NRArenaGlyphs",
52 sizeof (NRArenaGlyphsClass),
53 sizeof (NRArenaGlyphs),
54 (void (*) (NRObjectClass *)) nr_arena_glyphs_class_init,
55 (void (*) (NRObject *)) nr_arena_glyphs_init);
56 }
57 return type;
58 }
60 static void
61 nr_arena_glyphs_class_init (NRArenaGlyphsClass *klass)
62 {
63 NRObjectClass *object_class;
64 NRArenaItemClass *item_class;
66 object_class = (NRObjectClass *) klass;
67 item_class = (NRArenaItemClass *) klass;
69 glyphs_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
71 object_class->finalize = nr_arena_glyphs_finalize;
72 object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>;
74 item_class->update = nr_arena_glyphs_update;
75 item_class->clip = nr_arena_glyphs_clip;
76 item_class->pick = nr_arena_glyphs_pick;
77 }
79 static void
80 nr_arena_glyphs_init (NRArenaGlyphs *glyphs)
81 {
82 glyphs->style = NULL;
83 nr_matrix_set_identity(&glyphs->g_transform);
84 glyphs->font = NULL;
85 glyphs->glyph = 0;
87 glyphs->rfont = NULL;
88 glyphs->sfont = NULL;
89 glyphs->x = glyphs->y = 0.0;
91 // nr_matrix_set_identity(&glyphs->cached_tr);
92 // glyphs->cached_shp=NULL;
93 // glyphs->cached_shp_dirty=false;
94 // glyphs->cached_style_dirty=false;
96 // glyphs->stroke_shp=NULL;
97 }
99 static void
100 nr_arena_glyphs_finalize (NRObject *object)
101 {
102 NRArenaGlyphs *glyphs=static_cast<NRArenaGlyphs *>(object);
104 // if (glyphs->cached_shp) {
105 // delete glyphs->cached_shp;
106 // glyphs->cached_shp = NULL;
107 // }
108 // if (glyphs->stroke_shp) {
109 // delete glyphs->stroke_shp;
110 // glyphs->stroke_shp = NULL;
111 // }
113 if (glyphs->rfont) {
114 glyphs->rfont->Unref();
115 glyphs->rfont=NULL;
116 }
117 if (glyphs->sfont) {
118 glyphs->sfont->Unref();
119 glyphs->sfont=NULL;
120 }
122 if (glyphs->font) {
123 glyphs->font->Unref();
124 glyphs->font=NULL;
125 }
127 if (glyphs->style) {
128 sp_style_unref (glyphs->style);
129 glyphs->style = NULL;
130 }
132 ((NRObjectClass *) glyphs_parent_class)->finalize (object);
133 }
135 static guint
136 nr_arena_glyphs_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
137 {
138 NRArenaGlyphs *glyphs;
139 raster_font *rfont;
141 glyphs = NR_ARENA_GLYPHS (item);
143 if (!glyphs->font || !glyphs->style) return NR_ARENA_ITEM_STATE_ALL;
144 if ((glyphs->style->fill.type == SP_PAINT_TYPE_NONE) && (glyphs->style->stroke.type == SP_PAINT_TYPE_NONE)) return NR_ARENA_ITEM_STATE_ALL;
146 NRRect bbox;
147 bbox.x0 = bbox.y0 = NR_HUGE;
148 bbox.x1 = bbox.y1 = -NR_HUGE;
150 if (glyphs->style->fill.type != SP_PAINT_TYPE_NONE) {
151 NRMatrix t;
152 nr_matrix_multiply (&t, &glyphs->g_transform, &gc->transform);
153 glyphs->x = t.c[4];
154 glyphs->y = t.c[5];
155 t.c[4]=0;
156 t.c[5]=0;
157 rfont = glyphs->font->RasterFont(t, 0);
158 if (glyphs->rfont) glyphs->rfont->Unref();
159 glyphs->rfont = rfont;
161 if (glyphs->style->stroke.type == SP_PAINT_TYPE_NONE) { // Optimization: do fill bbox only if there's no stroke
162 NRRect narea;
163 if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea);
164 bbox.x0 = narea.x0 + glyphs->x;
165 bbox.y0 = narea.y0 + glyphs->y;
166 bbox.x1 = narea.x1 + glyphs->x;
167 bbox.y1 = narea.y1 + glyphs->y;
168 }
169 }
171 if (glyphs->style->stroke.type != SP_PAINT_TYPE_NONE) {
172 /* Build state data */
173 NRMatrix t;
174 nr_matrix_multiply (&t, &glyphs->g_transform, &gc->transform);
175 glyphs->x = t.c[4];
176 glyphs->y = t.c[5];
177 t.c[4]=0;
178 t.c[5]=0;
180 const float scale = NR_MATRIX_DF_EXPANSION (&gc->transform);
181 if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
182 font_style nstyl;
183 nstyl.transform = t;
184 nstyl.stroke_width=MAX (0.125, glyphs->style->stroke_width.computed * scale);
185 if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight;
186 if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round;
187 if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square;
188 if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy;
189 if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round;
190 if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight;
191 nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value;
192 nstyl.nbDash=0;
193 nstyl.dashes=NULL;
194 if ( glyphs->style->stroke_dash.n_dash > 0 ) {
195 nstyl.nbDash=glyphs->style->stroke_dash.n_dash;
196 nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double));
197 for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale;
198 }
199 rfont = glyphs->font->RasterFont( nstyl);
200 if ( nstyl.dashes ) free(nstyl.dashes);
201 if (glyphs->sfont) glyphs->sfont->Unref();
202 glyphs->sfont = rfont;
204 NRRect narea;
205 if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea);
206 narea.x0-=nstyl.stroke_width;
207 narea.y0-=nstyl.stroke_width;
208 narea.x1+=nstyl.stroke_width;
209 narea.y1+=nstyl.stroke_width;
210 bbox.x0 = narea.x0 + glyphs->x;
211 bbox.y0 = narea.y0 + glyphs->y;
212 bbox.x1 = narea.x1 + glyphs->x;
213 bbox.y1 = narea.y1 + glyphs->y;
214 }
215 }
216 if (nr_rect_d_test_empty(&bbox)) return NR_ARENA_ITEM_STATE_ALL;
218 item->bbox.x0 = (gint32)(bbox.x0 - 1.0);
219 item->bbox.y0 = (gint32)(bbox.y0 - 1.0);
220 item->bbox.x1 = (gint32)(bbox.x1 + 1.0);
221 item->bbox.y1 = (gint32)(bbox.y1 + 1.0);
222 nr_arena_request_render_rect (item->arena, &item->bbox);
224 return NR_ARENA_ITEM_STATE_ALL;
225 }
227 static guint
228 nr_arena_glyphs_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
229 {
230 NRArenaGlyphs *glyphs;
232 glyphs = NR_ARENA_GLYPHS (item);
234 if (!glyphs->font ) return item->state;
236 /* TODO : render to greyscale pixblock provided for clipping */
238 return item->state;
239 }
241 static NRArenaItem *
242 nr_arena_glyphs_pick (NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
243 {
244 NRArenaGlyphs *glyphs;
246 glyphs = NR_ARENA_GLYPHS (item);
248 if (!glyphs->font ) return NULL;
249 if (!glyphs->style) return NULL;
251 const double x = p[NR::X];
252 const double y = p[NR::Y];
253 /* With text we take a simple approach: pick if the point is in a characher bbox */
254 if ((x >= item->bbox.x0) && (y >= item->bbox.y0) && (x <= item->bbox.x1) && (y <= item->bbox.y1)) return item;
256 /* NR::Point const thePt = p;
257 if (glyphs->stroke_shp && (glyphs->style->stroke.type != SP_PAINT_TYPE_NONE)) {
258 if (glyphs->stroke_shp->PtWinding(thePt) > 0 ) return item;
259 }
260 if (delta > 1e-3) {
261 if (glyphs->stroke_shp && (glyphs->style->stroke.type != SP_PAINT_TYPE_NONE)) {
262 if ( glyphs->stroke_shp->DistanceLE(thePt, delta)) return item;
263 }
264 }*/
266 return NULL;
267 }
269 void
270 nr_arena_glyphs_set_path (NRArenaGlyphs *glyphs, SPCurve *curve, unsigned int lieutenant, font_instance *font, gint glyph, const NRMatrix *transform)
271 {
272 nr_return_if_fail (glyphs != NULL);
273 nr_return_if_fail (NR_IS_ARENA_GLYPHS (glyphs));
275 nr_arena_item_request_render (NR_ARENA_ITEM (glyphs));
277 // glyphs->cached_shp_dirty=true;
279 if (transform) {
280 glyphs->g_transform = *transform;
281 } else {
282 nr_matrix_set_identity (&glyphs->g_transform);
283 }
285 //printf("glyph_setpath ");
286 if ( font ) font->Ref();
287 if ( glyphs->font ) glyphs->font->Unref();
288 glyphs->font=font;
289 glyphs->glyph = glyph;
291 nr_arena_item_request_update (NR_ARENA_ITEM (glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
292 }
294 void
295 nr_arena_glyphs_set_style (NRArenaGlyphs *glyphs, SPStyle *style)
296 {
297 nr_return_if_fail (glyphs != NULL);
298 nr_return_if_fail (NR_IS_ARENA_GLYPHS (glyphs));
300 // glyphs->cached_style_dirty=true;
302 if (style) sp_style_ref (style);
303 if (glyphs->style) sp_style_unref (glyphs->style);
304 glyphs->style = style;
306 nr_arena_item_request_update (NR_ARENA_ITEM (glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
307 }
309 static guint
310 nr_arena_glyphs_fill_mask (NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
311 {
312 NRArenaItem *item;
314 /* fixme: area == m->area, so merge these */
316 item = NR_ARENA_ITEM (glyphs);
318 if (glyphs->rfont && nr_rect_l_test_intersect (area, &item->bbox)) {
319 raster_glyph* g=glyphs->rfont->GetGlyph(glyphs->glyph);
320 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
321 }
323 return item->state;
324 }
326 static guint
327 nr_arena_glyphs_stroke_mask (NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
328 {
329 NRArenaItem *item;
331 item = NR_ARENA_ITEM (glyphs);
332 if (glyphs->sfont && nr_rect_l_test_intersect (area, &item->bbox)) {
333 raster_glyph* g=glyphs->sfont->GetGlyph(glyphs->glyph);
334 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
335 }
336 /* if (glyphs->stroke_shp && nr_rect_l_test_intersect (area, &item->bbox)) {
337 NRPixBlock gb;
338 gint x, y;
339 nr_pixblock_setup_fast (&gb, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
340 // art_gray_svp_aa is just fillung apparently
341 // dunno why it's used here instead of its libnr counterpart
342 nr_pixblock_render_shape_mask_or (gb,glyphs->stroke_shp);
343 for (y = area->y0; y < area->y1; y++) {
344 guchar *d, *s;
345 d = NR_PIXBLOCK_PX (m) + (y - area->y0) * m->rs;
346 s = NR_PIXBLOCK_PX (&gb) + (y - area->y0) * gb.rs;
347 for (x = area->x0; x < area->x1; x++) {
348 *d = (*d) + ((255 - *d) * (*s) / 255);
349 d += 1;
350 s += 1;
351 }
352 }
353 nr_pixblock_release (&gb);
354 m->empty = FALSE;
355 }*/
357 return item->state;
358 }
360 static void nr_arena_glyphs_group_class_init (NRArenaGlyphsGroupClass *klass);
361 static void nr_arena_glyphs_group_init (NRArenaGlyphsGroup *group);
362 static void nr_arena_glyphs_group_finalize (NRObject *object);
364 static guint nr_arena_glyphs_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
365 static unsigned int nr_arena_glyphs_group_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
366 static unsigned int nr_arena_glyphs_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
367 static NRArenaItem *nr_arena_glyphs_group_pick (NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky);
369 static NRArenaGroupClass *group_parent_class;
371 NRType
372 nr_arena_glyphs_group_get_type (void)
373 {
374 static NRType type = 0;
375 if (!type) {
376 type = nr_object_register_type (NR_TYPE_ARENA_GROUP,
377 "NRArenaGlyphsGroup",
378 sizeof (NRArenaGlyphsGroupClass),
379 sizeof (NRArenaGlyphsGroup),
380 (void (*) (NRObjectClass *)) nr_arena_glyphs_group_class_init,
381 (void (*) (NRObject *)) nr_arena_glyphs_group_init);
382 }
383 return type;
384 }
386 static void
387 nr_arena_glyphs_group_class_init (NRArenaGlyphsGroupClass *klass)
388 {
389 NRObjectClass *object_class;
390 NRArenaItemClass *item_class;
392 object_class = (NRObjectClass *) klass;
393 item_class = (NRArenaItemClass *) klass;
395 group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;
397 object_class->finalize = nr_arena_glyphs_group_finalize;
398 object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;
400 item_class->update = nr_arena_glyphs_group_update;
401 item_class->render = nr_arena_glyphs_group_render;
402 item_class->clip = nr_arena_glyphs_group_clip;
403 item_class->pick = nr_arena_glyphs_group_pick;
404 }
406 static void
407 nr_arena_glyphs_group_init (NRArenaGlyphsGroup *group)
408 {
409 group->style = NULL;
410 group->paintbox.x0 = group->paintbox.y0 = 0.0F;
411 group->paintbox.x1 = group->paintbox.y1 = 1.0F;
413 group->fill_painter = NULL;
414 group->stroke_painter = NULL;
415 }
417 static void
418 nr_arena_glyphs_group_finalize (NRObject *object)
419 {
420 NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
422 if (group->fill_painter) {
423 sp_painter_free (group->fill_painter);
424 group->fill_painter = NULL;
425 }
427 if (group->stroke_painter) {
428 sp_painter_free (group->stroke_painter);
429 group->stroke_painter = NULL;
430 }
432 if (group->style) {
433 sp_style_unref (group->style);
434 group->style = NULL;
435 }
437 ((NRObjectClass *) group_parent_class)->finalize (object);
438 }
440 static guint
441 nr_arena_glyphs_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
442 {
443 NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP (item);
445 if (group->fill_painter) {
446 sp_painter_free (group->fill_painter);
447 group->fill_painter = NULL;
448 }
450 if (group->stroke_painter) {
451 sp_painter_free (group->stroke_painter);
452 group->stroke_painter = NULL;
453 }
455 item->render_opacity = TRUE;
456 if (group->style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
457 group->fill_painter = sp_paint_server_painter_new (SP_STYLE_FILL_SERVER (group->style),
458 NR::Matrix (&gc->transform), NR::Matrix (&gc->parent->transform),
459 &group->paintbox);
460 item->render_opacity = FALSE;
461 }
463 if (group->style->stroke.type == SP_PAINT_TYPE_PAINTSERVER) {
464 group->stroke_painter = sp_paint_server_painter_new (SP_STYLE_STROKE_SERVER (group->style),
465 NR::Matrix (&gc->transform), NR::Matrix (&gc->parent->transform),
466 &group->paintbox);
467 item->render_opacity = FALSE;
468 }
470 if ( item->render_opacity == TRUE && group->style->stroke.type != SP_PAINT_TYPE_NONE && group->style->fill.type != SP_PAINT_TYPE_NONE ) {
471 item->render_opacity=FALSE;
472 }
474 if (((NRArenaItemClass *) group_parent_class)->update)
475 return ((NRArenaItemClass *) group_parent_class)->update (item, area, gc, state, reset);
477 return NR_ARENA_ITEM_STATE_ALL;
478 }
480 /* This sucks - as soon, as we have inheritable renderprops, do something with that opacity */
482 static unsigned int
483 nr_arena_glyphs_group_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
484 {
485 NRArenaItem *child;
487 NRArenaGroup *group = NR_ARENA_GROUP (item);
488 NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP (item);
489 SPStyle const *style = ggroup->style;
491 guint ret = item->state;
493 /* Fill */
494 if (style->fill.type != SP_PAINT_TYPE_NONE || item->arena->rendermode == RENDERMODE_OUTLINE) {
495 NRPixBlock m;
496 nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
498 /* Render children fill mask */
499 for (child = group->children; child != NULL; child = child->next) {
500 ret = nr_arena_glyphs_fill_mask (NR_ARENA_GLYPHS (child), area, &m);
501 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
502 nr_pixblock_release (&m);
503 return ret;
504 }
505 }
507 /* Composite into buffer */
508 if (style->fill.type == SP_PAINT_TYPE_COLOR || item->arena->rendermode == RENDERMODE_OUTLINE) {
509 guint32 rgba;
510 if (item->arena->rendermode == RENDERMODE_OUTLINE) {
511 // In outline mode, render fill only, using outlinecolor
512 rgba = item->arena->outlinecolor;
513 } else if ( item->render_opacity ) {
514 rgba = sp_color_get_rgba32_falpha (&style->fill.value.color,
515 SP_SCALE24_TO_FLOAT (style->fill_opacity.value) *
516 SP_SCALE24_TO_FLOAT (style->opacity.value));
517 } else {
518 rgba = sp_color_get_rgba32_falpha (&style->fill.value.color, SP_SCALE24_TO_FLOAT (style->fill_opacity.value));
519 }
520 nr_blit_pixblock_mask_rgba32 (pb, &m, rgba);
521 pb->empty = FALSE;
522 } else if (style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
523 if (ggroup->fill_painter) {
524 nr_arena_render_paintserver_fill (pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT (style->fill_opacity.value), &m);
525 }
526 }
528 nr_pixblock_release (&m);
529 }
531 /* Stroke */
532 if (style->stroke.type != SP_PAINT_TYPE_NONE && !(item->arena->rendermode == RENDERMODE_OUTLINE)) {
533 NRPixBlock m;
534 guint32 rgba;
535 nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
536 /* Render children stroke mask */
537 for (child = group->children; child != NULL; child = child->next) {
538 ret = nr_arena_glyphs_stroke_mask (NR_ARENA_GLYPHS (child), area, &m);
539 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
540 nr_pixblock_release (&m);
541 return ret;
542 }
543 }
544 /* Composite into buffer */
545 switch (style->stroke.type) {
546 case SP_PAINT_TYPE_COLOR:
547 if ( item->render_opacity ) {
548 rgba = sp_color_get_rgba32_falpha (&style->stroke.value.color,
549 SP_SCALE24_TO_FLOAT (style->stroke_opacity.value) *
550 SP_SCALE24_TO_FLOAT (style->opacity.value));
551 } else {
552 rgba = sp_color_get_rgba32_falpha (&style->stroke.value.color,
553 SP_SCALE24_TO_FLOAT (style->stroke_opacity.value));
554 }
555 nr_blit_pixblock_mask_rgba32 (pb, &m, rgba);
556 pb->empty = FALSE;
557 break;
558 case SP_PAINT_TYPE_PAINTSERVER:
559 if (ggroup->stroke_painter) {
560 nr_arena_render_paintserver_fill (pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT (style->stroke_opacity.value), &m);
561 }
562 break;
563 default:
564 break;
565 }
566 nr_pixblock_release (&m);
567 }
569 return ret;
570 }
572 static unsigned int
573 nr_arena_glyphs_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
574 {
575 NRArenaGroup *group = NR_ARENA_GROUP (item);
577 guint ret = item->state;
579 /* Render children fill mask */
580 for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
581 ret = nr_arena_glyphs_fill_mask (NR_ARENA_GLYPHS (child), area, pb);
582 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret;
583 }
585 return ret;
586 }
588 static NRArenaItem *
589 nr_arena_glyphs_group_pick (NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
590 {
591 NRArenaItem *picked = NULL;
593 if (((NRArenaItemClass *) group_parent_class)->pick)
594 picked = ((NRArenaItemClass *) group_parent_class)->pick (item, p, delta, sticky);
596 if (picked) picked = item;
598 return picked;
599 }
601 void
602 nr_arena_glyphs_group_clear (NRArenaGlyphsGroup *sg)
603 {
604 NRArenaGroup *group = NR_ARENA_GROUP (sg);
606 nr_arena_item_request_render (NR_ARENA_ITEM (group));
608 while (group->children) {
609 nr_arena_item_remove_child (NR_ARENA_ITEM (group), group->children);
610 }
611 }
613 void
614 nr_arena_glyphs_group_add_component (NRArenaGlyphsGroup *sg, font_instance *font, int glyph, const NRMatrix *transform)
615 {
616 NRArenaGroup *group;
617 NRBPath bpath;
619 group = NR_ARENA_GROUP (sg);
621 if ( font ) bpath.path=(NArtBpath*)font->ArtBPath(glyph); else bpath.path=NULL;
622 if ( bpath.path ) {
624 nr_arena_item_request_render (NR_ARENA_ITEM (group));
626 NRArenaItem *new_arena;
627 new_arena = NRArenaGlyphs::create(group->arena);
628 nr_arena_item_append_child (NR_ARENA_ITEM (group), new_arena);
629 nr_arena_item_unref (new_arena);
630 nr_arena_glyphs_set_path (NR_ARENA_GLYPHS (new_arena), NULL, FALSE, font, glyph, transform);
631 nr_arena_glyphs_set_style (NR_ARENA_GLYPHS (new_arena), sg->style);
632 }
634 }
636 void
637 nr_arena_glyphs_group_set_style (NRArenaGlyphsGroup *sg, SPStyle *style)
638 {
639 NRArenaGroup *group;
640 NRArenaItem *child;
642 nr_return_if_fail (sg != NULL);
643 nr_return_if_fail (NR_IS_ARENA_GLYPHS_GROUP (sg));
645 group = NR_ARENA_GROUP (sg);
647 if (style) sp_style_ref (style);
648 if (sg->style) sp_style_unref (sg->style);
649 sg->style = style;
651 for (child = group->children; child != NULL; child = child->next) {
652 nr_return_if_fail (NR_IS_ARENA_GLYPHS (child));
653 nr_arena_glyphs_set_style (NR_ARENA_GLYPHS (child), sg->style);
654 }
656 nr_arena_item_request_update (NR_ARENA_ITEM (sg), NR_ARENA_ITEM_STATE_ALL, FALSE);
657 }
659 void
660 nr_arena_glyphs_group_set_paintbox (NRArenaGlyphsGroup *gg, const NRRect *pbox)
661 {
662 nr_return_if_fail (gg != NULL);
663 nr_return_if_fail (NR_IS_ARENA_GLYPHS_GROUP (gg));
664 nr_return_if_fail (pbox != NULL);
666 if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
667 gg->paintbox.x0 = pbox->x0;
668 gg->paintbox.y0 = pbox->y0;
669 gg->paintbox.x1 = pbox->x1;
670 gg->paintbox.y1 = pbox->y1;
671 } else {
672 /* fixme: We kill warning, although not sure what to do here (Lauris) */
673 gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
674 gg->paintbox.x1 = gg->paintbox.y1 = 256.0F;
675 }
677 nr_arena_item_request_update (NR_ARENA_ITEM (gg), NR_ARENA_ITEM_STATE_ALL, FALSE);
678 }