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 #ifdef ENABLE_SVG_FONTS
41 #include "nr-svgfonts.h"
42 #endif //#ifdef ENABLE_SVG_FONTS
44 static void nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass);
45 static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs);
46 static void nr_arena_glyphs_finalize(NRObject *object);
48 static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
49 static guint nr_arena_glyphs_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
50 static NRArenaItem *nr_arena_glyphs_pick(NRArenaItem *item, NR::Point p, double delta, unsigned int sticky);
52 static NRArenaItemClass *glyphs_parent_class;
54 NRType
55 nr_arena_glyphs_get_type(void)
56 {
57 static NRType type = 0;
58 if (!type) {
59 type = nr_object_register_type(NR_TYPE_ARENA_ITEM,
60 "NRArenaGlyphs",
61 sizeof(NRArenaGlyphsClass),
62 sizeof(NRArenaGlyphs),
63 (void (*)(NRObjectClass *)) nr_arena_glyphs_class_init,
64 (void (*)(NRObject *)) nr_arena_glyphs_init);
65 }
66 return type;
67 }
69 static void
70 nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass)
71 {
72 NRObjectClass *object_class;
73 NRArenaItemClass *item_class;
75 object_class = (NRObjectClass *) klass;
76 item_class = (NRArenaItemClass *) klass;
78 glyphs_parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
80 object_class->finalize = nr_arena_glyphs_finalize;
81 object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphs>;
83 item_class->update = nr_arena_glyphs_update;
84 item_class->clip = nr_arena_glyphs_clip;
85 item_class->pick = nr_arena_glyphs_pick;
86 }
88 static void
89 nr_arena_glyphs_init(NRArenaGlyphs *glyphs)
90 {
91 glyphs->style = NULL;
92 glyphs->g_transform.set_identity();
93 glyphs->font = NULL;
94 glyphs->glyph = 0;
96 glyphs->rfont = NULL;
97 glyphs->sfont = NULL;
98 glyphs->x = glyphs->y = 0.0;
99 }
101 static void
102 nr_arena_glyphs_finalize(NRObject *object)
103 {
104 NRArenaGlyphs *glyphs = static_cast<NRArenaGlyphs *>(object);
106 if (glyphs->rfont) {
107 glyphs->rfont->Unref();
108 glyphs->rfont=NULL;
109 }
110 if (glyphs->sfont) {
111 glyphs->sfont->Unref();
112 glyphs->sfont=NULL;
113 }
115 if (glyphs->font) {
116 glyphs->font->Unref();
117 glyphs->font=NULL;
118 }
120 if (glyphs->style) {
121 sp_style_unref(glyphs->style);
122 glyphs->style = NULL;
123 }
125 ((NRObjectClass *) glyphs_parent_class)->finalize(object);
126 }
128 static guint
129 nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*state*/, guint /*reset*/)
130 {
131 NRArenaGlyphs *glyphs;
132 raster_font *rfont;
134 glyphs = NR_ARENA_GLYPHS(item);
136 if (!glyphs->font || !glyphs->style)
137 return NR_ARENA_ITEM_STATE_ALL;
138 if ((glyphs->style->fill.isNone()) && (glyphs->style->stroke.isNone()))
139 return NR_ARENA_ITEM_STATE_ALL;
141 NRRect bbox;
142 bbox.x0 = bbox.y0 = NR_HUGE;
143 bbox.x1 = bbox.y1 = -NR_HUGE;
145 float const scale = NR::expansion(gc->transform);
147 if (!glyphs->style->fill.isNone()) {
148 NR::Matrix t;
149 t = glyphs->g_transform * gc->transform;
150 glyphs->x = t[4];
151 glyphs->y = t[5];
152 t[4]=0;
153 t[5]=0;
154 rfont = glyphs->font->RasterFont(t, 0);
155 if (glyphs->rfont) glyphs->rfont->Unref();
156 glyphs->rfont = rfont;
158 if (glyphs->style->stroke.isNone() || fabs(glyphs->style->stroke_width.computed * scale) <= 0.01) { // Optimization: do fill bbox only if there's no stroke
159 NRRect narea;
160 if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea);
161 bbox.x0 = narea.x0 + glyphs->x;
162 bbox.y0 = narea.y0 + glyphs->y;
163 bbox.x1 = narea.x1 + glyphs->x;
164 bbox.y1 = narea.y1 + glyphs->y;
165 }
166 }
168 if (!glyphs->style->stroke.isNone()) {
169 /* Build state data */
170 NR::Matrix t;
171 t = glyphs->g_transform * gc->transform;
172 glyphs->x = t[4];
173 glyphs->y = t[5];
174 t[4]=0;
175 t[5]=0;
177 if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
178 font_style nstyl;
179 nstyl.transform = t;
180 nstyl.stroke_width=MAX(0.125, glyphs->style->stroke_width.computed * scale);
181 if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight;
182 if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round;
183 if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square;
184 if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy;
185 if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round;
186 if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight;
187 nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value;
188 nstyl.nbDash=0;
189 nstyl.dash_offset = 0;
190 nstyl.dashes=NULL;
191 if ( glyphs->style->stroke_dash.n_dash > 0 ) {
192 nstyl.dash_offset = glyphs->style->stroke_dash.offset * scale;
193 nstyl.nbDash=glyphs->style->stroke_dash.n_dash;
194 nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double));
195 for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale;
196 }
197 rfont = glyphs->font->RasterFont( nstyl);
198 if ( nstyl.dashes ) free(nstyl.dashes);
199 if (glyphs->sfont) glyphs->sfont->Unref();
200 glyphs->sfont = rfont;
202 NRRect narea;
203 if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea);
204 narea.x0-=nstyl.stroke_width;
205 narea.y0-=nstyl.stroke_width;
206 narea.x1+=nstyl.stroke_width;
207 narea.y1+=nstyl.stroke_width;
208 bbox.x0 = narea.x0 + glyphs->x;
209 bbox.y0 = narea.y0 + glyphs->y;
210 bbox.x1 = narea.x1 + glyphs->x;
211 bbox.y1 = narea.y1 + glyphs->y;
212 }
213 }
214 if (nr_rect_d_test_empty(&bbox)) return NR_ARENA_ITEM_STATE_ALL;
216 item->bbox.x0 = (gint32)(bbox.x0 - 1.0);
217 item->bbox.y0 = (gint32)(bbox.y0 - 1.0);
218 item->bbox.x1 = (gint32)(bbox.x1 + 1.0);
219 item->bbox.y1 = (gint32)(bbox.y1 + 1.0);
220 nr_arena_request_render_rect(item->arena, &item->bbox);
222 return NR_ARENA_ITEM_STATE_ALL;
223 }
225 static guint
226 nr_arena_glyphs_clip(NRArenaItem *item, NRRectL */*area*/, NRPixBlock */*pb*/)
227 {
228 NRArenaGlyphs *glyphs;
230 glyphs = NR_ARENA_GLYPHS(item);
232 if (!glyphs->font ) return item->state;
234 /* TODO : render to greyscale pixblock provided for clipping */
236 return item->state;
237 }
239 static NRArenaItem *
240 nr_arena_glyphs_pick(NRArenaItem *item, NR::Point p, gdouble /*delta*/, unsigned int /*sticky*/)
241 {
242 NRArenaGlyphs *glyphs;
244 glyphs = NR_ARENA_GLYPHS(item);
246 if (!glyphs->font ) return NULL;
247 if (!glyphs->style) return NULL;
249 double const x = p[NR::X];
250 double const y = p[NR::Y];
251 /* With text we take a simple approach: pick if the point is in a characher bbox */
252 if ((x >= item->bbox.x0) && (y >= item->bbox.y0) && (x <= item->bbox.x1) && (y <= item->bbox.y1)) return item;
254 return NULL;
255 }
257 void
258 nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve */*curve*/, unsigned int /*lieutenant*/, font_instance *font, gint glyph, NR::Matrix const *transform)
259 {
260 nr_return_if_fail(glyphs != NULL);
261 nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));
263 nr_arena_item_request_render(NR_ARENA_ITEM(glyphs));
265 if (transform) {
266 glyphs->g_transform = *transform;
267 } else {
268 glyphs->g_transform.set_identity();
269 }
271 if (font) font->Ref();
272 if (glyphs->font) glyphs->font->Unref();
273 glyphs->font=font;
274 glyphs->glyph = glyph;
276 nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
277 }
279 void
280 nr_arena_glyphs_set_style(NRArenaGlyphs *glyphs, SPStyle *style)
281 {
282 nr_return_if_fail(glyphs != NULL);
283 nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs));
285 if (style) sp_style_ref(style);
286 if (glyphs->style) sp_style_unref(glyphs->style);
287 glyphs->style = style;
289 nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE);
290 }
292 static guint
293 nr_arena_glyphs_fill_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
294 {
295 /* fixme: area == m->area, so merge these */
297 NRArenaItem *item = NR_ARENA_ITEM(glyphs);
299 if (glyphs->rfont && nr_rect_l_test_intersect(area, &item->bbox)) {
300 raster_glyph *g = glyphs->rfont->GetGlyph(glyphs->glyph);
301 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y), *m);
302 }
304 return item->state;
305 }
307 static guint
308 nr_arena_glyphs_stroke_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m)
309 {
310 NRArenaItem *item = NR_ARENA_ITEM(glyphs);
311 if (glyphs->sfont && nr_rect_l_test_intersect(area, &item->bbox)) {
312 raster_glyph *g=glyphs->sfont->GetGlyph(glyphs->glyph);
313 if ( g ) g->Blit(NR::Point(glyphs->x, glyphs->y),*m);
314 }
316 return item->state;
317 }
319 static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass);
320 static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group);
321 static void nr_arena_glyphs_group_finalize(NRObject *object);
323 static guint nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset);
324 static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
325 static unsigned int nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
326 static NRArenaItem *nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky);
328 static NRArenaGroupClass *group_parent_class;
330 NRType
331 nr_arena_glyphs_group_get_type(void)
332 {
333 static NRType type = 0;
334 if (!type) {
335 type = nr_object_register_type(NR_TYPE_ARENA_GROUP,
336 "NRArenaGlyphsGroup",
337 sizeof(NRArenaGlyphsGroupClass),
338 sizeof(NRArenaGlyphsGroup),
339 (void (*)(NRObjectClass *)) nr_arena_glyphs_group_class_init,
340 (void (*)(NRObject *)) nr_arena_glyphs_group_init);
341 }
342 return type;
343 }
345 static void
346 nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass)
347 {
348 NRObjectClass *object_class;
349 NRArenaItemClass *item_class;
351 object_class = (NRObjectClass *) klass;
352 item_class = (NRArenaItemClass *) klass;
354 group_parent_class = (NRArenaGroupClass *) ((NRObjectClass *) klass)->parent;
356 object_class->finalize = nr_arena_glyphs_group_finalize;
357 object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGlyphsGroup>;
359 item_class->update = nr_arena_glyphs_group_update;
360 item_class->render = nr_arena_glyphs_group_render;
361 item_class->clip = nr_arena_glyphs_group_clip;
362 item_class->pick = nr_arena_glyphs_group_pick;
363 }
365 static void
366 nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group)
367 {
368 group->style = NULL;
369 group->paintbox.x0 = group->paintbox.y0 = 0.0F;
370 group->paintbox.x1 = group->paintbox.y1 = 1.0F;
372 group->fill_painter = NULL;
373 group->stroke_painter = NULL;
374 }
376 static void
377 nr_arena_glyphs_group_finalize(NRObject *object)
378 {
379 NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object);
381 if (group->fill_painter) {
382 sp_painter_free(group->fill_painter);
383 group->fill_painter = NULL;
384 }
386 if (group->stroke_painter) {
387 sp_painter_free(group->stroke_painter);
388 group->stroke_painter = NULL;
389 }
391 if (group->style) {
392 sp_style_unref(group->style);
393 group->style = NULL;
394 }
396 ((NRObjectClass *) group_parent_class)->finalize(object);
397 }
399 static guint
400 nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset)
401 {
402 NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item);
404 if (group->fill_painter) {
405 sp_painter_free(group->fill_painter);
406 group->fill_painter = NULL;
407 }
409 if (group->stroke_painter) {
410 sp_painter_free(group->stroke_painter);
411 group->stroke_painter = NULL;
412 }
414 item->render_opacity = TRUE;
415 if (group->style->fill.isPaintserver()) {
416 group->fill_painter = sp_paint_server_painter_new(SP_STYLE_FILL_SERVER(group->style),
417 gc->transform, gc->parent->transform,
418 &group->paintbox);
419 item->render_opacity = FALSE;
420 }
422 if (group->style->stroke.isPaintserver()) {
423 group->stroke_painter = sp_paint_server_painter_new(SP_STYLE_STROKE_SERVER(group->style),
424 gc->transform, gc->parent->transform,
425 &group->paintbox);
426 item->render_opacity = FALSE;
427 }
429 if ( item->render_opacity == TRUE && !group->style->stroke.isNone() && !group->style->fill.isNone() ) {
430 item->render_opacity=FALSE;
431 }
433 if (((NRArenaItemClass *) group_parent_class)->update)
434 return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset);
436 return NR_ARENA_ITEM_STATE_ALL;
437 }
440 static unsigned int
441 nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int /*flags*/)
442 {
443 NRArenaItem *child;
445 NRArenaGroup *group = NR_ARENA_GROUP(item);
446 NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item);
447 SPStyle const *style = ggroup->style;
449 guint ret = item->state;
451 if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
453 if (!ct)
454 return item->state;
456 guint32 rgba = item->arena->outlinecolor;
457 // FIXME: we use RGBA buffers but cairo writes BGRA (on i386), so we must cheat
458 // by setting color channels in the "wrong" order
459 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));
460 cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode
462 for (child = group->children; child != NULL; child = child->next) {
463 NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);
465 NArtBpath *bpath = (NArtBpath *) g->font->ArtBPath(g->glyph);
467 cairo_new_path(ct);
468 NR::Matrix g_t(g->g_transform);
469 feed_curve_to_cairo (ct, bpath, g_t * group->ctm, (pb->area).upgrade(), false, 0);
470 cairo_fill(ct);
471 pb->empty = FALSE;
472 }
474 return ret;
475 }
479 /* Fill */
480 if (!style->fill.isNone() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
481 NRPixBlock m;
482 nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
484 // if memory allocation failed, abort
485 if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
486 nr_pixblock_release (&m);
487 return (item->state);
488 }
490 m.visible_area = pb->visible_area;
492 /* Render children fill mask */
493 for (child = group->children; child != NULL; child = child->next) {
494 ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, &m);
495 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
496 nr_pixblock_release(&m);
497 return ret;
498 }
499 }
501 /* Composite into buffer */
502 if (style->fill.isPaintserver()) {
503 if (ggroup->fill_painter) {
504 nr_arena_render_paintserver_fill(pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT(style->fill_opacity.value), &m);
505 }
506 } else if (style->fill.isColor() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
507 guint32 rgba;
508 if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) {
509 // In outline mode, render fill only, using outlinecolor
510 rgba = item->arena->outlinecolor;
511 } else if ( item->render_opacity ) {
512 rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) *
513 SP_SCALE24_TO_FLOAT(style->opacity.value) );
514 } else {
515 rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) );
516 }
517 nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
518 pb->empty = FALSE;
519 }
521 nr_pixblock_release(&m);
522 }
524 /* Stroke */
525 if (!style->stroke.isNone() && !(item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE)) {
526 NRPixBlock m;
527 guint32 rgba;
528 nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
530 // if memory allocation failed, abort
531 if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) {
532 nr_pixblock_release (&m);
533 return (item->state);
534 }
536 m.visible_area = pb->visible_area;
537 /* Render children stroke mask */
538 for (child = group->children; child != NULL; child = child->next) {
539 ret = nr_arena_glyphs_stroke_mask(NR_ARENA_GLYPHS(child), area, &m);
540 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) {
541 nr_pixblock_release(&m);
542 return ret;
543 }
544 }
545 /* Composite into buffer */
546 if (style->stroke.isPaintserver()) {
547 if (ggroup->stroke_painter) {
548 nr_arena_render_paintserver_fill(pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value), &m);
549 }
550 } else if (style->stroke.isColor()) {
551 if ( item->render_opacity ) {
552 rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) *
553 SP_SCALE24_TO_FLOAT(style->opacity.value) );
554 } else {
555 rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) );
556 }
557 nr_blit_pixblock_mask_rgba32(pb, &m, rgba);
558 pb->empty = FALSE;
559 } else {
560 // nothing
561 }
562 nr_pixblock_release(&m);
563 }
565 return ret;
566 }
568 static unsigned int
569 nr_arena_glyphs_group_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
570 {
571 NRArenaGroup *group = NR_ARENA_GROUP(item);
573 guint ret = item->state;
575 /* Render children fill mask */
576 for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
577 ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, pb);
578 if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret;
579 }
581 return ret;
582 }
584 static NRArenaItem *
585 nr_arena_glyphs_group_pick(NRArenaItem *item, NR::Point p, gdouble delta, unsigned int sticky)
586 {
587 NRArenaItem *picked = NULL;
589 if (((NRArenaItemClass *) group_parent_class)->pick)
590 picked = ((NRArenaItemClass *) group_parent_class)->pick(item, p, delta, sticky);
592 if (picked) picked = item;
594 return picked;
595 }
597 void
598 nr_arena_glyphs_group_clear(NRArenaGlyphsGroup *sg)
599 {
600 NRArenaGroup *group = NR_ARENA_GROUP(sg);
602 nr_arena_item_request_render(NR_ARENA_ITEM(group));
604 while (group->children) {
605 nr_arena_item_remove_child(NR_ARENA_ITEM(group), group->children);
606 }
607 }
609 void
610 nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, NR::Matrix const *transform)
611 {
612 NRArenaGroup *group;
613 NRBPath bpath;
615 group = NR_ARENA_GROUP(sg);
617 bpath.path = ( font
618 ? (NArtBpath *) font->ArtBPath(glyph)
619 : NULL );
620 if ( bpath.path ) {
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 }
630 }
632 void
633 nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style)
634 {
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);
650 }
652 void
653 nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox)
654 {
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);
671 }
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 :