Code

a29c44ee14bc6bbb33073faf121c65aacf9b3544
[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 <libnr/n-art-bpath.h>
22 #include <libnr/nr-matrix-ops.h>
23 #include <libnr/nr-matrix-fns.h>
24 #include "../style.h"
25 #include "nr-arena.h"
26 #include "nr-arena-glyphs.h"
27 #include <cairo.h>
28 #include "inkscape-cairo.h"
30 #ifdef test_glyph_liv
31 #include "../display/canvas-bpath.h"
32 #include <libnrtype/font-instance.h>
33 #include <libnrtype/raster-glyph.h>
34 #include <libnrtype/RasterFont.h>
36 // defined in nr-arena-shape.cpp
37 void nr_pixblock_render_shape_mask_or(NRPixBlock &m, Shape *theS);
38 #endif
40 static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass);
41 static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs);
42 static void nr_arena_glyphs_finalize(NRObject *object);
44 static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
45 static guint nr_arena_glyphs_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
46 static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, NR::Point p, double delta, unsigned int sticky);
48 static NRArenaItemClass *glyphs_parent_class;
50 NRType
51 nr_arena_glyphs_get_type(void)
52 {
53     static NRType type = 0;
54     if (!type) {
55         type = nr_object_register_type(NR_TYPE_ARENA_ITEM,
56                                        "NRArenaGlyphs",
57                                        sizeof(NRArenaGlyphsClass),
58                                        sizeof(NRArenaGlyphs),
59                                        (void (*)(NRObjectClass *)) nr_arena_glyphs_class_init,
60                                        (void (*)(NRObject *)) nr_arena_glyphs_init);
61     }
62     return type;
63 }
65 static void
66 nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass)
67 {
68     NRObjectClass *object_class;
69     NRArenaItemClass *item_class;
71     object_class = (NRObjectClass *) klass;
72     item_class = (NRArenaItemClass *) klass;
74     glyphs_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
76     object_class->finalize = nr_arena_glyphs_finalize;
77     object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>;
79     item_class->update = nr_arena_glyphs_update;
80     item_class->clip = nr_arena_glyphs_clip;
81     item_class->pick = nr_arena_glyphs_pick;
82 }
84 static void
85 nr_arena_glyphs_init(NRArenaGlyphs *glyphs)
86 {
87     glyphs->style = NULL;
88     nr_matrix_set_identity(&glyphs->g_transform);
89     glyphs->font = NULL;
90     glyphs->glyph = 0;
92     glyphs->rfont = NULL;
93     glyphs->sfont = NULL;
94     glyphs->x = glyphs->y = 0.0;
95 }
97 static void
98 nr_arena_glyphs_finalize(NRObject *object)
99 {
100     NRArenaGlyphs *glyphs = static_cast<NRArenaGlyphs *>(object);
102     if (glyphs->rfont) {
103         glyphs->rfont->Unref();
104         glyphs->rfont=NULL;
105     }
106     if (glyphs->sfont) {
107         glyphs->sfont->Unref();
108         glyphs->sfont=NULL;
109     }
111     if (glyphs->font) {
112         glyphs->font->Unref();
113         glyphs->font=NULL;
114     }
116     if (glyphs->style) {
117         sp_style_unref(glyphs->style);
118         glyphs->style = NULL;
119     }
121     ((NRObjectClass *) glyphs_parent_class)->finalize(object);
124 static guint
125 nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
127     NRArenaGlyphs *glyphs;
128     raster_font *rfont;
130     glyphs = NR_ARENA_GLYPHS(item);
132     if (!glyphs->font || !glyphs->style) return NR_ARENA_ITEM_STATE_ALL;
133     if ((glyphs->style->fill.type == SP_PAINT_TYPE_NONE) && (glyphs->style->stroke.type == SP_PAINT_TYPE_NONE)) return NR_ARENA_ITEM_STATE_ALL;
135     NRRect bbox;
136     bbox.x0 = bbox.y0 = NR_HUGE;
137     bbox.x1 = bbox.y1 = -NR_HUGE;
139     float const scale = NR_MATRIX_DF_EXPANSION(&gc->transform);
141     if (glyphs->style->fill.type != SP_PAINT_TYPE_NONE) {
142         NRMatrix t;
143         nr_matrix_multiply(&t, &glyphs->g_transform, &gc->transform);
144         glyphs->x = t.c[4];
145         glyphs->y = t.c[5];
146         t.c[4]=0;
147         t.c[5]=0;
148         rfont = glyphs->font->RasterFont(t, 0);
149         if (glyphs->rfont) glyphs->rfont->Unref();
150         glyphs->rfont = rfont;
152         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
153             NRRect narea;
154             if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea);
155             bbox.x0 = narea.x0 + glyphs->x;
156             bbox.y0 = narea.y0 + glyphs->y;
157             bbox.x1 = narea.x1 + glyphs->x;
158             bbox.y1 = narea.y1 + glyphs->y;
159         }
160     }                               
162     if (glyphs->style->stroke.type != SP_PAINT_TYPE_NONE) {
163         /* Build state data */
164         NRMatrix t;
165         nr_matrix_multiply(&t, &glyphs->g_transform, &gc->transform);
166         glyphs->x = t.c[4];
167         glyphs->y = t.c[5];
168         t.c[4]=0;
169         t.c[5]=0;
171         if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
172             font_style nstyl;
173             nstyl.transform = t;
174             nstyl.stroke_width=MAX(0.125, glyphs->style->stroke_width.computed * scale);
175             if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight;
176             if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round;
177             if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square;
178             if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy;
179             if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round;
180             if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight;
181             nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value;
182             nstyl.nbDash=0;
183             nstyl.dashes=NULL;
184             if ( glyphs->style->stroke_dash.n_dash > 0 ) {
185                 nstyl.nbDash=glyphs->style->stroke_dash.n_dash;
186                 nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double));
187                 for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale;
188             }
189             rfont = glyphs->font->RasterFont( nstyl);
190             if ( nstyl.dashes ) free(nstyl.dashes);
191             if (glyphs->sfont) glyphs->sfont->Unref();
192             glyphs->sfont = rfont;
194             NRRect narea;
195             if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea);
196             narea.x0-=nstyl.stroke_width;
197             narea.y0-=nstyl.stroke_width;
198             narea.x1+=nstyl.stroke_width;
199             narea.y1+=nstyl.stroke_width;
200             bbox.x0 = narea.x0 + glyphs->x;
201             bbox.y0 = narea.y0 + glyphs->y;
202             bbox.x1 = narea.x1 + glyphs->x;
203             bbox.y1 = narea.y1 + glyphs->y;
204         }
205     }
206     if (nr_rect_d_test_empty(&bbox)) return NR_ARENA_ITEM_STATE_ALL;
208     item->bbox.x0 = (gint32)(bbox.x0 - 1.0);
209     item->bbox.y0 = (gint32)(bbox.y0 - 1.0);
210     item->bbox.x1 = (gint32)(bbox.x1 + 1.0);
211     item->bbox.y1 = (gint32)(bbox.y1 + 1.0);
212     nr_arena_request_render_rect(item->arena, &item->bbox);
214     return NR_ARENA_ITEM_STATE_ALL;
217 static guint
218 nr_arena_glyphs_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
220     NRArenaGlyphs *glyphs;
222     glyphs = NR_ARENA_GLYPHS(item);
224     if (!glyphs->font ) return item->state;
226     /* TODO : render to greyscale pixblock provided for clipping */
228     return item->state;
231 static NRArenaItem *
232 nr_arena_glyphs_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
234     NRArenaGlyphs *glyphs;
236     glyphs = NR_ARENA_GLYPHS(item);
238     if (!glyphs->font ) return NULL;
239     if (!glyphs->style) return NULL;
240         
241     double const x = p[NR::X];
242     double const y = p[NR::Y];
243     /* With text we take a simple approach: pick if the point is in a characher bbox */
244     if ((x >= item->bbox.x0) && (y >= item->bbox.y0) && (x <= item->bbox.x1) && (y <= item->bbox.y1)) return item;
246     return NULL;
249 void
250 nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve *curve, unsigned int lieutenant, font_instance *font, gint glyph, NRMatrix const *transform)
252     nr_return_if_fail(glyphs != NULL);
253     nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));
255     nr_arena_item_request_render(NR_ARENA_ITEM(glyphs));
256   
257     if (transform) {
258         glyphs->g_transform = *transform;
259     } else {
260         nr_matrix_set_identity(&glyphs->g_transform);
261     }
262                 
263     if (font) font->Ref();
264     if (glyphs->font) glyphs->font->Unref();
265     glyphs->font=font;
266     glyphs->glyph = glyph;
268     nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
271 void
272 nr_arena_glyphs_set_style(NRArenaGlyphs *glyphs, SPStyle *style)
274     nr_return_if_fail(glyphs != NULL);
275     nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));
277     if (style) sp_style_ref(style);
278     if (glyphs->style) sp_style_unref(glyphs->style);
279     glyphs->style = style;
281     nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
284 static guint
285 nr_arena_glyphs_fill_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
287     /* fixme: area == m->area, so merge these */
289     NRArenaItem *item = NR_ARENA_ITEM(glyphs);
291     if (glyphs->rfont && nr_rect_l_test_intersect(area, &item->bbox)) {
292         raster_glyph *g = glyphs->rfont->GetGlyph(glyphs->glyph);
293         if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y), *m);
294     }
296     return item->state;
299 static guint
300 nr_arena_glyphs_stroke_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
302     NRArenaItem *item = NR_ARENA_ITEM(glyphs);
303     if (glyphs->sfont && nr_rect_l_test_intersect(area, &item->bbox)) {
304         raster_glyph *g=glyphs->sfont->GetGlyph(glyphs->glyph);
305         if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
306     }
308     return item->state;
311 static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass);
312 static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group);
313 static void nr_arena_glyphs_group_finalize(NRObject *object);
315 static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
316 static unsigned int nr_arena_glyphs_group_render(NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
317 static unsigned int nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
318 static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky);
320 static NRArenaGroupClass *group_parent_class;
322 NRType
323 nr_arena_glyphs_group_get_type(void)
325     static NRType type = 0;
326     if (!type) {
327         type = nr_object_register_type(NR_TYPE_ARENA_GROUP,
328                                        "NRArenaGlyphsGroup",
329                                        sizeof(NRArenaGlyphsGroupClass),
330                                        sizeof(NRArenaGlyphsGroup),
331                                        (void (*)(NRObjectClass *)) nr_arena_glyphs_group_class_init,
332                                        (void (*)(NRObject *)) nr_arena_glyphs_group_init);
333     }
334     return type;
337 static void
338 nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass)
340     NRObjectClass *object_class;
341     NRArenaItemClass *item_class;
343     object_class = (NRObjectClass *) klass;
344     item_class = (NRArenaItemClass *) klass;
346     group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;
348     object_class->finalize = nr_arena_glyphs_group_finalize;
349     object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;
351     item_class->update = nr_arena_glyphs_group_update;
352     item_class->render = nr_arena_glyphs_group_render;
353     item_class->clip = nr_arena_glyphs_group_clip;
354     item_class->pick = nr_arena_glyphs_group_pick;
357 static void
358 nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group)
360     group->style = NULL;
361     group->paintbox.x0 = group->paintbox.y0 = 0.0F;
362     group->paintbox.x1 = group->paintbox.y1 = 1.0F;
364     group->fill_painter = NULL;
365     group->stroke_painter = NULL;
368 static void
369 nr_arena_glyphs_group_finalize(NRObject *object)
371     NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
373     if (group->fill_painter) {
374         sp_painter_free(group->fill_painter);
375         group->fill_painter = NULL;
376     }
378     if (group->stroke_painter) {
379         sp_painter_free(group->stroke_painter);
380         group->stroke_painter = NULL;
381     }
383     if (group->style) {
384         sp_style_unref(group->style);
385         group->style = NULL;
386     }
388     ((NRObjectClass *) group_parent_class)->finalize(object);
391 static guint
392 nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
394     NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item);
396     if (group->fill_painter) {
397         sp_painter_free(group->fill_painter);
398         group->fill_painter = NULL;
399     }
401     if (group->stroke_painter) {
402         sp_painter_free(group->stroke_painter);
403         group->stroke_painter = NULL;
404     }
406     item->render_opacity = TRUE;
407     if (group->style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
408         group->fill_painter = sp_paint_server_painter_new(SP_STYLE_FILL_SERVER(group->style),
409                                                           NR::Matrix(&gc->transform), NR::Matrix(&gc->parent->transform),
410                                                           &group->paintbox);
411         item->render_opacity = FALSE;
412     }
414     if (group->style->stroke.type == SP_PAINT_TYPE_PAINTSERVER) {
415         group->stroke_painter = sp_paint_server_painter_new(SP_STYLE_STROKE_SERVER(group->style),
416                                                             NR::Matrix(&gc->transform), NR::Matrix(&gc->parent->transform),
417                                                             &group->paintbox);
418         item->render_opacity = FALSE;
419     }
421     if ( item->render_opacity == TRUE && group->style->stroke.type != SP_PAINT_TYPE_NONE && group->style->fill.type != SP_PAINT_TYPE_NONE ) {
422         item->render_opacity=FALSE;
423     }
425     if (((NRArenaItemClass *) group_parent_class)->update)
426         return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset);
428     return NR_ARENA_ITEM_STATE_ALL;
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     if (item->arena->rendermode == RENDERMODE_OUTLINE) {
445         cairo_t *ct = nr_create_cairo_context (area, pb);
447         if (!ct) 
448             return item->state;
450         guint32 rgba = item->arena->outlinecolor;
451         cairo_set_source_rgba(ct, SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_B_F(rgba), SP_RGBA32_A_F(rgba));
452         cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode
454         for (child = group->children; child != NULL; child = child->next) {
455             NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);
457             NArtBpath *bpath = (NArtBpath *) g->font->ArtBPath(g->glyph);
459             cairo_new_path(ct);
460             NR::Matrix g_t(g->g_transform);
461             feed_curve_to_cairo (ct, bpath, g_t * group->ctm, NR::Point(area->x0, area->y0));
462             cairo_fill(ct);
463         }
465         cairo_surface_t *cst = cairo_get_target(ct);
466         cairo_destroy (ct);
467         cairo_surface_finish (cst);
468         cairo_surface_destroy (cst);
470         pb->empty = FALSE;
471         return ret;
472     }
477     /* Fill */
478     if (style->fill.type != SP_PAINT_TYPE_NONE || item->arena->rendermode == RENDERMODE_OUTLINE) {
479         NRPixBlock m;
480         nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
482         // if memory allocation failed, abort 
483         if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
484             nr_pixblock_release (&m);
485             return (item->state);
486         }
488         m.visible_area = pb->visible_area; 
490         /* Render children fill mask */
491         for (child = group->children; child != NULL; child = child->next) {
492             ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, &m);
493             if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
494                 nr_pixblock_release(&m);
495                 return ret;
496             }
497         }
499         /* Composite into buffer */
500         if (style->fill.type == SP_PAINT_TYPE_COLOR || item->arena->rendermode == RENDERMODE_OUTLINE) {
501             guint32 rgba;
502             if (item->arena->rendermode == RENDERMODE_OUTLINE) {
503                 // In outline mode, render fill only, using outlinecolor
504                 rgba = item->arena->outlinecolor;
505             } else if ( item->render_opacity ) {
506                 rgba = sp_color_get_rgba32_falpha(&style->fill.value.color,
507                                                   SP_SCALE24_TO_FLOAT(style->fill_opacity.value) *
508                                                   SP_SCALE24_TO_FLOAT(style->opacity.value));
509             } else {
510                 rgba = sp_color_get_rgba32_falpha(&style->fill.value.color, SP_SCALE24_TO_FLOAT(style->fill_opacity.value));
511             }
512             nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
513             pb->empty = FALSE;
514         } else if (style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
515             if (ggroup->fill_painter) {
516                 nr_arena_render_paintserver_fill(pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT(style->fill_opacity.value), &m);
517             }
518         }
520         nr_pixblock_release(&m);
521     }
523     /* Stroke */
524     if (style->stroke.type != SP_PAINT_TYPE_NONE && !(item->arena->rendermode == RENDERMODE_OUTLINE)) {
525         NRPixBlock m;
526         guint32 rgba;
527         nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
529         // if memory allocation failed, abort 
530         if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
531             nr_pixblock_release (&m);
532             return (item->state);
533         }
535         m.visible_area = pb->visible_area; 
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;
572 static unsigned int
573 nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
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;
588 static NRArenaItem *
589 nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
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;
601 void
602 nr_arena_glyphs_group_clear(NRArenaGlyphsGroup *sg)
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     }
613 void
614 nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, NRMatrix const *transform)
616     NRArenaGroup *group;
617     NRBPath bpath;
619     group = NR_ARENA_GROUP(sg);
621     bpath.path = ( font
622                    ? (NArtBpath *) font->ArtBPath(glyph)
623                    : NULL );
624     if ( bpath.path ) {
626         nr_arena_item_request_render(NR_ARENA_ITEM(group));
628         NRArenaItem *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     }
636 void
637 nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style)
639     nr_return_if_fail(sg != NULL);
640     nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(sg));
642     NRArenaGroup *group = NR_ARENA_GROUP(sg);
644     if (style) sp_style_ref(style);
645     if (sg->style) sp_style_unref(sg->style);
646     sg->style = style;
648     for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
649         nr_return_if_fail(NR_IS_ARENA_GLYPHS(child));
650         nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(child), sg->style);
651     }
653     nr_arena_item_request_update(NR_ARENA_ITEM(sg), NR_ARENA_ITEM_STATE_ALL, FALSE);
656 void
657 nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox)
659     nr_return_if_fail(gg != NULL);
660     nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg));
661     nr_return_if_fail(pbox != NULL);
663     if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
664         gg->paintbox.x0 = pbox->x0;
665         gg->paintbox.y0 = pbox->y0;
666         gg->paintbox.x1 = pbox->x1;
667         gg->paintbox.y1 = pbox->y1;
668     } else {
669         /* fixme: We kill warning, although not sure what to do here (Lauris) */
670         gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
671         gg->paintbox.x1 = gg->paintbox.y1 = 256.0F;
672     }
674     nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE);
678 /*
679   Local Variables:
680   mode:c++
681   c-file-style:"stroustrup"
682   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
683   indent-tabs-mode:nil
684   fill-column:99
685   End:
686 */
687 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :