diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2010-06-28 00:37:10 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2010-06-28 00:37:10 +0000 |
| commit | cf6ce8045cd7a019c263d557fd2ea6c3b8a0e669 (patch) | |
| tree | f9decbfe9e67caac94235d9f1198bef450ab9bb9 /src/display/nr-arena-glyphs.cpp | |
| parent | Implement clipping (slightly incorrect) and masking (diff) | |
| download | inkscape-cf6ce8045cd7a019c263d557fd2ea6c3b8a0e669.tar.gz inkscape-cf6ce8045cd7a019c263d557fd2ea6c3b8a0e669.zip | |
Text rendering. Factor out style handling into nr-style.h
(bzr r9508.1.5)
Diffstat (limited to 'src/display/nr-arena-glyphs.cpp')
| -rw-r--r-- | src/display/nr-arena-glyphs.cpp | 357 |
1 files changed, 73 insertions, 284 deletions
diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index d229157ed..8e1b659c7 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -24,6 +24,7 @@ #include "nr-arena-glyphs.h" #include <cairo.h> #include "inkscape-cairo.h" +#include "helper/geom.h" #ifdef test_glyph_liv #include "../display/canvas-bpath.h" @@ -86,13 +87,9 @@ nr_arena_glyphs_class_init(NRArenaGlyphsClass *klass) static void nr_arena_glyphs_init(NRArenaGlyphs *glyphs) { - glyphs->style = NULL; glyphs->g_transform.setIdentity(); glyphs->font = NULL; glyphs->glyph = 0; - - glyphs->rfont = NULL; - glyphs->sfont = NULL; glyphs->x = glyphs->y = 0.0; } @@ -101,120 +98,58 @@ nr_arena_glyphs_finalize(NRObject *object) { NRArenaGlyphs *glyphs = static_cast<NRArenaGlyphs *>(object); - if (glyphs->rfont) { - glyphs->rfont->Unref(); - glyphs->rfont=NULL; - } - if (glyphs->sfont) { - glyphs->sfont->Unref(); - glyphs->sfont=NULL; - } - if (glyphs->font) { glyphs->font->Unref(); glyphs->font=NULL; } - if (glyphs->style) { - sp_style_unref(glyphs->style); - glyphs->style = NULL; - } - ((NRObjectClass *) glyphs_parent_class)->finalize(object); } static guint nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*state*/, guint /*reset*/) { - NRArenaGlyphs *glyphs; - raster_font *rfont; + NRArenaGlyphs *glyphs = NR_ARENA_GLYPHS(item); + NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item->parent); - glyphs = NR_ARENA_GLYPHS(item); - - if (!glyphs->font || !glyphs->style) + if (!glyphs->font || !ggroup->style) return NR_ARENA_ITEM_STATE_ALL; - if ((glyphs->style->fill.isNone()) && (glyphs->style->stroke.isNone())) + if (ggroup->nrstyle.fill.type == NRStyle::PAINT_NONE && ggroup->nrstyle.stroke.type == NRStyle::PAINT_NONE) return NR_ARENA_ITEM_STATE_ALL; - NRRect bbox; - bbox.x0 = bbox.y0 = NR_HUGE; - bbox.x1 = bbox.y1 = -NR_HUGE; - - float const scale = gc->transform.descrim(); - - if (!glyphs->style->fill.isNone()) { - Geom::Matrix t; - t = glyphs->g_transform * gc->transform; - glyphs->x = t[4]; - glyphs->y = t[5]; - t[4]=0; - t[5]=0; - rfont = glyphs->font->RasterFont(t, 0); - if (glyphs->rfont) glyphs->rfont->Unref(); - glyphs->rfont = rfont; - - if (glyphs->style->stroke.isNone() || fabs(glyphs->style->stroke_width.computed * scale) <= 0.01) { // Optimization: do fill bbox only if there's no stroke - NRRect narea; - if ( glyphs->rfont ) glyphs->rfont->BBox(glyphs->glyph, &narea); - bbox.x0 = narea.x0 + glyphs->x; - bbox.y0 = narea.y0 + glyphs->y; - bbox.x1 = narea.x1 + glyphs->x; - bbox.y1 = narea.y1 + glyphs->y; + Geom::OptRect b; + Geom::Matrix t = glyphs->g_transform * gc->transform; + glyphs->x = t[4]; + glyphs->y = t[5]; + + b = bounds_exact_transformed(*glyphs->font->PathVector(glyphs->glyph), t); + if (b && ggroup->nrstyle.stroke.type != NRStyle::PAINT_NONE) { + float width, scale; + scale = gc->transform.descrim(); + width = MAX(0.125, ggroup->nrstyle.stroke_width * scale); + if ( fabs(ggroup->nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true + b->expandBy(width); } - } - - if (!glyphs->style->stroke.isNone()) { - /* Build state data */ - Geom::Matrix t; - t = glyphs->g_transform * gc->transform; - glyphs->x = t[4]; - glyphs->y = t[5]; - t[4]=0; - t[5]=0; - - if ( fabs(glyphs->style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord - font_style nstyl; - nstyl.transform = t; - nstyl.stroke_width=MAX(0.125, glyphs->style->stroke_width.computed * scale); - if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_BUTT ) nstyl.stroke_cap=butt_straight; - if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_ROUND ) nstyl.stroke_cap=butt_round; - if ( glyphs->style->stroke_linecap.computed == SP_STROKE_LINECAP_SQUARE ) nstyl.stroke_cap=butt_square; - if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_MITER ) nstyl.stroke_join=join_pointy; - if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_ROUND ) nstyl.stroke_join=join_round; - if ( glyphs->style->stroke_linejoin.computed == SP_STROKE_LINEJOIN_BEVEL ) nstyl.stroke_join=join_straight; - nstyl.stroke_miter_limit = glyphs->style->stroke_miterlimit.value; - nstyl.nbDash=0; - nstyl.dash_offset = 0; - nstyl.dashes=NULL; - if ( glyphs->style->stroke_dash.n_dash > 0 ) { - nstyl.dash_offset = glyphs->style->stroke_dash.offset * scale; - nstyl.nbDash=glyphs->style->stroke_dash.n_dash; - nstyl.dashes=(double*)malloc(nstyl.nbDash*sizeof(double)); - for (int i = 0; i < nstyl.nbDash; i++) nstyl.dashes[i]= glyphs->style->stroke_dash.dash[i] * scale; - } - rfont = glyphs->font->RasterFont( nstyl); - if ( nstyl.dashes ) free(nstyl.dashes); - if (glyphs->sfont) glyphs->sfont->Unref(); - glyphs->sfont = rfont; - - NRRect narea; - if ( glyphs->sfont ) glyphs->sfont->BBox(glyphs->glyph, &narea); - narea.x0-=nstyl.stroke_width; - narea.y0-=nstyl.stroke_width; - narea.x1+=nstyl.stroke_width; - narea.y1+=nstyl.stroke_width; - bbox.x0 = narea.x0 + glyphs->x; - bbox.y0 = narea.y0 + glyphs->y; - bbox.x1 = narea.x1 + glyphs->x; - bbox.y1 = narea.y1 + glyphs->y; + // those pesky miters, now + float miterMax = width * ggroup->nrstyle.miter_limit; + if ( miterMax > 0.01 ) { + // grunt mode. we should compute the various miters instead + // (one for each point on the curve) + b->expandBy(miterMax); } } - if (nr_rect_d_test_empty(bbox)) return NR_ARENA_ITEM_STATE_ALL; - item->bbox.x0 = static_cast<NR::ICoord>(floor(bbox.x0)); - item->bbox.y0 = static_cast<NR::ICoord>(floor(bbox.y0)); - item->bbox.x1 = static_cast<NR::ICoord>(ceil (bbox.x1)); - item->bbox.y1 = static_cast<NR::ICoord>(ceil (bbox.y1)); + if (b) { + item->bbox.x0 = static_cast<NR::ICoord>(floor(b->left())); + item->bbox.y0 = static_cast<NR::ICoord>(floor(b->top())); + item->bbox.x1 = static_cast<NR::ICoord>(ceil (b->right())); + item->bbox.y1 = static_cast<NR::ICoord>(ceil (b->bottom())); + } else { + item->bbox.x0 = 0; + item->bbox.y0 = 0; + item->bbox.x1 = -1; + item->bbox.y1 = -1; + } return NR_ARENA_ITEM_STATE_ALL; } @@ -226,7 +161,7 @@ nr_arena_glyphs_clip(cairo_t *ct, NRArenaItem *item, NRRectL */*area*/) glyphs = NR_ARENA_GLYPHS(item); - if (!glyphs->font ) return item->state; + if (!glyphs->font) return item->state; /* TODO : render to greyscale pixblock provided for clipping */ @@ -241,7 +176,6 @@ nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned i glyphs = NR_ARENA_GLYPHS(item); if (!glyphs->font ) return NULL; - if (!glyphs->style) return NULL; double const x = p[Geom::X]; double const y = p[Geom::Y]; @@ -273,46 +207,6 @@ nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve */*curve*/, unsigned int nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE); } -void -nr_arena_glyphs_set_style(NRArenaGlyphs *glyphs, SPStyle *style) -{ - nr_return_if_fail(glyphs != NULL); - nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs)); - - if (style) sp_style_ref(style); - if (glyphs->style) sp_style_unref(glyphs->style); - glyphs->style = style; - - nr_arena_item_request_update(NR_ARENA_ITEM(glyphs), NR_ARENA_ITEM_STATE_ALL, FALSE); -} - -static guint -nr_arena_glyphs_fill_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m) -{ - /* fixme: area == m->area, so merge these */ - - NRArenaItem *item = NR_ARENA_ITEM(glyphs); - - if (glyphs->rfont && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { - raster_glyph *g = glyphs->rfont->GetGlyph(glyphs->glyph); - if ( g ) g->Blit(Geom::Point(glyphs->x, glyphs->y), *m); - } - - return item->state; -} - -static guint -nr_arena_glyphs_stroke_mask(NRArenaGlyphs *glyphs, NRRectL *area, NRPixBlock *m) -{ - NRArenaItem *item = NR_ARENA_ITEM(glyphs); - if (glyphs->sfont && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { - raster_glyph *g=glyphs->sfont->GetGlyph(glyphs->glyph); - if ( g ) g->Blit(Geom::Point(glyphs->x, glyphs->y),*m); - } - - return item->state; -} - static void nr_arena_glyphs_group_class_init(NRArenaGlyphsGroupClass *klass); static void nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group); static void nr_arena_glyphs_group_finalize(NRObject *object); @@ -364,10 +258,7 @@ nr_arena_glyphs_group_init(NRArenaGlyphsGroup *group) { group->style = NULL; group->paintbox.x0 = group->paintbox.y0 = 0.0F; - group->paintbox.x1 = group->paintbox.y1 = 1.0F; - - group->fill_painter = NULL; - group->stroke_painter = NULL; + group->paintbox.x1 = group->paintbox.y1 = -1.0F; } static void @@ -375,16 +266,6 @@ nr_arena_glyphs_group_finalize(NRObject *object) { NRArenaGlyphsGroup *group=static_cast<NRArenaGlyphsGroup *>(object); - if (group->fill_painter) { - sp_painter_free(group->fill_painter); - group->fill_painter = NULL; - } - - if (group->stroke_painter) { - sp_painter_free(group->stroke_painter); - group->stroke_painter = NULL; - } - if (group->style) { sp_style_unref(group->style); group->style = NULL; @@ -398,34 +279,7 @@ nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint s { NRArenaGlyphsGroup *group = NR_ARENA_GLYPHS_GROUP(item); - if (group->fill_painter) { - sp_painter_free(group->fill_painter); - group->fill_painter = NULL; - } - - if (group->stroke_painter) { - sp_painter_free(group->stroke_painter); - group->stroke_painter = NULL; - } - - item->render_opacity = TRUE; - if (group->style->fill.isPaintserver()) { - group->fill_painter = sp_paint_server_painter_new(SP_STYLE_FILL_SERVER(group->style), - gc->transform, gc->parent->transform, - &group->paintbox); - item->render_opacity = FALSE; - } - - if (group->style->stroke.isPaintserver()) { - group->stroke_painter = sp_paint_server_painter_new(SP_STYLE_STROKE_SERVER(group->style), - gc->transform, gc->parent->transform, - &group->paintbox); - item->render_opacity = FALSE; - } - - if ( item->render_opacity == TRUE && !group->style->stroke.isNone() && !group->style->fill.isNone() ) { - item->render_opacity=FALSE; - } + group->nrstyle.update(); if (((NRArenaItemClass *) group_parent_class)->update) return ((NRArenaItemClass *) group_parent_class)->update(item, area, gc, state, reset); @@ -441,16 +295,11 @@ nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPi NRArenaGroup *group = NR_ARENA_GROUP(item); NRArenaGlyphsGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - SPStyle const *style = ggroup->style; - guint ret = item->state; - bool print_colors_preview = (item->arena->rendermode == Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW); + if (!ct) return item->state; if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - if (!ct) - return item->state; - guint32 rgba = item->arena->outlinecolor; // FIXME: we use RGBA buffers but cairo writes BGRA (on i386), so we must cheat // by setting color channels in the "wrong" order @@ -469,112 +318,59 @@ nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPi pb->empty = FALSE; } - return ret; + return item->state; } + // NOTE: this is very similar to nr-arena-shape.cpp; the only difference is path feeding + bool needs_opacity = ((1.0 - ggroup->nrstyle.opacity) >= 0.01); + bool has_stroke, has_fill; + cairo_save(ct); + cairo_translate(ct, -area->x0, -area->y0); + ink_cairo_transform(ct, ggroup->ctm); - /* Fill */ - if (!style->fill.isNone() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - NRPixBlock m; - nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE); + has_fill = ggroup->nrstyle.prepareFill(ct, &ggroup->paintbox); + has_stroke = ggroup->nrstyle.prepareStroke(ct, &ggroup->paintbox); - // if memory allocation failed, abort - if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) { - nr_pixblock_release (&m); - return (item->state); + if (has_fill || has_stroke) { + if (needs_opacity) { + cairo_push_group(ct); } - m.visible_area = pb->visible_area; + for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { + NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); + Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - /* Render children fill mask */ - for (child = group->children; child != NULL; child = child->next) { - ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, &m); - if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) { - nr_pixblock_release(&m); - return ret; - } + cairo_save(ct); + ink_cairo_transform(ct, g->g_transform); + feed_pathvector_to_cairo(ct, pathv); + cairo_restore(ct); } - /* Composite into buffer */ - if (style->fill.isPaintserver()) { - if (ggroup->fill_painter) { - nr_arena_render_paintserver_fill(pb, area, ggroup->fill_painter, SP_SCALE24_TO_FLOAT(style->fill_opacity.value), &m); - } - } else if (style->fill.isColor() || item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - guint32 rgba; - if (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE) { - // In outline mode, render fill only, using outlinecolor - rgba = item->arena->outlinecolor; - } else if ( item->render_opacity ) { - rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) * - SP_SCALE24_TO_FLOAT(style->opacity.value) ); - } else { - rgba = style->fill.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->fill_opacity.value) ); - } - - if (print_colors_preview) - nr_arena_separate_color_plates(&rgba); - - nr_blit_pixblock_mask_rgba32(pb, &m, rgba); - pb->empty = FALSE; + if (has_fill) { + ggroup->nrstyle.applyFill(ct); + cairo_fill_preserve(ct); } - - nr_pixblock_release(&m); - } - - /* Stroke */ - if (!style->stroke.isNone() && !(item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE)) { - NRPixBlock m; - guint32 rgba; - nr_pixblock_setup_fast(&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE); - - // if memory allocation failed, abort - if (m.size != NR_PIXBLOCK_SIZE_TINY && m.data.px == NULL) { - nr_pixblock_release (&m); - return (item->state); + if (has_stroke) { + ggroup->nrstyle.applyStroke(ct); + cairo_stroke_preserve(ct); } + cairo_new_path(ct); // clear path - m.visible_area = pb->visible_area; - /* Render children stroke mask */ - for (child = group->children; child != NULL; child = child->next) { - ret = nr_arena_glyphs_stroke_mask(NR_ARENA_GLYPHS(child), area, &m); - if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) { - nr_pixblock_release(&m); - return ret; - } - } - /* Composite into buffer */ - if (style->stroke.isPaintserver()) { - if (ggroup->stroke_painter) { - nr_arena_render_paintserver_fill(pb, area, ggroup->stroke_painter, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value), &m); - } - } else if (style->stroke.isColor()) { - if ( item->render_opacity ) { - rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) * - SP_SCALE24_TO_FLOAT(style->opacity.value) ); - } else { - rgba = style->stroke.value.color.toRGBA32( SP_SCALE24_TO_FLOAT(style->stroke_opacity.value) ); - } - - if (print_colors_preview) - nr_arena_separate_color_plates(&rgba); - - nr_blit_pixblock_mask_rgba32(pb, &m, rgba); - pb->empty = FALSE; - } else { - // nothing + if (needs_opacity) { + cairo_pop_group_to_source(ct); + cairo_paint_with_alpha(ct, ggroup->nrstyle.opacity); } - nr_pixblock_release(&m); - } + } // has fill or stroke pattern + cairo_restore(ct); - return ret; + return item->state; } static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL *area) { - NRArenaGroup *group = NR_ARENA_GROUP(item); + //NRArenaGroup *group = NR_ARENA_GROUP(item); guint ret = item->state; @@ -630,7 +426,6 @@ nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, nr_arena_item_append_child(NR_ARENA_ITEM(group), new_arena); nr_arena_item_unref(new_arena); nr_arena_glyphs_set_path(NR_ARENA_GLYPHS(new_arena), NULL, FALSE, font, glyph, &transform); - nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(new_arena), sg->style); } } @@ -640,16 +435,11 @@ nr_arena_glyphs_group_set_style(NRArenaGlyphsGroup *sg, SPStyle *style) nr_return_if_fail(sg != NULL); nr_return_if_fail(NR_IS_ARENA_GLYPHS_GROUP(sg)); - NRArenaGroup *group = NR_ARENA_GROUP(sg); - if (style) sp_style_ref(style); if (sg->style) sp_style_unref(sg->style); sg->style = style; - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - nr_return_if_fail(NR_IS_ARENA_GLYPHS(child)); - nr_arena_glyphs_set_style(NR_ARENA_GLYPHS(child), sg->style); - } + sg->nrstyle.set(style); nr_arena_item_request_update(NR_ARENA_ITEM(sg), NR_ARENA_ITEM_STATE_ALL, FALSE); } @@ -667,9 +457,8 @@ nr_arena_glyphs_group_set_paintbox(NRArenaGlyphsGroup *gg, NRRect const *pbox) gg->paintbox.x1 = pbox->x1; gg->paintbox.y1 = pbox->y1; } else { - /* fixme: We kill warning, although not sure what to do here (Lauris) */ gg->paintbox.x0 = gg->paintbox.y0 = 0.0F; - gg->paintbox.x1 = gg->paintbox.y1 = 256.0F; + gg->paintbox.x1 = gg->paintbox.y1 = -1.0F; } nr_arena_item_request_update(NR_ARENA_ITEM(gg), NR_ARENA_ITEM_STATE_ALL, FALSE); |
