Code

fix 1457118
[inkscape.git] / src / display / nr-arena-glyphs.cpp
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)
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 //      }
112   
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);
135 static guint
136 nr_arena_glyphs_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
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         const float scale = NR_MATRIX_DF_EXPANSION (&gc->transform);
152         if (glyphs->style->fill.type != SP_PAINT_TYPE_NONE) {
153                 NRMatrix t;
154                 nr_matrix_multiply (&t, &glyphs->g_transform, &gc->transform);
155                 glyphs->x = t.c[4];
156                 glyphs->y = t.c[5];
157                 t.c[4]=0;
158                 t.c[5]=0;
159                 rfont = glyphs->font->RasterFont(t, 0);
160                 if (glyphs->rfont) glyphs->rfont->Unref();
161                 glyphs->rfont = rfont;
163                 if (glyphs->style->stroke.type == SP_PAINT_TYPE_NONE || fabs(glyphs->style->stroke_width.computed * scale) <= 0.01) { // Optimization: do fill bbox only if there's no stroke
164                         NRRect narea;
165                         if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea);
166                         bbox.x0 = narea.x0 + glyphs->x;
167                         bbox.y0 = narea.y0 + glyphs->y;
168                         bbox.x1 = narea.x1 + glyphs->x;
169                         bbox.y1 = narea.y1 + glyphs->y;
170                 }
171         }                               
173         if (glyphs->style->stroke.type != SP_PAINT_TYPE_NONE) {
174                 /* Build state data */
175                 NRMatrix t;
176                 nr_matrix_multiply (&t, &glyphs->g_transform, &gc->transform);
177                 glyphs->x = t.c[4];
178                 glyphs->y = t.c[5];
179                 t.c[4]=0;
180                 t.c[5]=0;
182                 if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
183                         font_style nstyl;
184                         nstyl.transform = t;
185                         nstyl.stroke_width=MAX (0.125, glyphs->style->stroke_width.computed * scale);
186                         if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight;
187                         if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round;
188                         if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square;
189                         if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy;
190                         if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round;
191                         if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight;
192                         nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value;
193                         nstyl.nbDash=0;
194                         nstyl.dashes=NULL;
195                         if ( glyphs->style->stroke_dash.n_dash > 0 ) {
196                                 nstyl.nbDash=glyphs->style->stroke_dash.n_dash;
197                                 nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double));
198                                 for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale;
199                         }
200                         rfont = glyphs->font->RasterFont( nstyl);
201                         if ( nstyl.dashes ) free(nstyl.dashes);
202                         if (glyphs->sfont) glyphs->sfont->Unref();
203                         glyphs->sfont = rfont;
205                         NRRect narea;
206                         if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea);
207                         narea.x0-=nstyl.stroke_width;
208                         narea.y0-=nstyl.stroke_width;
209                         narea.x1+=nstyl.stroke_width;
210                         narea.y1+=nstyl.stroke_width;
211                         bbox.x0 = narea.x0 + glyphs->x;
212                         bbox.y0 = narea.y0 + glyphs->y;
213                         bbox.x1 = narea.x1 + glyphs->x;
214                         bbox.y1 = narea.y1 + glyphs->y;
215                 }
216         }
217         if (nr_rect_d_test_empty(&bbox)) return NR_ARENA_ITEM_STATE_ALL;
219         item->bbox.x0 = (gint32)(bbox.x0 - 1.0);
220         item->bbox.y0 = (gint32)(bbox.y0 - 1.0);
221         item->bbox.x1 = (gint32)(bbox.x1 + 1.0);
222         item->bbox.y1 = (gint32)(bbox.y1 + 1.0);
223         nr_arena_request_render_rect (item->arena, &item->bbox);
225         return NR_ARENA_ITEM_STATE_ALL;
228 static guint
229 nr_arena_glyphs_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
231         NRArenaGlyphs *glyphs;
233         glyphs = NR_ARENA_GLYPHS (item);
235         if (!glyphs->font ) return item->state;
237         /* TODO : render to greyscale pixblock provided for clipping */
239         return item->state;
242 static NRArenaItem *
243 nr_arena_glyphs_pick (NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
245         NRArenaGlyphs *glyphs;
247         glyphs = NR_ARENA_GLYPHS (item);
249         if (!glyphs->font ) return NULL;
250         if (!glyphs->style) return NULL;
251         
252         const double x = p[NR::X];
253         const double y = p[NR::Y];
254         /* With text we take a simple approach: pick if the point is in a characher bbox */
255         if ((x >= item->bbox.x0) && (y >= item->bbox.y0) && (x <= item->bbox.x1) && (y <= item->bbox.y1)) return item;
257 /*      NR::Point const thePt = p;
258                 if (glyphs->stroke_shp && (glyphs->style->stroke.type != SP_PAINT_TYPE_NONE)) {
259                         if (glyphs->stroke_shp->PtWinding(thePt) > 0 ) return item;
260                 }
261                 if (delta > 1e-3) {
262                         if (glyphs->stroke_shp && (glyphs->style->stroke.type != SP_PAINT_TYPE_NONE)) {
263                                 if ( glyphs->stroke_shp->DistanceLE(thePt, delta)) return item;
264                         }
265                 }*/
266   
267         return NULL;
270 void
271 nr_arena_glyphs_set_path (NRArenaGlyphs *glyphs, SPCurve *curve, unsigned int lieutenant, font_instance *font, gint glyph, const NRMatrix *transform)
273         nr_return_if_fail (glyphs != NULL);
274         nr_return_if_fail (NR_IS_ARENA_GLYPHS (glyphs));
276         nr_arena_item_request_render (NR_ARENA_ITEM (glyphs));
277   
278  // glyphs->cached_shp_dirty=true;
280         if (transform) {
281                 glyphs->g_transform = *transform;
282         } else {
283                 nr_matrix_set_identity (&glyphs->g_transform);
284         }
285                 
286         //printf("glyph_setpath ");
287         if ( font ) font->Ref();
288         if ( glyphs->font ) glyphs->font->Unref();
289         glyphs->font=font;
290         glyphs->glyph = glyph;
292         nr_arena_item_request_update (NR_ARENA_ITEM (glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
295 void
296 nr_arena_glyphs_set_style (NRArenaGlyphs *glyphs, SPStyle *style)
298         nr_return_if_fail (glyphs != NULL);
299         nr_return_if_fail (NR_IS_ARENA_GLYPHS (glyphs));
301 //  glyphs->cached_style_dirty=true;
302   
303         if (style) sp_style_ref (style);
304         if (glyphs->style) sp_style_unref (glyphs->style);
305         glyphs->style = style;
307         nr_arena_item_request_update (NR_ARENA_ITEM (glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
310 static guint
311 nr_arena_glyphs_fill_mask (NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
313         NRArenaItem *item;
315         /* fixme: area == m->area, so merge these */
317         item = NR_ARENA_ITEM (glyphs);
319         if (glyphs->rfont && nr_rect_l_test_intersect (area, &item->bbox)) {
320                 raster_glyph* g=glyphs->rfont->GetGlyph(glyphs->glyph);
321                 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
322         }
324         return item->state;
327 static guint
328 nr_arena_glyphs_stroke_mask (NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
330         NRArenaItem *item;
332         item = NR_ARENA_ITEM (glyphs);
333         if (glyphs->sfont && nr_rect_l_test_intersect (area, &item->bbox)) {
334                 raster_glyph* g=glyphs->sfont->GetGlyph(glyphs->glyph);
335                 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
336         }
337 /*      if (glyphs->stroke_shp && nr_rect_l_test_intersect (area, &item->bbox)) {
338                 NRPixBlock gb;
339                 gint x, y;
340                 nr_pixblock_setup_fast (&gb, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
341     // art_gray_svp_aa is just fillung apparently
342     // dunno why it's used here instead of its libnr counterpart
343     nr_pixblock_render_shape_mask_or (gb,glyphs->stroke_shp);    
344                 for (y = area->y0; y < area->y1; y++) {
345                         guchar *d, *s;
346                         d = NR_PIXBLOCK_PX (m) + (y - area->y0) * m->rs;
347                         s = NR_PIXBLOCK_PX (&gb) + (y - area->y0) * gb.rs;
348                         for (x = area->x0; x < area->x1; x++) {
349                                 *d = (*d) + ((255 - *d) * (*s) / 255);
350                                 d += 1;
351                                 s += 1;
352                         }
353                 }
354                 nr_pixblock_release (&gb);
355                 m->empty = FALSE;
356         }*/
357   
358         return item->state;
361 static void nr_arena_glyphs_group_class_init (NRArenaGlyphsGroupClass *klass);
362 static void nr_arena_glyphs_group_init (NRArenaGlyphsGroup *group);
363 static void nr_arena_glyphs_group_finalize (NRObject *object);
365 static guint nr_arena_glyphs_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
366 static unsigned int nr_arena_glyphs_group_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
367 static unsigned int nr_arena_glyphs_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
368 static NRArenaItem *nr_arena_glyphs_group_pick (NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky);
370 static NRArenaGroupClass *group_parent_class;
372 NRType
373 nr_arena_glyphs_group_get_type (void)
375         static NRType type = 0;
376         if (!type) {
377                 type = nr_object_register_type (NR_TYPE_ARENA_GROUP,
378                                                 "NRArenaGlyphsGroup",
379                                                 sizeof (NRArenaGlyphsGroupClass),
380                                                 sizeof (NRArenaGlyphsGroup),
381                                                 (void (*) (NRObjectClass *)) nr_arena_glyphs_group_class_init,
382                                                 (void (*) (NRObject *)) nr_arena_glyphs_group_init);
383         }
384         return type;
387 static void
388 nr_arena_glyphs_group_class_init (NRArenaGlyphsGroupClass *klass)
390         NRObjectClass *object_class;
391         NRArenaItemClass *item_class;
393         object_class = (NRObjectClass *) klass;
394         item_class = (NRArenaItemClass *) klass;
396         group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;
398         object_class->finalize = nr_arena_glyphs_group_finalize;
399         object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;
401         item_class->update = nr_arena_glyphs_group_update;
402         item_class->render = nr_arena_glyphs_group_render;
403         item_class->clip = nr_arena_glyphs_group_clip;
404         item_class->pick = nr_arena_glyphs_group_pick;
407 static void
408 nr_arena_glyphs_group_init (NRArenaGlyphsGroup *group)
410         group->style = NULL;
411         group->paintbox.x0 = group->paintbox.y0 = 0.0F;
412         group->paintbox.x1 = group->paintbox.y1 = 1.0F;
414         group->fill_painter = NULL;
415         group->stroke_painter = NULL;
418 static void
419 nr_arena_glyphs_group_finalize (NRObject *object)
421         NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
423         if (group->fill_painter) {
424                 sp_painter_free (group->fill_painter);
425                 group->fill_painter = NULL;
426         }
428         if (group->stroke_painter) {
429                 sp_painter_free (group->stroke_painter);
430                 group->stroke_painter = NULL;
431         }
433         if (group->style) {
434                 sp_style_unref (group->style);
435                 group->style = NULL;
436         }
438         ((NRObjectClass *) group_parent_class)->finalize (object);
441 static guint
442 nr_arena_glyphs_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
444         NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP (item);
446         if (group->fill_painter) {
447                 sp_painter_free (group->fill_painter);
448                 group->fill_painter = NULL;
449         }
451         if (group->stroke_painter) {
452                 sp_painter_free (group->stroke_painter);
453                 group->stroke_painter = NULL;
454         }
456         item->render_opacity = TRUE;
457         if (group->style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
458                 group->fill_painter = sp_paint_server_painter_new (SP_STYLE_FILL_SERVER (group->style),
459                                                          NR::Matrix (&gc->transform), NR::Matrix (&gc->parent->transform),
460                                                          &group->paintbox);
461                 item->render_opacity = FALSE;
462         }
464         if (group->style->stroke.type == SP_PAINT_TYPE_PAINTSERVER) {
465                 group->stroke_painter = sp_paint_server_painter_new (SP_STYLE_STROKE_SERVER (group->style),
466                                                          NR::Matrix (&gc->transform), NR::Matrix (&gc->parent->transform),
467                                                          &group->paintbox);
468                 item->render_opacity = FALSE;
469         }
471         if ( item->render_opacity == TRUE && group->style->stroke.type != SP_PAINT_TYPE_NONE && group->style->fill.type != SP_PAINT_TYPE_NONE ) {
472                 item->render_opacity=FALSE;
473         }
475         if (((NRArenaItemClass *) group_parent_class)->update)
476                 return ((NRArenaItemClass *) group_parent_class)->update (item, area, gc, state, reset);
478         return NR_ARENA_ITEM_STATE_ALL;
481 /* This sucks - as soon, as we have inheritable renderprops, do something with that opacity */
483 static unsigned int
484 nr_arena_glyphs_group_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
486         NRArenaItem *child;
488         NRArenaGroup *group = NR_ARENA_GROUP (item);
489         NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP (item);
490         SPStyle const *style = ggroup->style;
492         guint ret = item->state;
494         /* Fill */
495         if (style->fill.type != SP_PAINT_TYPE_NONE || item->arena->rendermode == RENDERMODE_OUTLINE) {
496                 NRPixBlock m;
497                 nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
499                 /* Render children fill mask */
500                 for (child = group->children; child != NULL; child = child->next) {
501                         ret = nr_arena_glyphs_fill_mask (NR_ARENA_GLYPHS (child), area, &m);
502                         if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
503                                 nr_pixblock_release (&m);
504                                 return ret;
505                         }
506                 }
508                 /* Composite into buffer */
509                 if (style->fill.type == SP_PAINT_TYPE_COLOR || item->arena->rendermode == RENDERMODE_OUTLINE) {
510                         guint32 rgba;
511                         if (item->arena->rendermode == RENDERMODE_OUTLINE) {
512                                 // In outline mode, render fill only, using outlinecolor
513                                 rgba = item->arena->outlinecolor;
514                         } else if ( item->render_opacity ) {
515                                 rgba = sp_color_get_rgba32_falpha (&style->fill.value.color,
516                                            SP_SCALE24_TO_FLOAT (style->fill_opacity.value) *
517                                            SP_SCALE24_TO_FLOAT (style->opacity.value));
518                         } else {
519                                 rgba = sp_color_get_rgba32_falpha (&style->fill.value.color, SP_SCALE24_TO_FLOAT (style->fill_opacity.value));
520                         }
521                         nr_blit_pixblock_mask_rgba32 (pb, &m, rgba);
522                         pb->empty = FALSE;
523                 } else if (style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
524                         if (ggroup->fill_painter) {
525                                 nr_arena_render_paintserver_fill (pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT (style->fill_opacity.value), &m);
526                         }
527                 }
529                 nr_pixblock_release (&m);
530         }
532         /* Stroke */
533         if (style->stroke.type != SP_PAINT_TYPE_NONE && !(item->arena->rendermode == RENDERMODE_OUTLINE)) {
534                 NRPixBlock m;
535                 guint32 rgba;
536                 nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
537                 /* Render children stroke mask */
538                 for (child = group->children; child != NULL; child = child->next) {
539                         ret = nr_arena_glyphs_stroke_mask (NR_ARENA_GLYPHS (child), area, &m);
540                         if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
541                                 nr_pixblock_release (&m);
542                                 return ret;
543                         }
544                 }
545                 /* Composite into buffer */
546                 switch (style->stroke.type) {
547                 case SP_PAINT_TYPE_COLOR:
548                         if ( item->render_opacity ) {
549                                 rgba = sp_color_get_rgba32_falpha (&style->stroke.value.color,
550                                            SP_SCALE24_TO_FLOAT (style->stroke_opacity.value) *
551                                            SP_SCALE24_TO_FLOAT (style->opacity.value));
552                         } else {
553                                 rgba = sp_color_get_rgba32_falpha (&style->stroke.value.color,
554                                                          SP_SCALE24_TO_FLOAT (style->stroke_opacity.value));
555                         }
556                         nr_blit_pixblock_mask_rgba32 (pb, &m, rgba);
557                         pb->empty = FALSE;
558                         break;
559                 case SP_PAINT_TYPE_PAINTSERVER:
560                         if (ggroup->stroke_painter) {
561                                 nr_arena_render_paintserver_fill (pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT (style->stroke_opacity.value), &m);
562                         }
563                         break;
564                 default:
565                         break;
566                 }
567                 nr_pixblock_release (&m);
568         }
570         return ret;
573 static unsigned int
574 nr_arena_glyphs_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
576         NRArenaGroup *group = NR_ARENA_GROUP (item);
578         guint ret = item->state;
580         /* Render children fill mask */
581         for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
582                 ret = nr_arena_glyphs_fill_mask (NR_ARENA_GLYPHS (child), area, pb);
583                 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret;
584         }
586         return ret;
589 static NRArenaItem *
590 nr_arena_glyphs_group_pick (NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
592         NRArenaItem *picked = NULL;
594         if (((NRArenaItemClass *) group_parent_class)->pick)
595                 picked = ((NRArenaItemClass *) group_parent_class)->pick (item, p, delta, sticky);
597         if (picked) picked = item;
599         return picked;
602 void
603 nr_arena_glyphs_group_clear (NRArenaGlyphsGroup *sg)
605         NRArenaGroup *group = NR_ARENA_GROUP (sg);
607         nr_arena_item_request_render (NR_ARENA_ITEM (group));
609         while (group->children) {
610                 nr_arena_item_remove_child (NR_ARENA_ITEM (group), group->children);
611         }
614 void
615 nr_arena_glyphs_group_add_component (NRArenaGlyphsGroup *sg, font_instance *font, int glyph, const NRMatrix *transform)
617         NRArenaGroup *group;
618         NRBPath bpath;
620         group = NR_ARENA_GROUP (sg);
622         if ( font ) bpath.path=(NArtBpath*)font->ArtBPath(glyph); else bpath.path=NULL;
623         if ( bpath.path ) {
625                 nr_arena_item_request_render (NR_ARENA_ITEM (group));
627                         NRArenaItem *new_arena;
628                         new_arena = NRArenaGlyphs::create(group->arena);
629                         nr_arena_item_append_child (NR_ARENA_ITEM (group), new_arena);
630                         nr_arena_item_unref (new_arena);
631                         nr_arena_glyphs_set_path (NR_ARENA_GLYPHS (new_arena), NULL, FALSE, font, glyph, transform);
632                         nr_arena_glyphs_set_style (NR_ARENA_GLYPHS (new_arena), sg->style);
633         }
637 void
638 nr_arena_glyphs_group_set_style (NRArenaGlyphsGroup *sg, SPStyle *style)
640         NRArenaGroup *group;
641         NRArenaItem *child;
643         nr_return_if_fail (sg != NULL);
644         nr_return_if_fail (NR_IS_ARENA_GLYPHS_GROUP (sg));
646         group = NR_ARENA_GROUP (sg);
648         if (style) sp_style_ref (style);
649         if (sg->style) sp_style_unref (sg->style);
650         sg->style = style;
652         for (child = group->children; child != NULL; child = child->next) {
653                 nr_return_if_fail (NR_IS_ARENA_GLYPHS (child));
654                 nr_arena_glyphs_set_style (NR_ARENA_GLYPHS (child), sg->style);
655         }
657         nr_arena_item_request_update (NR_ARENA_ITEM (sg), NR_ARENA_ITEM_STATE_ALL, FALSE);
660 void
661 nr_arena_glyphs_group_set_paintbox (NRArenaGlyphsGroup *gg, const NRRect *pbox)
663         nr_return_if_fail (gg != NULL);
664         nr_return_if_fail (NR_IS_ARENA_GLYPHS_GROUP (gg));
665         nr_return_if_fail (pbox != NULL);
667         if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
668                 gg->paintbox.x0 = pbox->x0;
669                 gg->paintbox.y0 = pbox->y0;
670                 gg->paintbox.x1 = pbox->x1;
671                 gg->paintbox.y1 = pbox->y1;
672         } else {
673                 /* fixme: We kill warning, although not sure what to do here (Lauris) */
674                 gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
675                 gg->paintbox.x1 = gg->paintbox.y1 = 256.0F;
676         }
678         nr_arena_item_request_update (NR_ARENA_ITEM (gg), NR_ARENA_ITEM_STATE_ALL, FALSE);