From 4dd33aa4d5c57706c7f64f63391174954160a308 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 6 Aug 2011 14:18:32 +0200 Subject: Rewrite NRArenaItem hierarchy into C++ (bzr r10347.1.21) --- src/display/drawing-text.cpp | 275 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 src/display/drawing-text.cpp (limited to 'src/display/drawing-text.cpp') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp new file mode 100644 index 000000000..784888bd7 --- /dev/null +++ b/src/display/drawing-text.cpp @@ -0,0 +1,275 @@ +/** + * @file + * @brief Group belonging to an SVG drawing element + *//* + * Authors: + * Krzysztof KosiƄski + * + * Copyright (C) 2011 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display/cairo-utils.h" +#include "display/canvas-bpath.h" // for SPWindRule (WTF!) +#include "display/drawing-context.h" +#include "display/drawing-surface.h" +#include "display/drawing-text.h" +#include "display/nr-arena.h" +#include "helper/geom.h" +#include "libnrtype/font-instance.h" +#include "style.h" + +namespace Inkscape { + +DrawingGlyphs::DrawingGlyphs(Drawing *drawing) + : DrawingItem(drawing) + , _glyph_transform(NULL) + , _font(NULL) + , _glyph(0) +{} + +DrawingGlyphs::~DrawingGlyphs() +{ + if (_font) { + _font->Unref(); + _font = NULL; + } + delete _glyph_transform; +} + +void +DrawingGlyphs::setGlyph(font_instance *font, int glyph, Geom::Affine const &trans) +{ + _markForRendering(); + + if (trans.isIdentity()) { + delete _glyph_transform; // delete NULL; is safe + _glyph_transform = NULL; + } else { + _glyph_transform = new Geom::Affine(trans); + } + + if (font) font->Ref(); + if (_font) _font->Unref(); + _font = font; + _glyph = glyph; + + _markForUpdate(STATE_ALL, false); +} + +unsigned +DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + DrawingText *ggroup = dynamic_cast(_parent); + if (!ggroup) throw InvalidItemException(); + + if (!_font || !ggroup->_style) return STATE_ALL; + if (ggroup->_nrstyle.fill.type == NRStyle::PAINT_NONE && + ggroup->_nrstyle.stroke.type == NRStyle::PAINT_NONE) + { + return STATE_ALL; + } + + Geom::OptRect b; + Geom::Affine t = _glyph_transform ? *_glyph_transform * ctx.ctm : ctx.ctm; + _x = t[4]; + _y = t[5]; + + b = bounds_exact_transformed(*_font->PathVector(_glyph), t); + if (b && ggroup->_nrstyle.stroke.type != NRStyle::PAINT_NONE) { + float width, scale; + scale = ctx.ctm.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); + } + // 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 (b) { + _bbox = b->roundOutwards(); + } else { + _bbox = Geom::OptIntRect(); + } + + return STATE_ALL; +} + +DrawingItem * +DrawingGlyphs::_pickItem(Geom::Point const &p, double delta) +{ + if (!_font || !_bbox) return NULL; + + // With text we take a simple approach: pick if the point is in a characher bbox + Geom::Rect expanded(*_bbox); + expanded.expandBy(delta); + if (expanded.contains(p)) return this; + return NULL; +} + + + +DrawingText::DrawingText(Drawing *drawing) + : DrawingGroup(drawing) +{} + +DrawingText::~DrawingText() +{} + +void +DrawingText::clear() +{ + _markForRendering(); + _children.clear_and_dispose(DeleteDisposer()); +} + +void +DrawingText::addComponent(font_instance *font, int glyph, Geom::Affine const &trans) +{ + if (!font || !font->PathVector(glyph)) return; + + _markForRendering(); + DrawingGlyphs *ng = new DrawingGlyphs(_drawing); + ng->setGlyph(font, glyph, trans); + appendChild(ng); +} + +void +DrawingText::setStyle(SPStyle *style) +{ + _nrstyle.set(style); + DrawingGroup::setStyle(style); +} + +void +DrawingText::setPaintBox(Geom::OptRect const &box) +{ + _paintbox = box; + _markForUpdate(STATE_ALL, false); +} + +unsigned +DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset) +{ + _nrstyle.update(); + return DrawingGroup::_updateItem(area, ctx, flags, reset); +} + +void +DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +{ + if (_drawing->rendermode == RENDERMODE_OUTLINE) { + DrawingContext::Save save(ct); + guint32 rgba = _drawing->outlinecolor; + ct.setSource(rgba); + ct.setTolerance(1.25); // low quality, but good enough for outline mode + ct.newPath(); + ct.transform(_ctm); + + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(ct); + if (g->_glyph_transform) { + ct.transform(*g->_glyph_transform); + } + ct.path(*g->_font->PathVector(g->_glyph)); + ct.fill(); + } + return; + } + + // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding + bool has_stroke, has_fill; + + Inkscape::DrawingContext::Save save(ct); + ct.transform(_ctm); + + has_fill = _nrstyle.prepareFill(ct, _paintbox); + has_stroke = _nrstyle.prepareStroke(ct, _paintbox); + + if (has_fill || has_stroke) { + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(ct); + if (g->_glyph_transform) { + ct.transform(*g->_glyph_transform); + } + ct.path(*g->_font->PathVector(g->_glyph)); + } + + if (has_fill) { + _nrstyle.applyFill(ct); + ct.fillPreserve(); + } + if (has_stroke) { + _nrstyle.applyStroke(ct); + ct.strokePreserve(); + } + ct.newPath(); // clear path + } +} + +void +DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) +{ + Inkscape::DrawingContext::Save save(ct); + + // handle clip-rule + if (_style) { + if (_style->clip_rule.computed == SP_WIND_RULE_EVENODD) { + ct.setFillRule(CAIRO_FILL_RULE_EVEN_ODD); + } else { + ct.setFillRule(CAIRO_FILL_RULE_WINDING); + } + } + ct.transform(_ctm); + + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(ct); + if (g->_glyph_transform) { + ct.transform(*g->_glyph_transform); + } + ct.path(*g->_font->PathVector(g->_glyph)); + } + ct.fill(); +} + +DrawingItem * +DrawingText::_pickItem(Geom::Point const &p, double delta) +{ + DrawingItem *picked = DrawingGroup::_pickItem(p, delta); + if (picked) return this; + return NULL; +} + +bool +DrawingText::_canClip() +{ + return true; +} + +} // end namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3 From 42c8636a2c5814746c41f1452ffa7df99cf21367 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 6 Aug 2011 15:38:28 +0200 Subject: Document things figured out during the rewriting (bzr r10347.1.22) --- src/display/drawing-text.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/display/drawing-text.cpp') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 784888bd7..e03a91b39 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -102,7 +102,7 @@ DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, } DrawingItem * -DrawingGlyphs::_pickItem(Geom::Point const &p, double delta) +DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) { if (!_font || !_bbox) return NULL; @@ -248,7 +248,7 @@ DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingText::_pickItem(Geom::Point const &p, double delta) +DrawingText::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) { DrawingItem *picked = DrawingGroup::_pickItem(p, delta); if (picked) return this; -- cgit v1.2.3 From 456dddb2670686427c60497702e86648635ce42e Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 6 Aug 2011 15:45:04 +0200 Subject: Fix compilation (oops). (bzr r10347.1.24) --- src/display/drawing-text.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/display/drawing-text.cpp') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index e03a91b39..5fc732779 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -248,9 +248,9 @@ DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingText::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) +DrawingText::_pickItem(Geom::Point const &p, double delta, bool sticky) { - DrawingItem *picked = DrawingGroup::_pickItem(p, delta); + DrawingItem *picked = DrawingGroup::_pickItem(p, delta, sticky); if (picked) return this; return NULL; } -- cgit v1.2.3 From 75976ea07dba9b97186667524d0a76603de416af Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 7 Aug 2011 12:53:12 +0200 Subject: Rewrite NRArena -> Inkscape::Drawing. Call render and update methods on the Drawing rather than on the root DrawingItem. (bzr r10347.1.25) --- src/display/drawing-text.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/display/drawing-text.cpp') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 5fc732779..2f0881c49 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -11,17 +11,17 @@ #include "display/cairo-utils.h" #include "display/canvas-bpath.h" // for SPWindRule (WTF!) +#include "display/drawing.h" #include "display/drawing-context.h" #include "display/drawing-surface.h" #include "display/drawing-text.h" -#include "display/nr-arena.h" #include "helper/geom.h" #include "libnrtype/font-instance.h" #include "style.h" namespace Inkscape { -DrawingGlyphs::DrawingGlyphs(Drawing *drawing) +DrawingGlyphs::DrawingGlyphs(Drawing &drawing) : DrawingItem(drawing) , _glyph_transform(NULL) , _font(NULL) @@ -115,7 +115,7 @@ DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) -DrawingText::DrawingText(Drawing *drawing) +DrawingText::DrawingText(Drawing &drawing) : DrawingGroup(drawing) {} @@ -164,9 +164,9 @@ DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, un void DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) { - if (_drawing->rendermode == RENDERMODE_OUTLINE) { + if (_drawing.outline()) { DrawingContext::Save save(ct); - guint32 rgba = _drawing->outlinecolor; + guint32 rgba = _drawing.outlinecolor; ct.setSource(rgba); ct.setTolerance(1.25); // low quality, but good enough for outline mode ct.newPath(); -- cgit v1.2.3 From caa510445fc091c63e1ca0ff8f44f2e81ae0638d Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 13 Aug 2011 20:30:30 +0200 Subject: More generic handling of child type in DrawingItem. Fix clip object selection bug (LP #365458). Fixed bugs: - https://launchpad.net/bugs/365458 (bzr r10347.1.31) --- src/display/drawing-text.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/display/drawing-text.cpp') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 2f0881c49..21588cc4f 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -102,7 +102,7 @@ DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, } DrawingItem * -DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, bool /*sticky*/) +DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, unsigned /*flags*/) { if (!_font || !_bbox) return NULL; @@ -248,9 +248,9 @@ DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) } DrawingItem * -DrawingText::_pickItem(Geom::Point const &p, double delta, bool sticky) +DrawingText::_pickItem(Geom::Point const &p, double delta, unsigned flags) { - DrawingItem *picked = DrawingGroup::_pickItem(p, delta, sticky); + DrawingItem *picked = DrawingGroup::_pickItem(p, delta, flags); if (picked) return this; return NULL; } -- cgit v1.2.3 From 66bab1f2b80ff441643fd5fdeb5bade70fb5aa8c Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 16 Aug 2011 03:40:10 +0200 Subject: Add sanity checks against singular transforms in the drawing tree. Fixes LP #825767. Fixed bugs: - https://launchpad.net/bugs/825767 (bzr r10347.1.33) --- src/display/drawing-text.cpp | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) (limited to 'src/display/drawing-text.cpp') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 21588cc4f..5e6396df1 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -23,7 +23,6 @@ namespace Inkscape { DrawingGlyphs::DrawingGlyphs(Drawing &drawing) : DrawingItem(drawing) - , _glyph_transform(NULL) , _font(NULL) , _glyph(0) {} @@ -34,7 +33,6 @@ DrawingGlyphs::~DrawingGlyphs() _font->Unref(); _font = NULL; } - delete _glyph_transform; } void @@ -42,12 +40,7 @@ DrawingGlyphs::setGlyph(font_instance *font, int glyph, Geom::Affine const &tran { _markForRendering(); - if (trans.isIdentity()) { - delete _glyph_transform; // delete NULL; is safe - _glyph_transform = NULL; - } else { - _glyph_transform = new Geom::Affine(trans); - } + setTransform(trans); if (font) font->Ref(); if (_font) _font->Unref(); @@ -70,12 +63,7 @@ DrawingGlyphs::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, return STATE_ALL; } - Geom::OptRect b; - Geom::Affine t = _glyph_transform ? *_glyph_transform * ctx.ctm : ctx.ctm; - _x = t[4]; - _y = t[5]; - - b = bounds_exact_transformed(*_font->PathVector(_glyph), t); + Geom::OptRect b = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); if (b && ggroup->_nrstyle.stroke.type != NRStyle::PAINT_NONE) { float width, scale; scale = ctx.ctm.descrim(); @@ -165,21 +153,19 @@ void DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) { if (_drawing.outline()) { - DrawingContext::Save save(ct); guint32 rgba = _drawing.outlinecolor; + Inkscape::DrawingContext::Save save(ct); ct.setSource(rgba); ct.setTolerance(1.25); // low quality, but good enough for outline mode - ct.newPath(); - ct.transform(_ctm); for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { DrawingGlyphs *g = dynamic_cast(&*i); if (!g) throw InvalidItemException(); Inkscape::DrawingContext::Save save(ct); - if (g->_glyph_transform) { - ct.transform(*g->_glyph_transform); - } + // skip glpyhs with singular transforms + if (g->_ctm.isSingular()) continue; + ct.transform(g->_ctm); ct.path(*g->_font->PathVector(g->_glyph)); ct.fill(); } @@ -189,9 +175,6 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding bool has_stroke, has_fill; - Inkscape::DrawingContext::Save save(ct); - ct.transform(_ctm); - has_fill = _nrstyle.prepareFill(ct, _paintbox); has_stroke = _nrstyle.prepareStroke(ct, _paintbox); @@ -201,9 +184,8 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned if (!g) throw InvalidItemException(); Inkscape::DrawingContext::Save save(ct); - if (g->_glyph_transform) { - ct.transform(*g->_glyph_transform); - } + if (g->_ctm.isSingular()) continue; + ct.transform(g->_ctm); ct.path(*g->_font->PathVector(g->_glyph)); } @@ -232,16 +214,13 @@ DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &area) ct.setFillRule(CAIRO_FILL_RULE_WINDING); } } - ct.transform(_ctm); for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { DrawingGlyphs *g = dynamic_cast(&*i); if (!g) throw InvalidItemException(); Inkscape::DrawingContext::Save save(ct); - if (g->_glyph_transform) { - ct.transform(*g->_glyph_transform); - } + ct.transform(g->_ctm); ct.path(*g->_font->PathVector(g->_glyph)); } ct.fill(); -- cgit v1.2.3 From 0fc028f7050c91bfdb1a50ba8cb6462b2bf03d57 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 21 Aug 2011 17:33:09 +0200 Subject: Filter background rendering now matches the SVG specification. (bzr r10347.1.37) --- src/display/drawing-text.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/display/drawing-text.cpp') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 5e6396df1..1134771bc 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -149,8 +149,8 @@ DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, un return DrawingGroup::_updateItem(area, ctx, flags, reset); } -void -DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags) +unsigned +DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at) { if (_drawing.outline()) { guint32 rgba = _drawing.outlinecolor; @@ -169,7 +169,7 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned ct.path(*g->_font->PathVector(g->_glyph)); ct.fill(); } - return; + return RENDER_OK; } // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding @@ -199,6 +199,7 @@ DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigned } ct.newPath(); // clear path } + return RENDER_OK; } void -- cgit v1.2.3