Code

Rename LPE: mirror reflect --> mirror symmetry
[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 <libnr/nr-convert2geom.h>
25 #include <2geom/matrix.h>
26 #include "../style.h"
27 #include "nr-arena.h"
28 #include "nr-arena-glyphs.h"
29 #include <cairo.h>
30 #include "inkscape-cairo.h"
32 #ifdef test_glyph_liv
33 #include "../display/canvas-bpath.h"
34 #include <libnrtype/font-instance.h>
35 #include <libnrtype/raster-glyph.h>
36 #include <libnrtype/RasterFont.h>
38 // defined in nr-arena-shape.cpp
39 void nr_pixblock_render_shape_mask_or(NRPixBlock &m, Shape *theS);
40 #endif
42 #ifdef ENABLE_SVG_FONTS
43 #include "nr-svgfonts.h"
44 #endif //#ifdef ENABLE_SVG_FONTS
46 static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass);
47 static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs);
48 static void nr_arena_glyphs_finalize(NRObject *object);
50 static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
51 static guint nr_arena_glyphs_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
52 static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, NR::Point p, double delta, unsigned int sticky);
54 static NRArenaItemClass *glyphs_parent_class;
56 NRType
57 nr_arena_glyphs_get_type(void)
58 {
59     static NRType type = 0;
60     if (!type) {
61         type = nr_object_register_type(NR_TYPE_ARENA_ITEM,
62                                        "NRArenaGlyphs",
63                                        sizeof(NRArenaGlyphsClass),
64                                        sizeof(NRArenaGlyphs),
65                                        (void (*)(NRObjectClass *)) nr_arena_glyphs_class_init,
66                                        (void (*)(NRObject *)) nr_arena_glyphs_init);
67     }
68     return type;
69 }
71 static void
72 nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass)
73 {
74     NRObjectClass *object_class;
75     NRArenaItemClass *item_class;
77     object_class = (NRObjectClass *) klass;
78     item_class = (NRArenaItemClass *) klass;
80     glyphs_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
82     object_class->finalize = nr_arena_glyphs_finalize;
83     object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>;
85     item_class->update = nr_arena_glyphs_update;
86     item_class->clip = nr_arena_glyphs_clip;
87     item_class->pick = nr_arena_glyphs_pick;
88 }
90 static void
91 nr_arena_glyphs_init(NRArenaGlyphs *glyphs)
92 {
93     glyphs->style = NULL;
94     glyphs->g_transform.set_identity();
95     glyphs->font = NULL;
96     glyphs->glyph = 0;
98     glyphs->rfont = NULL;
99     glyphs->sfont = NULL;
100     glyphs->x = glyphs->y = 0.0;
103 static void
104 nr_arena_glyphs_finalize(NRObject *object)
106     NRArenaGlyphs *glyphs = static_cast<NRArenaGlyphs *>(object);
108     if (glyphs->rfont) {
109         glyphs->rfont->Unref();
110         glyphs->rfont=NULL;
111     }
112     if (glyphs->sfont) {
113         glyphs->sfont->Unref();
114         glyphs->sfont=NULL;
115     }
117     if (glyphs->font) {
118         glyphs->font->Unref();
119         glyphs->font=NULL;
120     }
122     if (glyphs->style) {
123         sp_style_unref(glyphs->style);
124         glyphs->style = NULL;
125     }
127     ((NRObjectClass *) glyphs_parent_class)->finalize(object);
130 static guint
131 nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*state*/, guint /*reset*/)
133     NRArenaGlyphs *glyphs;
134     raster_font *rfont;
136     glyphs = NR_ARENA_GLYPHS(item);
138     if (!glyphs->font || !glyphs->style)
139         return NR_ARENA_ITEM_STATE_ALL;
140     if ((glyphs->style->fill.isNone()) && (glyphs->style->stroke.isNone()))
141         return NR_ARENA_ITEM_STATE_ALL;
143     NRRect bbox;
144     bbox.x0 = bbox.y0 = NR_HUGE;
145     bbox.x1 = bbox.y1 = -NR_HUGE;
147     float const scale = NR::expansion(gc->transform);
149     if (!glyphs->style->fill.isNone()) {
150         NR::Matrix t;
151         t = glyphs->g_transform * gc->transform;
152         glyphs->x = t[4];
153         glyphs->y = t[5];
154         t[4]=0;
155         t[5]=0;
156         rfont = glyphs->font->RasterFont(t, 0);
157         if (glyphs->rfont) glyphs->rfont->Unref();
158         glyphs->rfont = rfont;
160         if (glyphs->style->stroke.isNone() || fabs(glyphs->style->stroke_width.computed * scale) <= 0.01) { // Optimization: do fill bbox only if there's no stroke
161             NRRect narea;
162             if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea);
163             bbox.x0 = narea.x0 + glyphs->x;
164             bbox.y0 = narea.y0 + glyphs->y;
165             bbox.x1 = narea.x1 + glyphs->x;
166             bbox.y1 = narea.y1 + glyphs->y;
167         }
168     }
170     if (!glyphs->style->stroke.isNone()) {
171         /* Build state data */
172         NR::Matrix t;
173         t = glyphs->g_transform * gc->transform;
174         glyphs->x = t[4];
175         glyphs->y = t[5];
176         t[4]=0;
177         t[5]=0;
179         if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
180             font_style nstyl;
181             nstyl.transform = t;
182             nstyl.stroke_width=MAX(0.125, glyphs->style->stroke_width.computed * scale);
183             if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight;
184             if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round;
185             if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square;
186             if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy;
187             if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round;
188             if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight;
189             nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value;
190             nstyl.nbDash=0;
191             nstyl.dash_offset = 0;
192             nstyl.dashes=NULL;
193             if ( glyphs->style->stroke_dash.n_dash > 0 ) {
194                 nstyl.dash_offset = glyphs->style->stroke_dash.offset * scale;
195                 nstyl.nbDash=glyphs->style->stroke_dash.n_dash;
196                 nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double));
197                 for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale;
198             }
199             rfont = glyphs->font->RasterFont( nstyl);
200             if ( nstyl.dashes ) free(nstyl.dashes);
201             if (glyphs->sfont) glyphs->sfont->Unref();
202             glyphs->sfont = rfont;
204             NRRect narea;
205             if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea);
206             narea.x0-=nstyl.stroke_width;
207             narea.y0-=nstyl.stroke_width;
208             narea.x1+=nstyl.stroke_width;
209             narea.y1+=nstyl.stroke_width;
210             bbox.x0 = narea.x0 + glyphs->x;
211             bbox.y0 = narea.y0 + glyphs->y;
212             bbox.x1 = narea.x1 + glyphs->x;
213             bbox.y1 = narea.y1 + glyphs->y;
214         }
215     }
216     if (nr_rect_d_test_empty(&bbox)) return NR_ARENA_ITEM_STATE_ALL;
218     item->bbox.x0 = (gint32)(bbox.x0 - 1.0);
219     item->bbox.y0 = (gint32)(bbox.y0 - 1.0);
220     item->bbox.x1 = (gint32)(bbox.x1 + 1.0);
221     item->bbox.y1 = (gint32)(bbox.y1 + 1.0);
222     nr_arena_request_render_rect(item->arena, &item->bbox);
224     return NR_ARENA_ITEM_STATE_ALL;
227 static guint
228 nr_arena_glyphs_clip(NRArenaItem *item, NRRectL */*area*/, NRPixBlock */*pb*/)
230     NRArenaGlyphs *glyphs;
232     glyphs = NR_ARENA_GLYPHS(item);
234     if (!glyphs->font ) return item->state;
236     /* TODO : render to greyscale pixblock provided for clipping */
238     return item->state;
241 static NRArenaItem *
242 nr_arena_glyphs_pick(NRArenaItem *item, NR::Point p, gdouble /*delta*/, unsigned int /*sticky*/)
244     NRArenaGlyphs *glyphs;
246     glyphs = NR_ARENA_GLYPHS(item);
248     if (!glyphs->font ) return NULL;
249     if (!glyphs->style) return NULL;
251     double const x = p[NR::X];
252     double const y = p[NR::Y];
253     /* With text we take a simple approach: pick if the point is in a characher bbox */
254     if ((x >= item->bbox.x0) && (y >= item->bbox.y0) && (x <= item->bbox.x1) && (y <= item->bbox.y1)) return item;
256     return NULL;
259 void
260 nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve */*curve*/, unsigned int /*lieutenant*/, font_instance *font, gint glyph, NR::Matrix const *transform)
262     nr_return_if_fail(glyphs != NULL);
263     nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));
265     nr_arena_item_request_render(NR_ARENA_ITEM(glyphs));
267     if (transform) {
268         glyphs->g_transform = *transform;
269     } else {
270         glyphs->g_transform.set_identity();
271     }
273     if (font) font->Ref();
274     if (glyphs->font) glyphs->font->Unref();
275     glyphs->font=font;
276     glyphs->glyph = glyph;
278     nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
281 void
282 nr_arena_glyphs_set_style(NRArenaGlyphs *glyphs, SPStyle *style)
284     nr_return_if_fail(glyphs != NULL);
285     nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));
287     if (style) sp_style_ref(style);
288     if (glyphs->style) sp_style_unref(glyphs->style);
289     glyphs->style = style;
291     nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
294 static guint
295 nr_arena_glyphs_fill_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
297     /* fixme: area == m->area, so merge these */
299     NRArenaItem *item = NR_ARENA_ITEM(glyphs);
301     if (glyphs->rfont && nr_rect_l_test_intersect(area, &item->bbox)) {
302         raster_glyph *g = glyphs->rfont->GetGlyph(glyphs->glyph);
303         if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y), *m);
304     }
306     return item->state;
309 static guint
310 nr_arena_glyphs_stroke_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
312     NRArenaItem *item = NR_ARENA_ITEM(glyphs);
313     if (glyphs->sfont && nr_rect_l_test_intersect(area, &item->bbox)) {
314         raster_glyph *g=glyphs->sfont->GetGlyph(glyphs->glyph);
315         if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
316     }
318     return item->state;
321 static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass);
322 static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group);
323 static void nr_arena_glyphs_group_finalize(NRObject *object);
325 static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
326 static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
327 static unsigned int nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
328 static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky);
330 static NRArenaGroupClass *group_parent_class;
332 NRType
333 nr_arena_glyphs_group_get_type(void)
335     static NRType type = 0;
336     if (!type) {
337         type = nr_object_register_type(NR_TYPE_ARENA_GROUP,
338                                        "NRArenaGlyphsGroup",
339                                        sizeof(NRArenaGlyphsGroupClass),
340                                        sizeof(NRArenaGlyphsGroup),
341                                        (void (*)(NRObjectClass *)) nr_arena_glyphs_group_class_init,
342                                        (void (*)(NRObject *)) nr_arena_glyphs_group_init);
343     }
344     return type;
347 static void
348 nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass)
350     NRObjectClass *object_class;
351     NRArenaItemClass *item_class;
353     object_class = (NRObjectClass *) klass;
354     item_class = (NRArenaItemClass *) klass;
356     group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;
358     object_class->finalize = nr_arena_glyphs_group_finalize;
359     object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;
361     item_class->update = nr_arena_glyphs_group_update;
362     item_class->render = nr_arena_glyphs_group_render;
363     item_class->clip = nr_arena_glyphs_group_clip;
364     item_class->pick = nr_arena_glyphs_group_pick;
367 static void
368 nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group)
370     group->style = NULL;
371     group->paintbox.x0 = group->paintbox.y0 = 0.0F;
372     group->paintbox.x1 = group->paintbox.y1 = 1.0F;
374     group->fill_painter = NULL;
375     group->stroke_painter = NULL;
378 static void
379 nr_arena_glyphs_group_finalize(NRObject *object)
381     NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
383     if (group->fill_painter) {
384         sp_painter_free(group->fill_painter);
385         group->fill_painter = NULL;
386     }
388     if (group->stroke_painter) {
389         sp_painter_free(group->stroke_painter);
390         group->stroke_painter = NULL;
391     }
393     if (group->style) {
394         sp_style_unref(group->style);
395         group->style = NULL;
396     }
398     ((NRObjectClass *) group_parent_class)->finalize(object);
401 static guint
402 nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
404     NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item);
406     if (group->fill_painter) {
407         sp_painter_free(group->fill_painter);
408         group->fill_painter = NULL;
409     }
411     if (group->stroke_painter) {
412         sp_painter_free(group->stroke_painter);
413         group->stroke_painter = NULL;
414     }
416     item->render_opacity = TRUE;
417     if (group->style->fill.isPaintserver()) {
418         group->fill_painter = sp_paint_server_painter_new(SP_STYLE_FILL_SERVER(group->style),
419                                                           gc->transform, gc->parent->transform,
420                                                           &group->paintbox);
421         item->render_opacity = FALSE;
422     }
424     if (group->style->stroke.isPaintserver()) {
425         group->stroke_painter = sp_paint_server_painter_new(SP_STYLE_STROKE_SERVER(group->style),
426                                                             gc->transform, gc->parent->transform,
427                                                             &group->paintbox);
428         item->render_opacity = FALSE;
429     }
431     if ( item->render_opacity == TRUE && !group->style->stroke.isNone() && !group->style->fill.isNone() ) {
432         item->render_opacity=FALSE;
433     }
435     if (((NRArenaItemClass *) group_parent_class)->update)
436         return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset);
438     return NR_ARENA_ITEM_STATE_ALL;
442 static unsigned int
443 nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int /*flags*/)
445     NRArenaItem *child;
447     NRArenaGroup *group = NR_ARENA_GROUP(item);
448     NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item);
449     SPStyle const *style = ggroup->style;
451     guint ret = item->state;
453     if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
455         if (!ct)
456             return item->state;
458         guint32 rgba = item->arena->outlinecolor;
459         // FIXME: we use RGBA buffers but cairo writes BGRA (on i386), so we must cheat
460         // by setting color channels in the "wrong" order
461         cairo_set_source_rgba(ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba));
462         cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode
464         for (child = group->children; child != NULL; child = child->next) {
465             NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);
467             Geom::PathVector const * pathv = g->font->PathVector(g->glyph);
469             cairo_new_path(ct);
470             Geom::Matrix transform = to_2geom(g->g_transform * group->ctm);
471             feed_pathvector_to_cairo (ct, *pathv, transform, (pb->area).upgrade(), false, 0);
472             cairo_fill(ct);
473             pb->empty = FALSE;
474         }
476         return ret;
477     }
481     /* Fill */
482     if (!style->fill.isNone() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
483         NRPixBlock m;
484         nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
486         // if memory allocation failed, abort
487         if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
488             nr_pixblock_release (&m);
489             return (item->state);
490         }
492         m.visible_area = pb->visible_area;
494         /* Render children fill mask */
495         for (child = group->children; child != NULL; child = child->next) {
496             ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, &m);
497             if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
498                 nr_pixblock_release(&m);
499                 return ret;
500             }
501         }
503         /* Composite into buffer */
504         if (style->fill.isPaintserver()) {
505             if (ggroup->fill_painter) {
506                 nr_arena_render_paintserver_fill(pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT(style->fill_opacity.value), &m);
507             }
508         } else if (style->fill.isColor() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
509             guint32 rgba;
510             if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
511                 // In outline mode, render fill only, using outlinecolor
512                 rgba = item->arena->outlinecolor;
513             } else if ( item->render_opacity ) {
514                 rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) *
515                                                          SP_SCALE24_TO_FLOAT(style->opacity.value) );
516             } else {
517                 rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) );
518             }
519             nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
520             pb->empty = FALSE;
521         }
523         nr_pixblock_release(&m);
524     }
526     /* Stroke */
527     if (!style->stroke.isNone() && !(item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE)) {
528         NRPixBlock m;
529         guint32 rgba;
530         nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
532         // if memory allocation failed, abort
533         if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
534             nr_pixblock_release (&m);
535             return (item->state);
536         }
538         m.visible_area = pb->visible_area;
539         /* Render children stroke mask */
540         for (child = group->children; child != NULL; child = child->next) {
541             ret = nr_arena_glyphs_stroke_mask(NR_ARENA_GLYPHS(child), area, &m);
542             if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
543                 nr_pixblock_release(&m);
544                 return ret;
545             }
546         }
547         /* Composite into buffer */
548         if (style->stroke.isPaintserver()) {
549             if (ggroup->stroke_painter) {
550                 nr_arena_render_paintserver_fill(pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value), &m);
551             }
552         } else if (style->stroke.isColor()) {
553             if ( item->render_opacity ) {
554                 rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) *
555                                                            SP_SCALE24_TO_FLOAT(style->opacity.value) );
556             } else {
557                 rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) );
558             }
559             nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
560             pb->empty = FALSE;
561         } else {
562             // nothing
563         }
564         nr_pixblock_release(&m);
565     }
567     return ret;
570 static unsigned int
571 nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
573     NRArenaGroup *group = NR_ARENA_GROUP(item);
575     guint ret = item->state;
577     /* Render children fill mask */
578     for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
579         ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, pb);
580         if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret;
581     }
583     return ret;
586 static NRArenaItem *
587 nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
589     NRArenaItem *picked = NULL;
591     if (((NRArenaItemClass *) group_parent_class)->pick)
592         picked = ((NRArenaItemClass *) group_parent_class)->pick(item, p, delta, sticky);
594     if (picked) picked = item;
596     return picked;
599 void
600 nr_arena_glyphs_group_clear(NRArenaGlyphsGroup *sg)
602     NRArenaGroup *group = NR_ARENA_GROUP(sg);
604     nr_arena_item_request_render(NR_ARENA_ITEM(group));
606     while (group->children) {
607         nr_arena_item_remove_child(NR_ARENA_ITEM(group), group->children);
608     }
611 void
612 nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, NR::Matrix const *transform)
614     NRArenaGroup *group;
616     group = NR_ARENA_GROUP(sg);
618     Geom::PathVector const * pathv = ( font
619                                        ? font->PathVector(glyph)
620                                        : NULL );
621     if ( pathv ) {
622         nr_arena_item_request_render(NR_ARENA_ITEM(group));
624         NRArenaItem *new_arena = NRArenaGlyphs::create(group->arena);
625         nr_arena_item_append_child(NR_ARENA_ITEM(group), new_arena);
626         nr_arena_item_unref(new_arena);
627         nr_arena_glyphs_set_path(NR_ARENA_GLYPHS(new_arena), NULL, FALSE, font, glyph, transform);
628         nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(new_arena), sg->style);
629     }
632 void
633 nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style)
635     nr_return_if_fail(sg != NULL);
636     nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(sg));
638     NRArenaGroup *group = NR_ARENA_GROUP(sg);
640     if (style) sp_style_ref(style);
641     if (sg->style) sp_style_unref(sg->style);
642     sg->style = style;
644     for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
645         nr_return_if_fail(NR_IS_ARENA_GLYPHS(child));
646         nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(child), sg->style);
647     }
649     nr_arena_item_request_update(NR_ARENA_ITEM(sg), NR_ARENA_ITEM_STATE_ALL, FALSE);
652 void
653 nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox)
655     nr_return_if_fail(gg != NULL);
656     nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(gg));
657     nr_return_if_fail(pbox != NULL);
659     if ((pbox->x0 < pbox->x1) && (pbox->y0 < pbox->y1)) {
660         gg->paintbox.x0 = pbox->x0;
661         gg->paintbox.y0 = pbox->y0;
662         gg->paintbox.x1 = pbox->x1;
663         gg->paintbox.y1 = pbox->y1;
664     } else {
665         /* fixme: We kill warning, although not sure what to do here (Lauris) */
666         gg->paintbox.x0 = gg->paintbox.y0 = 0.0F;
667         gg->paintbox.x1 = gg->paintbox.y1 = 256.0F;
668     }
670     nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE);
674 /*
675   Local Variables:
676   mode:c++
677   c-file-style:"stroustrup"
678   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
679   indent-tabs-mode:nil
680   fill-column:99
681   End:
682 */
683 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :