Code

Unions Are Evil! When pixblock size is TINY, it stores data right in the data.px...
[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     /* fixme: area == m->area, so merge these */
284     NRArenaItem *item = NR_ARENA_ITEM(glyphs);
286     if (glyphs->rfont && nr_rect_l_test_intersect(area, &item->bbox)) {
287         raster_glyph *g = glyphs->rfont->GetGlyph(glyphs->glyph);
288         if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y), *m);
289     }
291     return item->state;
294 static guint
295 nr_arena_glyphs_stroke_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
297     NRArenaItem *item = NR_ARENA_ITEM(glyphs);
298     if (glyphs->sfont && nr_rect_l_test_intersect(area, &item->bbox)) {
299         raster_glyph *g=glyphs->sfont->GetGlyph(glyphs->glyph);
300         if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
301     }
303     return item->state;
306 static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass);
307 static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group);
308 static void nr_arena_glyphs_group_finalize(NRObject *object);
310 static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
311 static unsigned int nr_arena_glyphs_group_render(NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
312 static unsigned int nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
313 static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky);
315 static NRArenaGroupClass *group_parent_class;
317 NRType
318 nr_arena_glyphs_group_get_type(void)
320     static NRType type = 0;
321     if (!type) {
322         type = nr_object_register_type(NR_TYPE_ARENA_GROUP,
323                                        "NRArenaGlyphsGroup",
324                                        sizeof(NRArenaGlyphsGroupClass),
325                                        sizeof(NRArenaGlyphsGroup),
326                                        (void (*)(NRObjectClass *)) nr_arena_glyphs_group_class_init,
327                                        (void (*)(NRObject *)) nr_arena_glyphs_group_init);
328     }
329     return type;
332 static void
333 nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass)
335     NRObjectClass *object_class;
336     NRArenaItemClass *item_class;
338     object_class = (NRObjectClass *) klass;
339     item_class = (NRArenaItemClass *) klass;
341     group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;
343     object_class->finalize = nr_arena_glyphs_group_finalize;
344     object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;
346     item_class->update = nr_arena_glyphs_group_update;
347     item_class->render = nr_arena_glyphs_group_render;
348     item_class->clip = nr_arena_glyphs_group_clip;
349     item_class->pick = nr_arena_glyphs_group_pick;
352 static void
353 nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group)
355     group->style = NULL;
356     group->paintbox.x0 = group->paintbox.y0 = 0.0F;
357     group->paintbox.x1 = group->paintbox.y1 = 1.0F;
359     group->fill_painter = NULL;
360     group->stroke_painter = NULL;
363 static void
364 nr_arena_glyphs_group_finalize(NRObject *object)
366     NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
368     if (group->fill_painter) {
369         sp_painter_free(group->fill_painter);
370         group->fill_painter = NULL;
371     }
373     if (group->stroke_painter) {
374         sp_painter_free(group->stroke_painter);
375         group->stroke_painter = NULL;
376     }
378     if (group->style) {
379         sp_style_unref(group->style);
380         group->style = NULL;
381     }
383     ((NRObjectClass *) group_parent_class)->finalize(object);
386 static guint
387 nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
389     NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item);
391     if (group->fill_painter) {
392         sp_painter_free(group->fill_painter);
393         group->fill_painter = NULL;
394     }
396     if (group->stroke_painter) {
397         sp_painter_free(group->stroke_painter);
398         group->stroke_painter = NULL;
399     }
401     item->render_opacity = TRUE;
402     if (group->style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
403         group->fill_painter = sp_paint_server_painter_new(SP_STYLE_FILL_SERVER(group->style),
404                                                           NR::Matrix(&gc->transform), NR::Matrix(&gc->parent->transform),
405                                                           &group->paintbox);
406         item->render_opacity = FALSE;
407     }
409     if (group->style->stroke.type == SP_PAINT_TYPE_PAINTSERVER) {
410         group->stroke_painter = sp_paint_server_painter_new(SP_STYLE_STROKE_SERVER(group->style),
411                                                             NR::Matrix(&gc->transform), NR::Matrix(&gc->parent->transform),
412                                                             &group->paintbox);
413         item->render_opacity = FALSE;
414     }
416     if ( item->render_opacity == TRUE && group->style->stroke.type != SP_PAINT_TYPE_NONE && group->style->fill.type != SP_PAINT_TYPE_NONE ) {
417         item->render_opacity=FALSE;
418     }
420     if (((NRArenaItemClass *) group_parent_class)->update)
421         return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset);
423     return NR_ARENA_ITEM_STATE_ALL;
426 /* This sucks - as soon, as we have inheritable renderprops, do something with that opacity */
428 static unsigned int
429 nr_arena_glyphs_group_render(NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
431     NRArenaItem *child;
433     NRArenaGroup *group = NR_ARENA_GROUP(item);
434     NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item);
435     SPStyle const *style = ggroup->style;
437     guint ret = item->state;
439     /* Fill */
440     if (style->fill.type != SP_PAINT_TYPE_NONE || item->arena->rendermode == RENDERMODE_OUTLINE) {
441         NRPixBlock m;
442         nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
444         // if memory allocation failed, abort 
445         if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
446             nr_pixblock_release (&m);
447             return (item->state);
448         }
450         m.visible_area = pb->visible_area; 
452         /* Render children fill mask */
453         for (child = group->children; child != NULL; child = child->next) {
454             ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, &m);
455             if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
456                 nr_pixblock_release(&m);
457                 return ret;
458             }
459         }
461         /* Composite into buffer */
462         if (style->fill.type == SP_PAINT_TYPE_COLOR || item->arena->rendermode == RENDERMODE_OUTLINE) {
463             guint32 rgba;
464             if (item->arena->rendermode == RENDERMODE_OUTLINE) {
465                 // In outline mode, render fill only, using outlinecolor
466                 rgba = item->arena->outlinecolor;
467             } else if ( item->render_opacity ) {
468                 rgba = sp_color_get_rgba32_falpha(&style->fill.value.color,
469                                                   SP_SCALE24_TO_FLOAT(style->fill_opacity.value) *
470                                                   SP_SCALE24_TO_FLOAT(style->opacity.value));
471             } else {
472                 rgba = sp_color_get_rgba32_falpha(&style->fill.value.color, SP_SCALE24_TO_FLOAT(style->fill_opacity.value));
473             }
474             nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
475             pb->empty = FALSE;
476         } else if (style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
477             if (ggroup->fill_painter) {
478                 nr_arena_render_paintserver_fill(pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT(style->fill_opacity.value), &m);
479             }
480         }
482         nr_pixblock_release(&m);
483     }
485     /* Stroke */
486     if (style->stroke.type != SP_PAINT_TYPE_NONE && !(item->arena->rendermode == RENDERMODE_OUTLINE)) {
487         NRPixBlock m;
488         guint32 rgba;
489         nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
491         // if memory allocation failed, abort 
492         if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
493             nr_pixblock_release (&m);
494             return (item->state);
495         }
497         m.visible_area = pb->visible_area; 
498         /* Render children stroke mask */
499         for (child = group->children; child != NULL; child = child->next) {
500             ret = nr_arena_glyphs_stroke_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         }
506         /* Composite into buffer */
507         switch (style->stroke.type) {
508             case SP_PAINT_TYPE_COLOR:
509                 if ( item->render_opacity ) {
510                     rgba = sp_color_get_rgba32_falpha(&style->stroke.value.color,
511                                                       SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) *
512                                                       SP_SCALE24_TO_FLOAT(style->opacity.value));
513                 } else {
514                     rgba = sp_color_get_rgba32_falpha(&style->stroke.value.color,
515                                                       SP_SCALE24_TO_FLOAT(style->stroke_opacity.value));
516                 }
517                 nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
518                 pb->empty = FALSE;
519                 break;
520             case SP_PAINT_TYPE_PAINTSERVER:
521                 if (ggroup->stroke_painter) {
522                     nr_arena_render_paintserver_fill(pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value), &m);
523                 }
524                 break;
525             default:
526                 break;
527         }
528         nr_pixblock_release(&m);
529     }
531     return ret;
534 static unsigned int
535 nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
537     NRArenaGroup *group = NR_ARENA_GROUP(item);
539     guint ret = item->state;
541     /* Render children fill mask */
542     for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
543         ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, pb);
544         if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret;
545     }
547     return ret;
550 static NRArenaItem *
551 nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
553     NRArenaItem *picked = NULL;
555     if (((NRArenaItemClass *) group_parent_class)->pick)
556         picked = ((NRArenaItemClass *) group_parent_class)->pick(item, p, delta, sticky);
558     if (picked) picked = item;
560     return picked;
563 void
564 nr_arena_glyphs_group_clear(NRArenaGlyphsGroup *sg)
566     NRArenaGroup *group = NR_ARENA_GROUP(sg);
568     nr_arena_item_request_render(NR_ARENA_ITEM(group));
570     while (group->children) {
571         nr_arena_item_remove_child(NR_ARENA_ITEM(group), group->children);
572     }
575 void
576 nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, NRMatrix const *transform)
578     NRArenaGroup *group;
579     NRBPath bpath;
581     group = NR_ARENA_GROUP(sg);
583     bpath.path = ( font
584                    ? (NArtBpath *) font->ArtBPath(glyph)
585                    : NULL );
586     if ( bpath.path ) {
588         nr_arena_item_request_render(NR_ARENA_ITEM(group));
590         NRArenaItem *new_arena = NRArenaGlyphs::create(group->arena);
591         nr_arena_item_append_child(NR_ARENA_ITEM(group), new_arena);
592         nr_arena_item_unref(new_arena);
593         nr_arena_glyphs_set_path(NR_ARENA_GLYPHS(new_arena), NULL, FALSE, font, glyph, transform);
594         nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(new_arena), sg->style);
595     }
598 void
599 nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style)
601     nr_return_if_fail(sg != NULL);
602     nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(sg));
604     NRArenaGroup *group = NR_ARENA_GROUP(sg);
606     if (style) sp_style_ref(style);
607     if (sg->style) sp_style_unref(sg->style);
608     sg->style = style;
610     for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
611         nr_return_if_fail(NR_IS_ARENA_GLYPHS(child));
612         nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(child), sg->style);
613     }
615     nr_arena_item_request_update(NR_ARENA_ITEM(sg), NR_ARENA_ITEM_STATE_ALL, FALSE);
618 void
619 nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox)
621     nr_return_if_fail(gg != NULL);
622     nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg));
623     nr_return_if_fail(pbox != NULL);
625     if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
626         gg->paintbox.x0 = pbox->x0;
627         gg->paintbox.y0 = pbox->y0;
628         gg->paintbox.x1 = pbox->x1;
629         gg->paintbox.y1 = pbox->y1;
630     } else {
631         /* fixme: We kill warning, although not sure what to do here (Lauris) */
632         gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
633         gg->paintbox.x1 = gg->paintbox.y1 = 256.0F;
634     }
636     nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE);
640 /*
641   Local Variables:
642   mode:c++
643   c-file-style:"stroustrup"
644   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
645   indent-tabs-mode:nil
646   fill-column:99
647   End:
648 */
649 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :