Code

c6bc3b13142431a205d7ae988e5227f7c5d8e25e
[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;
90 }
92 static void
93 nr_arena_glyphs_finalize (NRObject *object)
94 {
95         NRArenaGlyphs *glyphs=static_cast<NRArenaGlyphs *>(object);
97         if (glyphs->rfont) {
98                 glyphs->rfont->Unref();
99                 glyphs->rfont=NULL;
100         }
101         if (glyphs->sfont) {
102                 glyphs->sfont->Unref();
103                 glyphs->sfont=NULL;
104         }
106         if (glyphs->font) {
107                 glyphs->font->Unref();
108                 glyphs->font=NULL;
109         }
111         if (glyphs->style) {
112                 sp_style_unref (glyphs->style);
113                 glyphs->style = NULL;
114         }
116         ((NRObjectClass *) glyphs_parent_class)->finalize (object);
119 static guint
120 nr_arena_glyphs_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
122         NRArenaGlyphs *glyphs;
123         raster_font *rfont;
125         glyphs = NR_ARENA_GLYPHS (item);
127         if (!glyphs->font || !glyphs->style) return NR_ARENA_ITEM_STATE_ALL;
128         if ((glyphs->style->fill.type == SP_PAINT_TYPE_NONE) && (glyphs->style->stroke.type == SP_PAINT_TYPE_NONE)) return NR_ARENA_ITEM_STATE_ALL;
130         NRRect bbox;
131         bbox.x0 = bbox.y0 = NR_HUGE;
132         bbox.x1 = bbox.y1 = -NR_HUGE;
134         float const scale = NR_MATRIX_DF_EXPANSION (&gc->transform);
136         if (glyphs->style->fill.type != SP_PAINT_TYPE_NONE) {
137                 NRMatrix t;
138                 nr_matrix_multiply (&t, &glyphs->g_transform, &gc->transform);
139                 glyphs->x = t.c[4];
140                 glyphs->y = t.c[5];
141                 t.c[4]=0;
142                 t.c[5]=0;
143                 rfont = glyphs->font->RasterFont(t, 0);
144                 if (glyphs->rfont) glyphs->rfont->Unref();
145                 glyphs->rfont = rfont;
147                 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
148                         NRRect narea;
149                         if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea);
150                         bbox.x0 = narea.x0 + glyphs->x;
151                         bbox.y0 = narea.y0 + glyphs->y;
152                         bbox.x1 = narea.x1 + glyphs->x;
153                         bbox.y1 = narea.y1 + glyphs->y;
154                 }
155         }                               
157         if (glyphs->style->stroke.type != SP_PAINT_TYPE_NONE) {
158                 /* Build state data */
159                 NRMatrix t;
160                 nr_matrix_multiply (&t, &glyphs->g_transform, &gc->transform);
161                 glyphs->x = t.c[4];
162                 glyphs->y = t.c[5];
163                 t.c[4]=0;
164                 t.c[5]=0;
166                 if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
167                         font_style nstyl;
168                         nstyl.transform = t;
169                         nstyl.stroke_width=MAX (0.125, glyphs->style->stroke_width.computed * scale);
170                         if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight;
171                         if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round;
172                         if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square;
173                         if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy;
174                         if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round;
175                         if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight;
176                         nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value;
177                         nstyl.nbDash=0;
178                         nstyl.dashes=NULL;
179                         if ( glyphs->style->stroke_dash.n_dash > 0 ) {
180                                 nstyl.nbDash=glyphs->style->stroke_dash.n_dash;
181                                 nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double));
182                                 for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale;
183                         }
184                         rfont = glyphs->font->RasterFont( nstyl);
185                         if ( nstyl.dashes ) free(nstyl.dashes);
186                         if (glyphs->sfont) glyphs->sfont->Unref();
187                         glyphs->sfont = rfont;
189                         NRRect narea;
190                         if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea);
191                         narea.x0-=nstyl.stroke_width;
192                         narea.y0-=nstyl.stroke_width;
193                         narea.x1+=nstyl.stroke_width;
194                         narea.y1+=nstyl.stroke_width;
195                         bbox.x0 = narea.x0 + glyphs->x;
196                         bbox.y0 = narea.y0 + glyphs->y;
197                         bbox.x1 = narea.x1 + glyphs->x;
198                         bbox.y1 = narea.y1 + glyphs->y;
199                 }
200         }
201         if (nr_rect_d_test_empty(&bbox)) return NR_ARENA_ITEM_STATE_ALL;
203         item->bbox.x0 = (gint32)(bbox.x0 - 1.0);
204         item->bbox.y0 = (gint32)(bbox.y0 - 1.0);
205         item->bbox.x1 = (gint32)(bbox.x1 + 1.0);
206         item->bbox.y1 = (gint32)(bbox.y1 + 1.0);
207         nr_arena_request_render_rect (item->arena, &item->bbox);
209         return NR_ARENA_ITEM_STATE_ALL;
212 static guint
213 nr_arena_glyphs_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
215         NRArenaGlyphs *glyphs;
217         glyphs = NR_ARENA_GLYPHS (item);
219         if (!glyphs->font ) return item->state;
221         /* TODO : render to greyscale pixblock provided for clipping */
223         return item->state;
226 static NRArenaItem *
227 nr_arena_glyphs_pick (NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
229         NRArenaGlyphs *glyphs;
231         glyphs = NR_ARENA_GLYPHS (item);
233         if (!glyphs->font ) return NULL;
234         if (!glyphs->style) return NULL;
235         
236         double const x = p[NR::X];
237         double const y = p[NR::Y];
238         /* With text we take a simple approach: pick if the point is in a characher bbox */
239         if ((x >= item->bbox.x0) && (y >= item->bbox.y0) && (x <= item->bbox.x1) && (y <= item->bbox.y1)) return item;
241         return NULL;
244 void
245 nr_arena_glyphs_set_path (NRArenaGlyphs *glyphs, SPCurve *curve, unsigned int lieutenant, font_instance *font, gint glyph, NRMatrix const *transform)
247         nr_return_if_fail (glyphs != NULL);
248         nr_return_if_fail (NR_IS_ARENA_GLYPHS (glyphs));
250         nr_arena_item_request_render (NR_ARENA_ITEM (glyphs));
251   
252         if (transform) {
253                 glyphs->g_transform = *transform;
254         } else {
255                 nr_matrix_set_identity (&glyphs->g_transform);
256         }
257                 
258         if ( font ) font->Ref();
259         if ( glyphs->font ) glyphs->font->Unref();
260         glyphs->font=font;
261         glyphs->glyph = glyph;
263         nr_arena_item_request_update (NR_ARENA_ITEM (glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
266 void
267 nr_arena_glyphs_set_style (NRArenaGlyphs *glyphs, SPStyle *style)
269         nr_return_if_fail (glyphs != NULL);
270         nr_return_if_fail (NR_IS_ARENA_GLYPHS (glyphs));
272         if (style) sp_style_ref (style);
273         if (glyphs->style) sp_style_unref (glyphs->style);
274         glyphs->style = style;
276         nr_arena_item_request_update (NR_ARENA_ITEM (glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
279 static guint
280 nr_arena_glyphs_fill_mask (NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
282         NRArenaItem *item;
284         /* fixme: area == m->area, so merge these */
286         item = NR_ARENA_ITEM (glyphs);
288         if (glyphs->rfont && nr_rect_l_test_intersect (area, &item->bbox)) {
289                 raster_glyph* g=glyphs->rfont->GetGlyph(glyphs->glyph);
290                 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
291         }
293         return item->state;
296 static guint
297 nr_arena_glyphs_stroke_mask (NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
299         NRArenaItem *item;
301         item = NR_ARENA_ITEM (glyphs);
302         if (glyphs->sfont && nr_rect_l_test_intersect (area, &item->bbox)) {
303                 raster_glyph* g=glyphs->sfont->GetGlyph(glyphs->glyph);
304                 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
305         }
307         return item->state;
310 static void nr_arena_glyphs_group_class_init (NRArenaGlyphsGroupClass *klass);
311 static void nr_arena_glyphs_group_init (NRArenaGlyphsGroup *group);
312 static void nr_arena_glyphs_group_finalize (NRObject *object);
314 static guint nr_arena_glyphs_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
315 static unsigned int nr_arena_glyphs_group_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
316 static unsigned int nr_arena_glyphs_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
317 static NRArenaItem *nr_arena_glyphs_group_pick (NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky);
319 static NRArenaGroupClass *group_parent_class;
321 NRType
322 nr_arena_glyphs_group_get_type (void)
324         static NRType type = 0;
325         if (!type) {
326                 type = nr_object_register_type (NR_TYPE_ARENA_GROUP,
327                                                 "NRArenaGlyphsGroup",
328                                                 sizeof (NRArenaGlyphsGroupClass),
329                                                 sizeof (NRArenaGlyphsGroup),
330                                                 (void (*) (NRObjectClass *)) nr_arena_glyphs_group_class_init,
331                                                 (void (*) (NRObject *)) nr_arena_glyphs_group_init);
332         }
333         return type;
336 static void
337 nr_arena_glyphs_group_class_init (NRArenaGlyphsGroupClass *klass)
339         NRObjectClass *object_class;
340         NRArenaItemClass *item_class;
342         object_class = (NRObjectClass *) klass;
343         item_class = (NRArenaItemClass *) klass;
345         group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;
347         object_class->finalize = nr_arena_glyphs_group_finalize;
348         object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;
350         item_class->update = nr_arena_glyphs_group_update;
351         item_class->render = nr_arena_glyphs_group_render;
352         item_class->clip = nr_arena_glyphs_group_clip;
353         item_class->pick = nr_arena_glyphs_group_pick;
356 static void
357 nr_arena_glyphs_group_init (NRArenaGlyphsGroup *group)
359         group->style = NULL;
360         group->paintbox.x0 = group->paintbox.y0 = 0.0F;
361         group->paintbox.x1 = group->paintbox.y1 = 1.0F;
363         group->fill_painter = NULL;
364         group->stroke_painter = NULL;
367 static void
368 nr_arena_glyphs_group_finalize (NRObject *object)
370         NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
372         if (group->fill_painter) {
373                 sp_painter_free (group->fill_painter);
374                 group->fill_painter = NULL;
375         }
377         if (group->stroke_painter) {
378                 sp_painter_free (group->stroke_painter);
379                 group->stroke_painter = NULL;
380         }
382         if (group->style) {
383                 sp_style_unref (group->style);
384                 group->style = NULL;
385         }
387         ((NRObjectClass *) group_parent_class)->finalize (object);
390 static guint
391 nr_arena_glyphs_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
393         NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP (item);
395         if (group->fill_painter) {
396                 sp_painter_free (group->fill_painter);
397                 group->fill_painter = NULL;
398         }
400         if (group->stroke_painter) {
401                 sp_painter_free (group->stroke_painter);
402                 group->stroke_painter = NULL;
403         }
405         item->render_opacity = TRUE;
406         if (group->style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
407                 group->fill_painter = sp_paint_server_painter_new (SP_STYLE_FILL_SERVER (group->style),
408                                                          NR::Matrix (&gc->transform), NR::Matrix (&gc->parent->transform),
409                                                          &group->paintbox);
410                 item->render_opacity = FALSE;
411         }
413         if (group->style->stroke.type == SP_PAINT_TYPE_PAINTSERVER) {
414                 group->stroke_painter = sp_paint_server_painter_new (SP_STYLE_STROKE_SERVER (group->style),
415                                                          NR::Matrix (&gc->transform), NR::Matrix (&gc->parent->transform),
416                                                          &group->paintbox);
417                 item->render_opacity = FALSE;
418         }
420         if ( item->render_opacity == TRUE && group->style->stroke.type != SP_PAINT_TYPE_NONE && group->style->fill.type != SP_PAINT_TYPE_NONE ) {
421                 item->render_opacity=FALSE;
422         }
424         if (((NRArenaItemClass *) group_parent_class)->update)
425                 return ((NRArenaItemClass *) group_parent_class)->update (item, area, gc, state, reset);
427         return NR_ARENA_ITEM_STATE_ALL;
430 /* This sucks - as soon, as we have inheritable renderprops, do something with that opacity */
432 static unsigned int
433 nr_arena_glyphs_group_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
435         NRArenaItem *child;
437         NRArenaGroup *group = NR_ARENA_GROUP (item);
438         NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP (item);
439         SPStyle const *style = ggroup->style;
441         guint ret = item->state;
443         /* Fill */
444         if (style->fill.type != SP_PAINT_TYPE_NONE || item->arena->rendermode == RENDERMODE_OUTLINE) {
445                 NRPixBlock m;
446                 nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
448                 /* Render children fill mask */
449                 for (child = group->children; child != NULL; child = child->next) {
450                         ret = nr_arena_glyphs_fill_mask (NR_ARENA_GLYPHS (child), area, &m);
451                         if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
452                                 nr_pixblock_release (&m);
453                                 return ret;
454                         }
455                 }
457                 /* Composite into buffer */
458                 if (style->fill.type == SP_PAINT_TYPE_COLOR || item->arena->rendermode == RENDERMODE_OUTLINE) {
459                         guint32 rgba;
460                         if (item->arena->rendermode == RENDERMODE_OUTLINE) {
461                                 // In outline mode, render fill only, using outlinecolor
462                                 rgba = item->arena->outlinecolor;
463                         } else if ( item->render_opacity ) {
464                                 rgba = sp_color_get_rgba32_falpha (&style->fill.value.color,
465                                            SP_SCALE24_TO_FLOAT (style->fill_opacity.value) *
466                                            SP_SCALE24_TO_FLOAT (style->opacity.value));
467                         } else {
468                                 rgba = sp_color_get_rgba32_falpha (&style->fill.value.color, SP_SCALE24_TO_FLOAT (style->fill_opacity.value));
469                         }
470                         nr_blit_pixblock_mask_rgba32 (pb, &m, rgba);
471                         pb->empty = FALSE;
472                 } else if (style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
473                         if (ggroup->fill_painter) {
474                                 nr_arena_render_paintserver_fill (pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT (style->fill_opacity.value), &m);
475                         }
476                 }
478                 nr_pixblock_release (&m);
479         }
481         /* Stroke */
482         if (style->stroke.type != SP_PAINT_TYPE_NONE && !(item->arena->rendermode == RENDERMODE_OUTLINE)) {
483                 NRPixBlock m;
484                 guint32 rgba;
485                 nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
486                 /* Render children stroke mask */
487                 for (child = group->children; child != NULL; child = child->next) {
488                         ret = nr_arena_glyphs_stroke_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                 }
494                 /* Composite into buffer */
495                 switch (style->stroke.type) {
496                 case SP_PAINT_TYPE_COLOR:
497                         if ( item->render_opacity ) {
498                                 rgba = sp_color_get_rgba32_falpha (&style->stroke.value.color,
499                                            SP_SCALE24_TO_FLOAT (style->stroke_opacity.value) *
500                                            SP_SCALE24_TO_FLOAT (style->opacity.value));
501                         } else {
502                                 rgba = sp_color_get_rgba32_falpha (&style->stroke.value.color,
503                                                          SP_SCALE24_TO_FLOAT (style->stroke_opacity.value));
504                         }
505                         nr_blit_pixblock_mask_rgba32 (pb, &m, rgba);
506                         pb->empty = FALSE;
507                         break;
508                 case SP_PAINT_TYPE_PAINTSERVER:
509                         if (ggroup->stroke_painter) {
510                                 nr_arena_render_paintserver_fill (pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT (style->stroke_opacity.value), &m);
511                         }
512                         break;
513                 default:
514                         break;
515                 }
516                 nr_pixblock_release (&m);
517         }
519         return ret;
522 static unsigned int
523 nr_arena_glyphs_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
525         NRArenaGroup *group = NR_ARENA_GROUP (item);
527         guint ret = item->state;
529         /* Render children fill mask */
530         for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
531                 ret = nr_arena_glyphs_fill_mask (NR_ARENA_GLYPHS (child), area, pb);
532                 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret;
533         }
535         return ret;
538 static NRArenaItem *
539 nr_arena_glyphs_group_pick (NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
541         NRArenaItem *picked = NULL;
543         if (((NRArenaItemClass *) group_parent_class)->pick)
544                 picked = ((NRArenaItemClass *) group_parent_class)->pick (item, p, delta, sticky);
546         if (picked) picked = item;
548         return picked;
551 void
552 nr_arena_glyphs_group_clear (NRArenaGlyphsGroup *sg)
554         NRArenaGroup *group = NR_ARENA_GROUP (sg);
556         nr_arena_item_request_render (NR_ARENA_ITEM (group));
558         while (group->children) {
559                 nr_arena_item_remove_child (NR_ARENA_ITEM (group), group->children);
560         }
563 void
564 nr_arena_glyphs_group_add_component (NRArenaGlyphsGroup *sg, font_instance *font, int glyph, NRMatrix const *transform)
566         NRArenaGroup *group;
567         NRBPath bpath;
569         group = NR_ARENA_GROUP (sg);
571         if ( font ) bpath.path=(NArtBpath*)font->ArtBPath(glyph); else bpath.path=NULL;
572         if ( bpath.path ) {
574                 nr_arena_item_request_render (NR_ARENA_ITEM (group));
576                         NRArenaItem *new_arena;
577                         new_arena = NRArenaGlyphs::create(group->arena);
578                         nr_arena_item_append_child (NR_ARENA_ITEM (group), new_arena);
579                         nr_arena_item_unref (new_arena);
580                         nr_arena_glyphs_set_path (NR_ARENA_GLYPHS (new_arena), NULL, FALSE, font, glyph, transform);
581                         nr_arena_glyphs_set_style (NR_ARENA_GLYPHS (new_arena), sg->style);
582         }
586 void
587 nr_arena_glyphs_group_set_style (NRArenaGlyphsGroup *sg, SPStyle *style)
589         NRArenaGroup *group;
590         NRArenaItem *child;
592         nr_return_if_fail (sg != NULL);
593         nr_return_if_fail (NR_IS_ARENA_GLYPHS_GROUP (sg));
595         group = NR_ARENA_GROUP (sg);
597         if (style) sp_style_ref (style);
598         if (sg->style) sp_style_unref (sg->style);
599         sg->style = style;
601         for (child = group->children; child != NULL; child = child->next) {
602                 nr_return_if_fail (NR_IS_ARENA_GLYPHS (child));
603                 nr_arena_glyphs_set_style (NR_ARENA_GLYPHS (child), sg->style);
604         }
606         nr_arena_item_request_update (NR_ARENA_ITEM (sg), NR_ARENA_ITEM_STATE_ALL, FALSE);
609 void
610 nr_arena_glyphs_group_set_paintbox (NRArenaGlyphsGroup *gg, NRRect const *pbox)
612         nr_return_if_fail (gg != NULL);
613         nr_return_if_fail (NR_IS_ARENA_GLYPHS_GROUP (gg));
614         nr_return_if_fail (pbox != NULL);
616         if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
617                 gg->paintbox.x0 = pbox->x0;
618                 gg->paintbox.y0 = pbox->y0;
619                 gg->paintbox.x1 = pbox->x1;
620                 gg->paintbox.y1 = pbox->y1;
621         } else {
622                 /* fixme: We kill warning, although not sure what to do here (Lauris) */
623                 gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
624                 gg->paintbox.x1 = gg->paintbox.y1 = 256.0F;
625         }
627         nr_arena_item_request_update (NR_ARENA_ITEM (gg), NR_ARENA_ITEM_STATE_ALL, FALSE);