From d19db89e2e22d4e09c539bd42823d511aebb669f Mon Sep 17 00:00:00 2001 From: David Mathog <> Date: Wed, 19 Jun 2013 19:20:33 +0200 Subject: changes_2013_05_22a.patch: 1. Resolves issue of bug #988601 message 170 (Support of 'Unset' styles in EMF export). 2. Implements CSS 3 (and CSS 2) text-decoration support. Note that it does not yet provide any method of adding these features - at present it just shows whatever is in the SVG. This new code is also used to display EMF/WMF strike-through and underline text decorations when these files are read in. Those decorations may also be written out to EMF/WMF. Other text decoration features, like overline, or dotted lines, are dropped. For SVG text-decoration -line, -style, -color are all implemented. CSS3 provides two ways to represent the same state, this code uses the compound text-decoration method rather than the 3 fields method. Also it leaves out keywords that are not needed and would break backwards compatibility. For instance: text-decoration: underline solid is valid, but would break CSS2. Solid is the default, so that sort of case is written as: text-decoration: underline If the state is CSS3 specific all of the needed fields are of course include, like text-decoration: underline wavy red 3. It incorporates the fix for bug 1181326 (Text edit mishandles span of just colored spaces) 4. It incorporates further changes to text editing so that style can be changed on spans consisting of only spaces when text decorations are present in the span. 5. It incorporates code to disable text decorations when text so marked is mapped onto a path. 6. Fixed more bugs in Hebrew language support than I can remember. Hebrew language export/import to EMF now works quite well. (See the examples in libTERE v 0.7.) WMF does not support unicode and for all intents and purposes Inkscape has no way to read or write Hebrew to it. Some of more important things that now work that didn't (or didn't always): Hebrew diacritical marks, R/L/center justification, and bidirectional text. The Hebrew fonts "Ezra SIL" and "EZRA SIL SR" should be installed before viewing the libTERE examples, otherwise font substitutions will cause some text shifts. 7. Implemented font failover in Text Reassemble, which makes the process more robust. (Again, see the examples in libTERE. ) (bzr r11668.1.71) --- src/display/drawing-context.h | 15 +++ src/display/drawing-text.cpp | 304 +++++++++++++++++++++++++++++++++++++++--- src/display/drawing-text.h | 15 ++- src/display/nr-style.cpp | 58 ++++++++ src/display/nr-style.h | 37 +++++ 5 files changed, 409 insertions(+), 20 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h index b8c4667c2..d4f0dbfc3 100644 --- a/src/display/drawing-context.h +++ b/src/display/drawing-context.h @@ -67,6 +67,21 @@ public: void rectangle(Geom::IntRect const &r) { cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height()); } + // Used in drawing-text.cpp to overwrite glyphs, which have the opposite path rotation as a regular rect + void revrectangle(Geom::Rect const &r) { + cairo_move_to ( _ct, r.left(), r.top() ); + cairo_rel_line_to (_ct, 0, r.height() ); + cairo_rel_line_to (_ct, r.width(), 0 ); + cairo_rel_line_to (_ct, 0, -r.height() ); + cairo_close_path ( _ct); + } + void revrectangle(Geom::IntRect const &r) { + cairo_move_to ( _ct, r.left(), r.top() ); + cairo_rel_line_to (_ct, 0, r.height() ); + cairo_rel_line_to (_ct, r.width(), 0 ); + cairo_rel_line_to (_ct, 0, -r.height() ); + cairo_close_path ( _ct); + } void newPath() { cairo_new_path(_ct); } void newSubpath() { cairo_new_sub_path(_ct); } void path(Geom::PathVector const &pv); diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 2a6505c67..234006983 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -18,9 +18,11 @@ #include "helper/geom.h" #include "libnrtype/font-instance.h" #include "style.h" +#include "2geom/pathvector.h" namespace Inkscape { + DrawingGlyphs::DrawingGlyphs(Drawing &drawing) : DrawingItem(drawing) , _font(NULL) @@ -61,12 +63,34 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext return STATE_ALL; } + _pick_bbox = Geom::IntRect(); _bbox = Geom::IntRect(); - Geom::OptRect b = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); + Geom::OptRect b; + +/* orignally it did the one line below, + but it did not handle ws characters at all, and it had problems with scaling for overline/underline. + Replaced with the section below, which seems to be much more stable. + + b = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); +*/ + /* Make a bounding box that is a little taller and lower (currently 10% extra) than the font's drawing box. Extra space is + to hold overline or underline, if present. All characters in a font use the same ascent and descent, + but different widths. This lets leading and trailing spaces have text decorations. If it is not done + the bounding box is limited to the box surrounding the drawn parts of visible glyphs only, and draws outside are ignored. + */ + + float scale = 1.0; + if(_transform){ scale /= _transform->descrim(); } + + Geom::Rect bigbox(Geom::Point(0.0, _asc*scale*1.1),Geom::Point(_width*scale, -_dsc*scale*1.1)); + b = bigbox * ctx.ctm; + if (b && (ggroup->_nrstyle.stroke.type != NRStyle::PAINT_NONE)) { float width, scale; + + // this expands the selection box for cases where the stroke is "thick" scale = ctx.ctm.descrim(); if (_transform) { scale /= _transform->descrim(); // FIXME temporary hack @@ -75,7 +99,8 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext if ( fabs(ggroup->_nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true b->expandBy(0.5 * width); } - // save bbox without miters for picking + + // save bbox without miters for picking _pick_bbox = b->roundOutwards(); float miterMax = width * ggroup->_nrstyle.miter_limit; @@ -89,7 +114,12 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext _bbox = b->roundOutwards(); _pick_bbox = *_bbox; } - +/* +std::cout << "DEBUG _bbox" +<< " { " << _bbox->min()[Geom::X] << " , " << _bbox->min()[Geom::Y] +<< " } , { " << _bbox->max()[Geom::X] << " , " << _bbox->max()[Geom::Y] +<< " }" << std::endl; +*/ return STATE_ALL; } @@ -106,7 +136,7 @@ DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, unsigned /*flags*/) return NULL; } - // With text we take a simple approach: pick if the point is in a characher bbox + // With text we take a simple approach: pick if the point is in a character bbox Geom::Rect expanded(_pick_bbox); expanded.expandBy(delta); if (expanded.contains(p)) return this; @@ -129,17 +159,28 @@ DrawingText::clear() _children.clear_and_dispose(DeleteDisposer()); } -void -DrawingText::addComponent(font_instance *font, int glyph, Geom::Affine const &trans) +bool +DrawingText::addComponent(font_instance *font, int glyph, Geom::Affine const &trans, + float width, float ascent, float descent, float phase_length) { +/* original, did not save a glyph for white space characters, causes problems for text-decoration if (!font || !font->PathVector(glyph)) { - return; + return(false); } +*/ + if (!font)return(false); _markForRendering(); DrawingGlyphs *ng = new DrawingGlyphs(_drawing); ng->setGlyph(font, glyph, trans); + if(font->PathVector(glyph)){ ng->_drawable = true; } + else { ng->_drawable = false; } + ng->_width = width; // only used when _drawable = false + ng->_asc = ascent; // of font, not of this one character + ng->_dsc = descent; // of font, not of this one character + ng->_pl = phase_length; // used for phase of dots, dashes, and wavy appendChild(ng); + return(true); } void @@ -156,9 +197,175 @@ DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, un return DrawingGroup::_updateItem(area, ctx, flags, reset); } +void DrawingText::decorateStyle(DrawingContext &ct, double vextent, double xphase, Geom::Point p1, Geom::Point p2) +{ + double wave[16]={ + 0.000000, 0.382499, 0.706825, 0.923651, 1.000000, 0.923651, 0.706825, 0.382499, + 0.000000, -0.382499, -0.706825, -0.923651, -1.000000, -0.923651, -0.706825, -0.382499, + }; + int dashes[16]={ + 8, 7, 6, 5, + 4, 3, 2, 1, + -8, -7, -6, -5 + -4, -3, -2, -1 + }; + int dots[16]={ + 4, 3, 2, 1, + -4, -3, -2, -1, + 4, 3, 2, 1, + -4, -3, -2, -1 + }; + Geom::Point p3,p4,ps,pf; + double step = vextent/32.0; + unsigned i = 15 & (unsigned) round(xphase/step); // xphase is >= 0.0 + + /* For most spans draw the last little bit right to p2 or even a little beyond. + This allows decoration continuity within the line, and does not step outside the clip box off the end + For the first/last section on the line though, stay well clear of the edge, or when the + text is dragged it may "spray" pixels. + if(_nrstyle.tspan_line_end){ pf = p2 - Geom::Point(2*step, 0.0); } + else { pf = p2; } + if(_nrstyle.tspan_line_start){ ps = p1 + Geom::Point(2*step, 0.0); + i = 15 & (i + 2); + } + else { ps = p1; } + */ + /* snap to nearest step in X */ +ps = Geom::Point(step * round(p1[Geom::X]/step),p1[Geom::Y]); +pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); + + if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_ISDOUBLE){ + ps -= Geom::Point(0, vextent/12.0); + pf -= Geom::Point(0, vextent/12.0); + ct.moveTo(ps); + ct.lineTo(pf); + ps += Geom::Point(0, vextent/6.0); + pf += Geom::Point(0, vextent/6.0); + ct.moveTo(ps); + ct.lineTo(pf); + } + /* The next three have a problem in that they are phase dependent. The bits of a line are not + necessarily passing through this routine in order, so we have to use the xphase information + to figure where in each of their cycles to start. Only accurate to 1 part in 16. + Huge possitive offset should keep the phase calculation from ever being negative. + */ + else if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_DOTTED){ + while(1){ + if(dots[i]>0){ + if(ps[Geom::X]> pf[Geom::X])break; + ct.moveTo(ps); + ps += Geom::Point(step * (double)dots[i], 0.0); + if(ps[Geom::X]>= pf[Geom::X]){ + ct.lineTo(pf); + break; + } + else { + ct.lineTo(ps); + } + ps += Geom::Point(step * 4.0, 0.0); + } + else { + ps += Geom::Point(step * -(double)dots[i], 0.0); + } + i = 0; // once in phase, it stays in phase + } + } + else if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_DASHED){ + while(1){ + if(dashes[i]>0){ + if(ps[Geom::X]> pf[Geom::X])break; + ct.moveTo(ps); + ps += Geom::Point(step * (double)dashes[i], 0.0); + if(ps[Geom::X]>= pf[Geom::X]){ + ct.lineTo(pf); + break; + } + else { + ct.lineTo(ps); + } + ps += Geom::Point(step * 8.0, 0.0); + } + else { + ps += Geom::Point(step * -(double)dashes[i], 0.0); + } + i = 0; // once in phase, it stays in phase + } + } + else if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_WAVY){ + double amp = vextent/10.0; + double x = ps[Geom::X]; + double y = ps[Geom::Y]; + ct.moveTo(Geom::Point(x, y + amp * wave[i])); + while(1){ + i = ((i + 1) & 15); + x += step; + ct.lineTo(Geom::Point(x, y + amp * wave[i])); + if(x >= pf[Geom::X])break; + } + } + else { // TEXT_DECORATION_STYLE_SOLID, also default in case it was not set for some reason + ct.moveTo(ps); + ct.lineTo(pf); +// ct.revrectangle(Geom::Rect(ps,pf)); + } +} + +/* returns scaled line thickness */ +double DrawingText::decorateItem(DrawingContext &ct, Geom::Affine aff, double phase_length) +{ + double tsp_width_adj, tsp_asc_adj, tsp_size_adj; + double final_underline_thickness, final_line_through_thickness; + double thickness; + + tsp_width_adj = _nrstyle.tspan_width / _nrstyle.font_size; + tsp_asc_adj = _nrstyle.ascender / _nrstyle.font_size; + tsp_size_adj = (_nrstyle.ascender + _nrstyle.descender) / _nrstyle.font_size; +#define VALTRUNC(A,B,C) (A < B ? B : ( A > C ? C : A )) + final_underline_thickness = VALTRUNC(_nrstyle.underline_thickness, tsp_size_adj/30.0, tsp_size_adj/10.0); + final_line_through_thickness = VALTRUNC(_nrstyle.line_through_thickness, tsp_size_adj/30.0, tsp_size_adj/10.0); + Inkscape::DrawingContext::Save save(ct); + + double scale = aff.descrim(); + double xphase = phase_length/ _nrstyle.font_size; // used to figure out phase of patterns + + ct.transform(aff); // must be leftmost affine in span + Geom::Point p1; + Geom::Point p2; + // All lines must be the same thickness, in combinations, line_through trumps underline + thickness = final_underline_thickness; + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_UNDERLINE){ + p1 = Geom::Point(0.0, -_nrstyle.underline_position); + p2 = Geom::Point(tsp_width_adj,-_nrstyle.underline_position); + decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + } + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_OVERLINE){ + p1 = Geom::Point(0.0, tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); + p2 = Geom::Point(tsp_width_adj,tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); + decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + } + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_LINETHROUGH){ + thickness = final_line_through_thickness; + p1 = Geom::Point(0.0, _nrstyle.line_through_position); + p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position); + decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + } + // Obviously this does not blink, but it does indicate which text has been set with that attribute + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_BLINK){ + thickness = final_line_through_thickness; + p1 = Geom::Point(0.0, _nrstyle.line_through_position - 2*final_line_through_thickness); + p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position - 2*final_line_through_thickness); + decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + p1 = Geom::Point(0.0, _nrstyle.line_through_position + 2*final_line_through_thickness); + p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position + 2*final_line_through_thickness); + decorateStyle(ct, tsp_size_adj, xphase, p1, p2); + } + thickness *= scale; + return(thickness); +} + unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*area*/, unsigned /*flags*/, DrawingItem * /*stop_at*/) { - if (_drawing.outline()) { + if (_drawing.outline()) { guint32 rgba = _drawing.outlinecolor; Inkscape::DrawingContext::Save save(ct); ct.setSource(rgba); @@ -169,34 +376,72 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are if (!g) throw InvalidItemException(); Inkscape::DrawingContext::Save save(ct); - // skip glpyhs with singular transforms + // skip glyphs with singular transforms if (g->_ctm.isSingular()) continue; ct.transform(g->_ctm); - ct.path(*g->_font->PathVector(g->_glyph)); - ct.fill(); + if(g->_drawable){ + ct.path(*g->_font->PathVector(g->_glyph)); + ct.fill(); + } } return RENDER_OK; } // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding - bool has_stroke, has_fill; - - has_fill = _nrstyle.prepareFill(ct, _item_bbox); + double leftmost = DBL_MAX; + double phase_length = 0.0; + bool firsty = true; + bool decorate = true; + double starty = 0.0; + bool has_stroke, has_fill; + Geom::Affine aff; + using Geom::X; + using Geom::Y; + + has_fill = _nrstyle.prepareFill( ct, _item_bbox); has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); if (has_fill || has_stroke) { + Geom::Affine rotinv; + bool invset=false; for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { DrawingGlyphs *g = dynamic_cast(&*i); if (!g) throw InvalidItemException(); + if(!invset){ + rotinv = g->_ctm.withoutTranslation().inverse(); + invset = true; + } Inkscape::DrawingContext::Save save(ct); if (g->_ctm.isSingular()) continue; ct.transform(g->_ctm); - ct.path(*g->_font->PathVector(g->_glyph)); + if(g->_drawable){ + ct.path(*g->_font->PathVector(g->_glyph)); + } + // get the leftmost affine transform (leftmost defined with respect to the x axis of the first transform). + // That way the decoration will work no matter what mix of L->R, R->L text is in the span. + if(_nrstyle.text_decoration_line != TEXT_DECORATION_LINE_CLEAR){ + Geom::Point pt =g->_ctm.translation() * rotinv; + if(pt[X] < leftmost){ + leftmost = pt[X]; + aff = g->_ctm; + phase_length = g->_pl; + } + /* If the text has been mapped onto a path, which causes y to vary, drop the text decorations. + To handle that properly would need a conformal map + */ + if(firsty){ + firsty = false; + starty = pt[Y]; + } + else { + if(fabs(pt[Y] - starty) > 1.0e-6)decorate=false; + } + } } Inkscape::DrawingContext::Save save(ct); - ct.transform(_ctm); +// ct.transform(_ctm); // Seems to work fine without this line, which was in the original. if (has_fill) { _nrstyle.applyFill(ct); ct.fillPreserve(); @@ -206,6 +451,29 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are ct.strokePreserve(); } ct.newPath(); // clear path + if(_nrstyle.text_decoration_line != TEXT_DECORATION_LINE_CLEAR && decorate){ + guint32 ergba; + if(_nrstyle.text_decoration_useColor){ // color different from the glyph + ergba = SP_RGBA32_F_COMPOSE( + _nrstyle.text_decoration_color.color.v.c[0], + _nrstyle.text_decoration_color.color.v.c[1], + _nrstyle.text_decoration_color.color.v.c[2], + 1.0); + } + else { // whatever the current fill color is + ergba = SP_RGBA32_F_COMPOSE( + _nrstyle.fill.color.v.c[0], + _nrstyle.fill.color.v.c[1], + _nrstyle.fill.color.v.c[2], + 1.0); + } + ct.setSource(ergba); + ct.setTolerance(0.5); + double thickness = decorateItem(ct, aff, phase_length); + ct.setLineWidth(thickness); + ct.strokePreserve(); + ct.newPath(); // clear path + } } return RENDER_OK; } @@ -231,7 +499,9 @@ void DrawingText::_clipItem(DrawingContext &ct, Geom::IntRect const &/*area*/) Inkscape::DrawingContext::Save save(ct); ct.transform(g->_ctm); - ct.path(*g->_font->PathVector(g->_glyph)); + if(g->_drawable){ + ct.path(*g->_font->PathVector(g->_glyph)); + } } ct.fill(); } diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index 79b1b097c..99b46bc8a 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -35,8 +35,13 @@ protected: virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); font_instance *_font; - int _glyph; - Geom::IntRect _pick_bbox; + int _glyph; + bool _drawable; + float _width; // These three are used to set up bounding box + float _asc; // + float _dsc; // + float _pl; // phase length + Geom::IntRect _pick_bbox; friend class DrawingText; }; @@ -49,9 +54,11 @@ public: ~DrawingText(); void clear(); - void addComponent(font_instance *font, int glyph, Geom::Affine const &trans); + bool addComponent(font_instance *font, int glyph, Geom::Affine const &trans, + float width, float ascent, float descent, float phase_length); void setStyle(SPStyle *style); + protected: virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset); @@ -61,6 +68,8 @@ protected: virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); + double decorateItem(DrawingContext &ct, Geom::Affine aff, double phase_length); + void decorateStyle(DrawingContext &ct, double vextent, double xphase, Geom::Point p1, Geom::Point p2); NRStyle _nrstyle; friend class DrawingGlyphs; diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index 26d70ad15..a18bc0523 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -54,6 +54,20 @@ NRStyle::NRStyle() , line_join(CAIRO_LINE_JOIN_MITER) , fill_pattern(NULL) , stroke_pattern(NULL) + , text_decoration_line(TEXT_DECORATION_LINE_CLEAR) + , text_decoration_style(TEXT_DECORATION_STYLE_CLEAR) + , phase_length(0.0) + , tspan_line_start(false) + , tspan_line_end(false) + , tspan_width(0) + , ascender(0) + , descender(0) + , line_gap(0) + , underline_thickness(0) + , underline_position(0) + , line_through_thickness(0) + , line_through_position(0) + , font_size(0) {} NRStyle::~NRStyle() @@ -144,6 +158,50 @@ void NRStyle::set(SPStyle *style) dash = NULL; } + text_decoration_line = TEXT_DECORATION_LINE_CLEAR; + if(style->text_decoration_line.inherit ){ text_decoration_line |= TEXT_DECORATION_LINE_INHERIT; } + if(style->text_decoration_line.underline ){ text_decoration_line |= TEXT_DECORATION_LINE_UNDERLINE + TEXT_DECORATION_LINE_SET; } + if(style->text_decoration_line.overline ){ text_decoration_line |= TEXT_DECORATION_LINE_OVERLINE + TEXT_DECORATION_LINE_SET; } + if(style->text_decoration_line.line_through){ text_decoration_line |= TEXT_DECORATION_LINE_LINETHROUGH + TEXT_DECORATION_LINE_SET; } + if(style->text_decoration_line.blink ){ text_decoration_line |= TEXT_DECORATION_LINE_BLINK + TEXT_DECORATION_LINE_SET; } + + text_decoration_style = TEXT_DECORATION_STYLE_CLEAR; + if(style->text_decoration_style.inherit ){ text_decoration_style |= TEXT_DECORATION_STYLE_INHERIT; } + if(style->text_decoration_style.solid ){ text_decoration_style |= TEXT_DECORATION_STYLE_SOLID + TEXT_DECORATION_STYLE_SET; } + if(style->text_decoration_style.isdouble ){ text_decoration_style |= TEXT_DECORATION_STYLE_ISDOUBLE + TEXT_DECORATION_STYLE_SET; } + if(style->text_decoration_style.dotted ){ text_decoration_style |= TEXT_DECORATION_STYLE_DOTTED + TEXT_DECORATION_STYLE_SET; } + if(style->text_decoration_style.dashed ){ text_decoration_style |= TEXT_DECORATION_STYLE_DASHED + TEXT_DECORATION_STYLE_SET; } + if(style->text_decoration_style.wavy ){ text_decoration_style |= TEXT_DECORATION_STYLE_WAVY + TEXT_DECORATION_STYLE_SET; } + + if( style->text_decoration_color.set || + style->text_decoration_color.inherit || + style->text_decoration_color.currentcolor || + style->text_decoration_color.colorSet){ + text_decoration_color.set(style->text_decoration_color.value.color); + text_decoration_useColor = true; + } + else { + text_decoration_color.clear(); + text_decoration_useColor = false; + } + + if(text_decoration_line != TEXT_DECORATION_LINE_CLEAR){ + phase_length = style->text_decoration_data.phase_length; + tspan_line_start = style->text_decoration_data.tspan_line_start; + tspan_line_end = style->text_decoration_data.tspan_line_end; + tspan_width = style->text_decoration_data.tspan_width; + ascender = style->text_decoration_data.ascender; + descender = style->text_decoration_data.descender; + line_gap = style->text_decoration_data.line_gap; + underline_thickness = style->text_decoration_data.underline_thickness; + underline_position = style->text_decoration_data.underline_position; + line_through_thickness = style->text_decoration_data.line_through_thickness; + line_through_position = style->text_decoration_data.line_through_position; + font_size = style->font_size.computed; + } + + text_direction = style->direction.computed; + update(); } diff --git a/src/display/nr-style.h b/src/display/nr-style.h index cd0bd208f..df4c4f921 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -67,6 +67,43 @@ struct NRStyle { cairo_pattern_t *fill_pattern; cairo_pattern_t *stroke_pattern; + +#define TEXT_DECORATION_LINE_CLEAR 0x00 +#define TEXT_DECORATION_LINE_SET 0x01 +#define TEXT_DECORATION_LINE_INHERIT 0x02 +#define TEXT_DECORATION_LINE_UNDERLINE 0x04 +#define TEXT_DECORATION_LINE_OVERLINE 0x08 +#define TEXT_DECORATION_LINE_LINETHROUGH 0x10 +#define TEXT_DECORATION_LINE_BLINK 0x20 + +#define TEXT_DECORATION_STYLE_CLEAR 0x00 +#define TEXT_DECORATION_STYLE_SET 0x01 +#define TEXT_DECORATION_STYLE_INHERIT 0x02 +#define TEXT_DECORATION_STYLE_SOLID 0x04 +#define TEXT_DECORATION_STYLE_ISDOUBLE 0x08 +#define TEXT_DECORATION_STYLE_DOTTED 0x10 +#define TEXT_DECORATION_STYLE_DASHED 0x20 +#define TEXT_DECORATION_STYLE_WAVY 0x40 + + int text_decoration_line; + int text_decoration_style; + Paint text_decoration_color; + bool text_decoration_useColor; // if false, use whatever the glyph color was + // These are the same as in style.h + float phase_length; + bool tspan_line_start; + bool tspan_line_end; + float tspan_width; + float ascender; + float descender; + float line_gap; + float underline_thickness; + float underline_position; + float line_through_thickness; + float line_through_position; + float font_size; + + int text_direction; }; #endif -- cgit v1.2.3 From c60177d361dd435e58caa902a395fa21c9415f51 Mon Sep 17 00:00:00 2001 From: Matthew Petroff Date: Wed, 17 Jul 2013 18:12:31 -0400 Subject: Removed "helper/unit.*" dependency from "ui/widget/registered-widget.*". (bzr r12380.1.21) --- src/display/canvas-axonomgrid.cpp | 2 +- src/display/canvas-grid.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index 1eadd3fd2..59d2bb36d 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -419,7 +419,7 @@ _wr.setUpdating (false); attach_all (*table, widget_array, sizeof(widget_array)); // set widget values - _rumg->setUnit (gridunit); + _rumg->setUnit (gridunit->abbr); gdouble val; val = origin[Geom::X]; diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index ee5ad0945..9fbb5f907 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -802,7 +802,7 @@ CanvasXYGrid::newSpecificWidget() attach_all (*table, widget_array, sizeof(widget_array)); // set widget values - _rumg->setUnit (gridunit); + _rumg->setUnit (gridunit->abbr); gdouble val; val = origin[Geom::X]; -- cgit v1.2.3 From e641b84738df214c63ff67ce1bd2d0b8f6449c2e Mon Sep 17 00:00:00 2001 From: Matthew Petroff Date: Thu, 18 Jul 2013 15:02:24 -0400 Subject: Ported "display/canvas-grid.*" and "display/canvas-axonomgrid.*". (bzr r12380.1.25) --- src/display/canvas-axonomgrid.cpp | 104 ++++++++--------------------- src/display/canvas-grid.cpp | 134 +++++++++++++------------------------- src/display/canvas-grid.h | 6 +- 3 files changed, 78 insertions(+), 166 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index 59d2bb36d..5d6efb18e 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -51,7 +51,7 @@ #include "2geom/angle.h" #include "util/mathfns.h" #include "round.h" -#include "helper/units.h" +#include "util/units.h" enum Dim3 { X=0, Y, Z }; @@ -160,15 +160,17 @@ CanvasAxonomGrid::CanvasAxonomGrid (SPNamedView * nv, Inkscape::XML::Node * in_r : CanvasGrid(nv, in_repr, in_doc, GRID_AXONOMETRIC) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gridunit = sp_unit_get_by_abbreviation( prefs->getString("/options/grids/axonom/units").data() ); + Inkscape::Util::UnitTable unit_table; + Inkscape::Util::Unit px = unit_table.getUnit("px"); + gridunit = new Inkscape::Util::Unit(unit_table.getUnit(prefs->getString("/options/grids/axonom/units"))); if (!gridunit) - gridunit = &sp_unit_get_by_id(SP_UNIT_PX); - origin[Geom::X] = sp_units_get_pixels( prefs->getDouble("/options/grids/axonom/origin_x", 0.0), *gridunit ); - origin[Geom::Y] = sp_units_get_pixels( prefs->getDouble("/options/grids/axonom/origin_y", 0.0), *gridunit ); + gridunit = new Inkscape::Util::Unit(unit_table.getUnit("px")); + origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_x", 0.0), gridunit, &px); + origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_y", 0.0), gridunit, &px); color = prefs->getInt("/options/grids/axonom/color", 0x0000ff20); empcolor = prefs->getInt("/options/grids/axonom/empcolor", 0x0000ff40); empspacing = prefs->getInt("/options/grids/axonom/empspacing", 5); - lengthy = sp_units_get_pixels( prefs->getDouble("/options/grids/axonom/spacing_y", 1.0), *gridunit ); + lengthy = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/spacing_y", 1.0), gridunit, &px); angle_deg[X] = prefs->getDouble("/options/grids/axonom/angle_x", 30.0); angle_deg[Z] = prefs->getDouble("/options/grids/axonom/angle_z", 30.0); angle_deg[Y] = 0; @@ -188,63 +190,6 @@ CanvasAxonomGrid::~CanvasAxonomGrid () if (snapper) delete snapper; } - -/* fixme: Collect all these length parsing methods and think common sane API */ - -static gboolean sp_nv_read_length(gchar const *str, guint base, gdouble *val, SPUnit const **unit) -{ - if (!str) { - return FALSE; - } - - gchar *u; - gdouble v = g_ascii_strtod(str, &u); - if (!u) { - return FALSE; - } - while (isspace(*u)) { - u += 1; - } - - if (!*u) { - /* No unit specified - keep default */ - *val = v; - return TRUE; - } - - if (base & SP_UNIT_DEVICE) { - if (u[0] && u[1] && !isalnum(u[2]) && !strncmp(u, "px", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_PX); - *val = v; - return TRUE; - } - } - - if (base & SP_UNIT_ABSOLUTE) { - if (!strncmp(u, "pt", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_PT); - } else if (!strncmp(u, "mm", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_MM); - } else if (!strncmp(u, "cm", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_CM); - } else if (!strncmp(u, "m", 1)) { - *unit = &sp_unit_get_by_id(SP_UNIT_M); - } else if (!strncmp(u, "in", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_IN); - } else if (!strncmp(u, "ft", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_FT); - } else if (!strncmp(u, "pc", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_PC); - } else { - return FALSE; - } - *val = v; - return TRUE; - } - - return FALSE; -} - static gboolean sp_nv_read_opacity(gchar const *str, guint32 *color) { if (!str) { @@ -269,18 +214,23 @@ void CanvasAxonomGrid::readRepr() { gchar const *value; + Inkscape::Util::UnitTable unit_table; + Inkscape::Util::Unit px = unit_table.getUnit("px"); if ( (value = repr->attribute("originx")) ) { - sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &origin[Geom::X], &gridunit); - origin[Geom::X] = sp_units_get_pixels(origin[Geom::X], *(gridunit)); + Inkscape::Util::Quantity q = unit_table.getQuantity(value); + gridunit = q.unit; + origin[Geom::X] = unit_table.getQuantity(value).value(&px); } if ( (value = repr->attribute("originy")) ) { - sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &origin[Geom::Y], &gridunit); - origin[Geom::Y] = sp_units_get_pixels(origin[Geom::Y], *(gridunit)); + Inkscape::Util::Quantity q = unit_table.getQuantity(value); + gridunit = q.unit; + origin[Geom::Y] = unit_table.getQuantity(value).value(&px); } if ( (value = repr->attribute("spacingy")) ) { - sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &lengthy, &gridunit); - lengthy = sp_units_get_pixels(lengthy, *(gridunit)); + Inkscape::Util::Quantity q = unit_table.getQuantity(value); + gridunit = q.unit; + lengthy = q.value(&px); if (lengthy < 0.0500) lengthy = 0.0500; } @@ -422,14 +372,16 @@ _wr.setUpdating (false); _rumg->setUnit (gridunit->abbr); gdouble val; + Inkscape::Util::UnitTable unit_table; + Inkscape::Util::Unit px = unit_table.getUnit("px"); val = origin[Geom::X]; - val = sp_pixels_get_units (val, *(gridunit)); + val = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_ox->setValue (val); val = origin[Geom::Y]; - val = sp_pixels_get_units (val, *(gridunit)); + val = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_oy->setValue (val); val = lengthy; - double gridy = sp_pixels_get_units (val, *(gridunit)); + double gridy = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_sy->setValue (gridy); _rsu_ax->setValue(angle_deg[X]); @@ -458,17 +410,17 @@ CanvasAxonomGrid::updateWidgets() _rcb_enabled.setActive(snapper->getEnabled()); } - _rumg.setUnit (gridunit); + _rumg.setUnit (gridunit->abbr); gdouble val; val = origin[Geom::X]; - val = sp_pixels_get_units (val, *(gridunit)); + val = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_ox.setValue (val); val = origin[Geom::Y]; - val = sp_pixels_get_units (val, *(gridunit)); + val = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_oy.setValue (val); val = lengthy; - double gridy = sp_pixels_get_units (val, *(gridunit)); + double gridy = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_sy.setValue (gridy); _rsu_ax.setValue(angle_deg[X]); diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 9fbb5f907..fdf156262 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -397,12 +397,15 @@ void CanvasGrid::setOrigin(Geom::Point const &origin_px) Inkscape::SVGOStringStream os_x, os_y; gdouble val; + Inkscape::Util::UnitTable unit_table; + Inkscape::Util::Unit px = unit_table.getUnit("px"); + val = origin_px[Geom::X]; - val = sp_pixels_get_units (val, *gridunit); - os_x << val << sp_unit_get_abbreviation(gridunit); + val = Inkscape::Util::Quantity::convert(val, &px, gridunit); + os_x << val << gridunit->abbr; val = origin_px[Geom::Y]; - val = sp_pixels_get_units (val, *gridunit); - os_y << val << sp_unit_get_abbreviation(gridunit); + val = Inkscape::Util::Quantity::convert(val, &px, gridunit); + os_y << val << gridunit->abbr; repr->setAttribute("originx", os_x.str().c_str()); repr->setAttribute("originy", os_y.str().c_str()); } @@ -488,17 +491,19 @@ CanvasXYGrid::CanvasXYGrid (SPNamedView * nv, Inkscape::XML::Node * in_repr, SPD : CanvasGrid(nv, in_repr, in_doc, GRID_RECTANGULAR) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gridunit = sp_unit_get_by_abbreviation( prefs->getString("/options/grids/xy/units").data() ); + Inkscape::Util::UnitTable unit_table; + gridunit = new Inkscape::Util::Unit(unit_table.getUnit(prefs->getString("/options/grids/xy/units"))); if (!gridunit) { - gridunit = &sp_unit_get_by_id(SP_UNIT_PX); + gridunit = new Inkscape::Util::Unit(unit_table.getUnit("px")); } - origin[Geom::X] = sp_units_get_pixels(prefs->getDouble("/options/grids/xy/origin_x", 0.0), *gridunit); - origin[Geom::Y] = sp_units_get_pixels(prefs->getDouble("/options/grids/xy/origin_y", 0.0), *gridunit); + Inkscape::Util::Unit px = unit_table.getUnit("px"); + origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_x", 0.0), gridunit, &px); + origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_y", 0.0), gridunit, &px); color = prefs->getInt("/options/grids/xy/color", 0x0000ff20); empcolor = prefs->getInt("/options/grids/xy/empcolor", 0x0000ff40); empspacing = prefs->getInt("/options/grids/xy/empspacing", 5); - spacing[Geom::X] = sp_units_get_pixels(prefs->getDouble("/options/grids/xy/spacing_x", 0.0), *gridunit); - spacing[Geom::Y] = sp_units_get_pixels(prefs->getDouble("/options/grids/xy/spacing_y", 0.0), *gridunit); + spacing[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_x", 0.0), gridunit, &px); + spacing[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_y", 0.0), gridunit, &px); render_dotted = prefs->getBool("/options/grids/xy/dotted", false); snapper = new CanvasXYGridSnapper(this, &namedview->snap_manager, 0); @@ -511,64 +516,6 @@ CanvasXYGrid::~CanvasXYGrid () if (snapper) delete snapper; } - -/* fixme: Collect all these length parsing methods and think common sane API */ - -static gboolean -sp_nv_read_length(gchar const *str, guint base, gdouble *val, SPUnit const **unit) -{ - if (!str) { - return FALSE; - } - - gchar *u; - gdouble v = g_ascii_strtod(str, &u); - if (!u) { - return FALSE; - } - while (isspace(*u)) { - u += 1; - } - - if (!*u) { - /* No unit specified - keep default */ - *val = v; - return TRUE; - } - - if (base & SP_UNIT_DEVICE) { - if (u[0] && u[1] && !isalnum(u[2]) && !strncmp(u, "px", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_PX); - *val = v; - return TRUE; - } - } - - if (base & SP_UNIT_ABSOLUTE) { - if (!strncmp(u, "pt", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_PT); - } else if (!strncmp(u, "mm", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_MM); - } else if (!strncmp(u, "cm", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_CM); - } else if (!strncmp(u, "m", 1)) { - *unit = &sp_unit_get_by_id(SP_UNIT_M); - } else if (!strncmp(u, "in", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_IN); - } else if (!strncmp(u, "ft", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_FT); - } else if (!strncmp(u, "pc", 2)) { - *unit = &sp_unit_get_by_id(SP_UNIT_PC); - } else { - return FALSE; - } - *val = v; - return TRUE; - } - - return FALSE; -} - static gboolean sp_nv_read_opacity(gchar const *str, guint32 *color) { if (!str) { @@ -643,30 +590,37 @@ static void validateInt(gint oldVal, void CanvasXYGrid::readRepr() { + Inkscape::Util::UnitTable unit_table; + Inkscape::Util::Unit px = unit_table.getUnit("px"); + gchar const *value; if ( (value = repr->attribute("originx")) ) { - sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &origin[Geom::X], &gridunit); - origin[Geom::X] = sp_units_get_pixels(origin[Geom::X], *(gridunit)); + Inkscape::Util::Quantity q = unit_table.getQuantity(value); + gridunit = q.unit; + origin[Geom::X] = unit_table.getQuantity(value).value(&px); } if ( (value = repr->attribute("originy")) ) { - sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &origin[Geom::Y], &gridunit); - origin[Geom::Y] = sp_units_get_pixels(origin[Geom::Y], *(gridunit)); + Inkscape::Util::Quantity q = unit_table.getQuantity(value); + gridunit = q.unit; + origin[Geom::Y] = unit_table.getQuantity(value).value(&px); } if ( (value = repr->attribute("spacingx")) ) { double oldVal = spacing[Geom::X]; - sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &spacing[Geom::X], &gridunit); - validateScalar( oldVal, &spacing[Geom::X]); - spacing[Geom::X] = sp_units_get_pixels(spacing[Geom::X], *(gridunit)); - + Inkscape::Util::Quantity q = unit_table.getQuantity(value); + gridunit = q.unit; + spacing[Geom::X] = q.quantity; + validateScalar(oldVal, &spacing[Geom::X]); + spacing[Geom::X] = Inkscape::Util::Quantity::convert(spacing[Geom::X], gridunit, &px); } if ( (value = repr->attribute("spacingy")) ) { double oldVal = spacing[Geom::Y]; - sp_nv_read_length(value, SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE, &spacing[Geom::Y], &gridunit); - validateScalar( oldVal, &spacing[Geom::Y]); - spacing[Geom::Y] = sp_units_get_pixels(spacing[Geom::Y], *(gridunit)); - + Inkscape::Util::Quantity q = unit_table.getQuantity(value); + gridunit = q.unit; + spacing[Geom::Y] = q.quantity; + validateScalar(oldVal, &spacing[Geom::Y]); + spacing[Geom::Y] = Inkscape::Util::Quantity::convert(spacing[Geom::Y], gridunit, &px); } if ( (value = repr->attribute("color")) ) { @@ -805,17 +759,19 @@ CanvasXYGrid::newSpecificWidget() _rumg->setUnit (gridunit->abbr); gdouble val; + Inkscape::Util::UnitTable unit_table; + Inkscape::Util::Unit px = unit_table.getUnit("px"); val = origin[Geom::X]; - val = sp_pixels_get_units (val, *(gridunit)); + val = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_ox->setValue (val); val = origin[Geom::Y]; - val = sp_pixels_get_units (val, *(gridunit)); + val = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_oy->setValue (val); val = spacing[Geom::X]; - double gridx = sp_pixels_get_units (val, *(gridunit)); + double gridx = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_sx->setValue (gridx); val = spacing[Geom::Y]; - double gridy = sp_pixels_get_units (val, *(gridunit)); + double gridy = Inkscape::Util::Quantity::convert(val, &px, gridunit); _rsu_sy->setValue (gridy); _rcp_gcol->setRgba32 (color); @@ -851,20 +807,20 @@ CanvasXYGrid::updateWidgets() _rcb_enabled.setActive(snapper->getEnabled()); } - _rumg.setUnit (gridunit); + _rumg.setUnit (gridunit->abbr); gdouble val; val = origin[Geom::X]; - val = sp_pixels_get_units (val, *(gridunit)); + val = Inkscape::Quantity::convert(val, &px, gridunit); _rsu_ox.setValue (val); val = origin[Geom::Y]; - val = sp_pixels_get_units (val, *(gridunit)); + val = Inkscape::Quantity::convert(val, &px, gridunit); _rsu_oy.setValue (val); val = spacing[Geom::X]; - double gridx = sp_pixels_get_units (val, *(gridunit)); + double gridx = Inkscape::Quantity::convert(val, &px, gridunit); _rsu_sx.setValue (gridx); val = spacing[Geom::Y]; - double gridy = sp_pixels_get_units (val, *(gridunit)); + double gridy = Inkscape::Quantity::convert(val, &px, gridunit); _rsu_sy.setValue (gridy); _rcp_gcol.setRgba32 (color); diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h index 7eaef407f..70b4bf744 100644 --- a/src/display/canvas-grid.h +++ b/src/display/canvas-grid.h @@ -28,6 +28,10 @@ namespace XML { class Node; } +namespace Util { +class Unit; +} + enum GridType { GRID_RECTANGULAR = 0, GRID_AXONOMETRIC = 1 @@ -88,7 +92,7 @@ public: guint32 empcolor; /**< Color for emphasis lines */ gint empspacing; /**< Spacing between emphasis lines */ - SPUnit const* gridunit; + Inkscape::Util::Unit const* gridunit; Inkscape::XML::Node * repr; SPDocument *doc; -- cgit v1.2.3 From 3772fc428950b2b946a1bd7c7c97e06219c3165f Mon Sep 17 00:00:00 2001 From: Matthew Petroff Date: Thu, 18 Jul 2013 17:21:24 -0400 Subject: Switch unit functions from using pointer arguements to reference arguements. (bzr r12380.1.28) --- src/display/canvas-axonomgrid.cpp | 21 +++++++++----------- src/display/canvas-grid.cpp | 40 ++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 34 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index 5d6efb18e..d3db94975 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -161,16 +161,15 @@ CanvasAxonomGrid::CanvasAxonomGrid (SPNamedView * nv, Inkscape::XML::Node * in_r { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); Inkscape::Util::UnitTable unit_table; - Inkscape::Util::Unit px = unit_table.getUnit("px"); gridunit = new Inkscape::Util::Unit(unit_table.getUnit(prefs->getString("/options/grids/axonom/units"))); if (!gridunit) gridunit = new Inkscape::Util::Unit(unit_table.getUnit("px")); - origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_x", 0.0), gridunit, &px); - origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_y", 0.0), gridunit, &px); + origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_x", 0.0), *gridunit, "px"); + origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_y", 0.0), *gridunit, "px"); color = prefs->getInt("/options/grids/axonom/color", 0x0000ff20); empcolor = prefs->getInt("/options/grids/axonom/empcolor", 0x0000ff40); empspacing = prefs->getInt("/options/grids/axonom/empspacing", 5); - lengthy = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/spacing_y", 1.0), gridunit, &px); + lengthy = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/spacing_y", 1.0), *gridunit, "px"); angle_deg[X] = prefs->getDouble("/options/grids/axonom/angle_x", 30.0); angle_deg[Z] = prefs->getDouble("/options/grids/axonom/angle_z", 30.0); angle_deg[Y] = 0; @@ -215,22 +214,21 @@ CanvasAxonomGrid::readRepr() { gchar const *value; Inkscape::Util::UnitTable unit_table; - Inkscape::Util::Unit px = unit_table.getUnit("px"); if ( (value = repr->attribute("originx")) ) { Inkscape::Util::Quantity q = unit_table.getQuantity(value); gridunit = q.unit; - origin[Geom::X] = unit_table.getQuantity(value).value(&px); + origin[Geom::X] = unit_table.getQuantity(value).value("px"); } if ( (value = repr->attribute("originy")) ) { Inkscape::Util::Quantity q = unit_table.getQuantity(value); gridunit = q.unit; - origin[Geom::Y] = unit_table.getQuantity(value).value(&px); + origin[Geom::Y] = unit_table.getQuantity(value).value("px"); } if ( (value = repr->attribute("spacingy")) ) { Inkscape::Util::Quantity q = unit_table.getQuantity(value); gridunit = q.unit; - lengthy = q.value(&px); + lengthy = q.value("px"); if (lengthy < 0.0500) lengthy = 0.0500; } @@ -373,15 +371,14 @@ _wr.setUpdating (false); gdouble val; Inkscape::Util::UnitTable unit_table; - Inkscape::Util::Unit px = unit_table.getUnit("px"); val = origin[Geom::X]; - val = Inkscape::Util::Quantity::convert(val, &px, gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); _rsu_ox->setValue (val); val = origin[Geom::Y]; - val = Inkscape::Util::Quantity::convert(val, &px, gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); _rsu_oy->setValue (val); val = lengthy; - double gridy = Inkscape::Util::Quantity::convert(val, &px, gridunit); + double gridy = Inkscape::Util::Quantity::convert(val, "px", *gridunit); _rsu_sy->setValue (gridy); _rsu_ax->setValue(angle_deg[X]); diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index fdf156262..e72e01dbc 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -398,13 +398,12 @@ void CanvasGrid::setOrigin(Geom::Point const &origin_px) gdouble val; Inkscape::Util::UnitTable unit_table; - Inkscape::Util::Unit px = unit_table.getUnit("px"); val = origin_px[Geom::X]; - val = Inkscape::Util::Quantity::convert(val, &px, gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); os_x << val << gridunit->abbr; val = origin_px[Geom::Y]; - val = Inkscape::Util::Quantity::convert(val, &px, gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); os_y << val << gridunit->abbr; repr->setAttribute("originx", os_x.str().c_str()); repr->setAttribute("originy", os_y.str().c_str()); @@ -496,14 +495,13 @@ CanvasXYGrid::CanvasXYGrid (SPNamedView * nv, Inkscape::XML::Node * in_repr, SPD if (!gridunit) { gridunit = new Inkscape::Util::Unit(unit_table.getUnit("px")); } - Inkscape::Util::Unit px = unit_table.getUnit("px"); - origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_x", 0.0), gridunit, &px); - origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_y", 0.0), gridunit, &px); + origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_x", 0.0), *gridunit, "px"); + origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_y", 0.0), *gridunit, "px"); color = prefs->getInt("/options/grids/xy/color", 0x0000ff20); empcolor = prefs->getInt("/options/grids/xy/empcolor", 0x0000ff40); empspacing = prefs->getInt("/options/grids/xy/empspacing", 5); - spacing[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_x", 0.0), gridunit, &px); - spacing[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_y", 0.0), gridunit, &px); + spacing[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_x", 0.0), *gridunit, "px"); + spacing[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_y", 0.0), *gridunit, "px"); render_dotted = prefs->getBool("/options/grids/xy/dotted", false); snapper = new CanvasXYGridSnapper(this, &namedview->snap_manager, 0); @@ -591,19 +589,18 @@ void CanvasXYGrid::readRepr() { Inkscape::Util::UnitTable unit_table; - Inkscape::Util::Unit px = unit_table.getUnit("px"); gchar const *value; if ( (value = repr->attribute("originx")) ) { Inkscape::Util::Quantity q = unit_table.getQuantity(value); gridunit = q.unit; - origin[Geom::X] = unit_table.getQuantity(value).value(&px); + origin[Geom::X] = unit_table.getQuantity(value).value("px"); } if ( (value = repr->attribute("originy")) ) { Inkscape::Util::Quantity q = unit_table.getQuantity(value); gridunit = q.unit; - origin[Geom::Y] = unit_table.getQuantity(value).value(&px); + origin[Geom::Y] = unit_table.getQuantity(value).value("px"); } if ( (value = repr->attribute("spacingx")) ) { @@ -612,7 +609,7 @@ CanvasXYGrid::readRepr() gridunit = q.unit; spacing[Geom::X] = q.quantity; validateScalar(oldVal, &spacing[Geom::X]); - spacing[Geom::X] = Inkscape::Util::Quantity::convert(spacing[Geom::X], gridunit, &px); + spacing[Geom::X] = Inkscape::Util::Quantity::convert(spacing[Geom::X], *gridunit, "px"); } if ( (value = repr->attribute("spacingy")) ) { double oldVal = spacing[Geom::Y]; @@ -620,7 +617,7 @@ CanvasXYGrid::readRepr() gridunit = q.unit; spacing[Geom::Y] = q.quantity; validateScalar(oldVal, &spacing[Geom::Y]); - spacing[Geom::Y] = Inkscape::Util::Quantity::convert(spacing[Geom::Y], gridunit, &px); + spacing[Geom::Y] = Inkscape::Util::Quantity::convert(spacing[Geom::Y], *gridunit, "px"); } if ( (value = repr->attribute("color")) ) { @@ -760,18 +757,17 @@ CanvasXYGrid::newSpecificWidget() gdouble val; Inkscape::Util::UnitTable unit_table; - Inkscape::Util::Unit px = unit_table.getUnit("px"); val = origin[Geom::X]; - val = Inkscape::Util::Quantity::convert(val, &px, gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); _rsu_ox->setValue (val); val = origin[Geom::Y]; - val = Inkscape::Util::Quantity::convert(val, &px, gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); _rsu_oy->setValue (val); val = spacing[Geom::X]; - double gridx = Inkscape::Util::Quantity::convert(val, &px, gridunit); + double gridx = Inkscape::Util::Quantity::convert(val, "px", *gridunit); _rsu_sx->setValue (gridx); val = spacing[Geom::Y]; - double gridy = Inkscape::Util::Quantity::convert(val, &px, gridunit); + double gridy = Inkscape::Util::Quantity::convert(val, "px", *gridunit); _rsu_sy->setValue (gridy); _rcp_gcol->setRgba32 (color); @@ -811,16 +807,16 @@ CanvasXYGrid::updateWidgets() gdouble val; val = origin[Geom::X]; - val = Inkscape::Quantity::convert(val, &px, gridunit); + val = Inkscape::Quantity::convert(val, "px", *gridunit); _rsu_ox.setValue (val); val = origin[Geom::Y]; - val = Inkscape::Quantity::convert(val, &px, gridunit); + val = Inkscape::Quantity::convert(val, "px", *gridunit); _rsu_oy.setValue (val); val = spacing[Geom::X]; - double gridx = Inkscape::Quantity::convert(val, &px, gridunit); + double gridx = Inkscape::Quantity::convert(val, "px", *gridunit); _rsu_sx.setValue (gridx); val = spacing[Geom::Y]; - double gridy = Inkscape::Quantity::convert(val, &px, gridunit); + double gridy = Inkscape::Quantity::convert(val, "px", *gridunit); _rsu_sy.setValue (gridy); _rcp_gcol.setRgba32 (color); -- cgit v1.2.3 From d955b45ebb37552b33e8d3350be2446bd4692bd9 Mon Sep 17 00:00:00 2001 From: Matthew Petroff Date: Fri, 19 Jul 2013 15:01:55 -0400 Subject: Removed "helper/units.h" from "display/canvas-grid.cpp". (bzr r12380.1.36) --- src/display/canvas-grid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/display') diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index e72e01dbc..1a5e0e52d 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -42,7 +42,7 @@ #include "display/canvas-grid.h" #include "display/sp-canvas-group.h" #include "document.h" -#include "helper/units.h" +#include "util/units.h" #include "inkscape.h" #include "preferences.h" #include "sp-namedview.h" -- cgit v1.2.3 From ed40d19ee34bde5b7a6b7bf38904838f8d072f87 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 31 Jul 2013 20:18:48 +0200 Subject: Fix selection of images in outline mode. Fixes LP #1089702 Fixed bugs: - https://launchpad.net/bugs/1089702 (bzr r12440) --- src/display/drawing-image.cpp | 46 ++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 753249e60..bdb7c15b0 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -9,6 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <2geom/bezier-curve.h> #include "display/cairo-utils.h" #include "display/drawing.h" #include "display/drawing-context.h" @@ -287,21 +288,9 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar static double distance_to_segment (Geom::Point const &p, Geom::Point const &a1, Geom::Point const &a2) { - // calculate sides of the triangle and their squares - double d1 = Geom::L2(p - a1); - double d1_2 = d1 * d1; - double d2 = Geom::L2(p - a2); - double d2_2 = d2 * d2; - double a = Geom::L2(a1 - a2); - double a_2 = a * a; - - // if one of the angles at the base is > 90, return the corresponding side - if (d1_2 + a_2 <= d2_2) return d1; - if (d2_2 + a_2 <= d1_2) return d2; - - // otherwise calculate the height to the base - double peri = (a + d1 + d2)/2; - return (2*sqrt(peri * (peri - a) * (peri - d1) * (peri - d2))/a); + Geom::LineSegment l(a1, a2); + Geom::Point np = l.pointAt(l.nearestPoint(p)); + return Geom::distance(np, p); } DrawingItem * @@ -313,22 +302,17 @@ DrawingImage::_pickItem(Geom::Point const &p, double delta, unsigned /*sticky*/) if (outline) { Geom::Rect r = bounds(); - - Geom::Point c00 = r.corner(0); - Geom::Point c01 = r.corner(3); - Geom::Point c11 = r.corner(2); - Geom::Point c10 = r.corner(1); - - // frame - if (distance_to_segment (p, c00, c10) < delta) return this; - if (distance_to_segment (p, c10, c11) < delta) return this; - if (distance_to_segment (p, c11, c01) < delta) return this; - if (distance_to_segment (p, c01, c00) < delta) return this; - - // diagonals - if (distance_to_segment (p, c00, c11) < delta) return this; - if (distance_to_segment (p, c10, c01) < delta) return this; - + Geom::Point pick = p * _ctm.inverse(); + + // find whether any side or diagonal is within delta + // to do so, iterate over all pairs of corners + for (unsigned i = 0; i < 3; ++i) { // for i=3, there is nothing to do + for (unsigned j = i+1; j < 4; ++j) { + if (distance_to_segment(pick, r.corner(i), r.corner(j)) < delta) { + return this; + } + } + } return NULL; } else { -- cgit v1.2.3 From beecbea1b415d5b9536f2309c4f30fc258e346f5 Mon Sep 17 00:00:00 2001 From: Markus Engel Date: Wed, 31 Jul 2013 22:51:23 +0200 Subject: Cleaned up a bit; fixed struct vs. class forward declarations. (bzr r11608.1.111) --- src/display/canvas-axonomgrid.h | 2 +- src/display/canvas-grid.h | 2 +- src/display/nr-filter-diffuselighting.h | 6 +++--- src/display/nr-filter-specularlighting.h | 6 +++--- src/display/nr-light.h | 6 +++--- src/display/nr-style.h | 2 +- src/display/nr-svgfonts.h | 6 +++--- 7 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-axonomgrid.h b/src/display/canvas-axonomgrid.h index f58ea3aca..4e5af863d 100644 --- a/src/display/canvas-axonomgrid.h +++ b/src/display/canvas-axonomgrid.h @@ -14,7 +14,7 @@ struct SPCanvasBuf; class SPDesktop; -struct SPNamedView; +class SPNamedView; namespace Inkscape { namespace XML { diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h index 7eaef407f..09c261e0d 100644 --- a/src/display/canvas-grid.h +++ b/src/display/canvas-grid.h @@ -13,7 +13,7 @@ #include "line-snapper.h" class SPDesktop; -struct SPNamedView; +class SPNamedView; struct SPCanvasBuf; class SPDocument; diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h index 15cc8e1ff..043a5eb39 100644 --- a/src/display/nr-filter-diffuselighting.h +++ b/src/display/nr-filter-diffuselighting.h @@ -19,9 +19,9 @@ #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" -struct SPFeDistantLight; -struct SPFePointLight; -struct SPFeSpotLight; +class SPFeDistantLight; +class SPFePointLight; +class SPFeSpotLight; struct SVGICCColor; namespace Inkscape { diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h index 0d1c0644f..c57e3a9ff 100644 --- a/src/display/nr-filter-specularlighting.h +++ b/src/display/nr-filter-specularlighting.h @@ -17,9 +17,9 @@ #include "display/nr-light-types.h" #include "display/nr-filter-primitive.h" -struct SPFeDistantLight; -struct SPFePointLight; -struct SPFeSpotLight; +class SPFeDistantLight; +class SPFePointLight; +class SPFeSpotLight; struct SVGICCColor; namespace Inkscape { diff --git a/src/display/nr-light.h b/src/display/nr-light.h index 022243bfc..0c1235483 100644 --- a/src/display/nr-light.h +++ b/src/display/nr-light.h @@ -13,9 +13,9 @@ #include "display/nr-light-types.h" #include <2geom/forward.h> -struct SPFeDistantLight; -struct SPFePointLight; -struct SPFeSpotLight; +class SPFeDistantLight; +class SPFePointLight; +class SPFeSpotLight; namespace Inkscape { namespace Filters { diff --git a/src/display/nr-style.h b/src/display/nr-style.h index cd0bd208f..43df6f8f1 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -16,7 +16,7 @@ #include <2geom/rect.h> #include "color.h" -struct SPPaintServer; +class SPPaintServer; struct SPStyle; namespace Inkscape { diff --git a/src/display/nr-svgfonts.h b/src/display/nr-svgfonts.h index 1101f93f2..e1bb047bb 100644 --- a/src/display/nr-svgfonts.h +++ b/src/display/nr-svgfonts.h @@ -17,9 +17,9 @@ #include class SvgFont; -struct SPFont; -struct SPGlyph; -struct SPMissingGlyph; +class SPFont; +class SPGlyph; +class SPMissingGlyph; struct _GdkEventExpose; typedef _GdkEventExpose GdkEventExpose; -- cgit v1.2.3 From bf4a1d2d49850170b936c30cfe2b30e798716406 Mon Sep 17 00:00:00 2001 From: Markus Engel Date: Sat, 3 Aug 2013 03:03:43 +0200 Subject: Cleaned up. (bzr r11608.1.117) --- src/display/nr-style.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index 26d70ad15..1929bfed6 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -153,8 +153,10 @@ bool NRStyle::prepareFill(Inkscape::DrawingContext &ct, Geom::OptRect const &pai if (!fill_pattern) { switch (fill.type) { case PAINT_SERVER: { - fill_pattern = sp_paint_server_create_pattern(fill.server, ct.raw(), paintbox, fill.opacity); - } break; + //fill_pattern = sp_paint_server_create_pattern(fill.server, ct.raw(), paintbox, fill.opacity); + fill_pattern = fill.server->pattern_new(ct.raw(), paintbox, fill.opacity); + + } break; case PAINT_COLOR: { SPColor const &c = fill.color; fill_pattern = cairo_pattern_create_rgba( @@ -178,8 +180,10 @@ bool NRStyle::prepareStroke(Inkscape::DrawingContext &ct, Geom::OptRect const &p if (!stroke_pattern) { switch (stroke.type) { case PAINT_SERVER: { - stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), paintbox, stroke.opacity); - } break; + //stroke_pattern = sp_paint_server_create_pattern(stroke.server, ct.raw(), paintbox, stroke.opacity); + stroke_pattern = stroke.server->pattern_new(ct.raw(), paintbox, stroke.opacity); + + } break; case PAINT_COLOR: { SPColor const &c = stroke.color; stroke_pattern = cairo_pattern_create_rgba( -- cgit v1.2.3 From 6ae6c0bea96eef09907091279e0678aa5f83102d Mon Sep 17 00:00:00 2001 From: Matthew Petroff Date: Sun, 4 Aug 2013 18:01:18 -0400 Subject: Switched to global UnitTable. (bzr r12380.1.62) --- src/display/canvas-axonomgrid.cpp | 4 +--- src/display/canvas-grid.cpp | 7 +------ 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index d3db94975..f7a7cb39a 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -53,6 +53,7 @@ #include "round.h" #include "util/units.h" +using Inkscape::Util::unit_table; enum Dim3 { X=0, Y, Z }; @@ -160,7 +161,6 @@ CanvasAxonomGrid::CanvasAxonomGrid (SPNamedView * nv, Inkscape::XML::Node * in_r : CanvasGrid(nv, in_repr, in_doc, GRID_AXONOMETRIC) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Inkscape::Util::UnitTable unit_table; gridunit = new Inkscape::Util::Unit(unit_table.getUnit(prefs->getString("/options/grids/axonom/units"))); if (!gridunit) gridunit = new Inkscape::Util::Unit(unit_table.getUnit("px")); @@ -213,7 +213,6 @@ void CanvasAxonomGrid::readRepr() { gchar const *value; - Inkscape::Util::UnitTable unit_table; if ( (value = repr->attribute("originx")) ) { Inkscape::Util::Quantity q = unit_table.getQuantity(value); gridunit = q.unit; @@ -370,7 +369,6 @@ _wr.setUpdating (false); _rumg->setUnit (gridunit->abbr); gdouble val; - Inkscape::Util::UnitTable unit_table; val = origin[Geom::X]; val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); _rsu_ox->setValue (val); diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 1a5e0e52d..ef32c113b 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -55,6 +55,7 @@ #include "display/sp-canvas.h" using Inkscape::DocumentUndo; +using Inkscape::Util::unit_table; namespace Inkscape { @@ -397,8 +398,6 @@ void CanvasGrid::setOrigin(Geom::Point const &origin_px) Inkscape::SVGOStringStream os_x, os_y; gdouble val; - Inkscape::Util::UnitTable unit_table; - val = origin_px[Geom::X]; val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); os_x << val << gridunit->abbr; @@ -490,7 +489,6 @@ CanvasXYGrid::CanvasXYGrid (SPNamedView * nv, Inkscape::XML::Node * in_repr, SPD : CanvasGrid(nv, in_repr, in_doc, GRID_RECTANGULAR) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Inkscape::Util::UnitTable unit_table; gridunit = new Inkscape::Util::Unit(unit_table.getUnit(prefs->getString("/options/grids/xy/units"))); if (!gridunit) { gridunit = new Inkscape::Util::Unit(unit_table.getUnit("px")); @@ -588,8 +586,6 @@ static void validateInt(gint oldVal, void CanvasXYGrid::readRepr() { - Inkscape::Util::UnitTable unit_table; - gchar const *value; if ( (value = repr->attribute("originx")) ) { Inkscape::Util::Quantity q = unit_table.getQuantity(value); @@ -756,7 +752,6 @@ CanvasXYGrid::newSpecificWidget() _rumg->setUnit (gridunit->abbr); gdouble val; - Inkscape::Util::UnitTable unit_table; val = origin[Geom::X]; val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); _rsu_ox->setValue (val); -- cgit v1.2.3 From 0697088a2e3fbb3f7777db721e8c5e4661311dbe Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 13 Sep 2013 23:14:45 +0200 Subject: Improve the functions which create GdkPixbuf from Cairo surface and vice versa. Simplifies some code. Also introduce proper refcounting into svg_preview_cache.cpp and fix its users. (bzr r12512) --- src/display/cairo-utils.cpp | 139 ++++++++++++++++++++++++++++++++++------ src/display/cairo-utils.h | 20 ++++-- src/display/drawing-image.cpp | 5 +- src/display/nr-filter-image.cpp | 16 +---- src/display/nr-filter-image.h | 1 - 5 files changed, 138 insertions(+), 43 deletions(-) (limited to 'src/display') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index fc56c7b26..2726c9d5a 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -28,16 +28,13 @@ #include "helper/geom-curves.h" #include "display/cairo-templates.h" -namespace { - /** * Key for cairo_surface_t to keep track of current color interpolation value * Only the address of the structure is used, it is never initialized. See: * http://www.cairographics.org/manual/cairo-Types.html#cairo-user-data-key-t */ -cairo_user_data_key_t ci_key; - -} // namespace +cairo_user_data_key_t ink_color_interpolation_key; +cairo_user_data_key_t ink_pixbuf_key; namespace Inkscape { @@ -291,7 +288,7 @@ feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv) SPColorInterpolation get_cairo_surface_ci(cairo_surface_t *surface) { - void* data = cairo_surface_get_user_data( surface, &ci_key ); + void* data = cairo_surface_get_user_data( surface, &ink_color_interpolation_key ); if( data != NULL ) { return (SPColorInterpolation)GPOINTER_TO_INT( data ); } else { @@ -317,13 +314,13 @@ set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation ci) { ink_cairo_surface_linear_to_srgb( surface ); } - cairo_surface_set_user_data(surface, &ci_key, GINT_TO_POINTER (ci), NULL); + cairo_surface_set_user_data(surface, &ink_color_interpolation_key, GINT_TO_POINTER (ci), NULL); } } void copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out) { - cairo_surface_set_user_data(out, &ci_key, cairo_surface_get_user_data(in, &ci_key), NULL); + cairo_surface_set_user_data(out, &ink_color_interpolation_key, cairo_surface_get_user_data(in, &ink_color_interpolation_key), NULL); } void @@ -375,26 +372,112 @@ ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m) } void -ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) +ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) { - cairo_surface_t *pbs = ink_cairo_surface_create_for_argb32_pixbuf(pb); + cairo_surface_t *pbs = ink_cairo_surface_get_for_pixbuf(pb); cairo_set_source_surface(ct, pbs, x, y); - cairo_surface_destroy(pbs); } +/* The functions below implement the following hack: + * + * The pixels formats of Cairo and GdkPixbuf are different. + * GdkPixbuf accesses pixels as bytes, alpha is not premultiplied, + * and successive bytes of a single pixel contain R, G, B and A components. + * Cairo accesses pixels as 32-bit ints, alpha is premultiplied, + * and each int contains as 0xAARRGGBB, accessed with bitwise operations. + * + * In other words, on a little endian system, a GdkPixbuf will contain: + * char *data = "rgbargbargba...." + * int *data = { 0xAABBGGRR, 0xAABBGGRR, 0xAABBGGRR, ... } + * while a Cairo image surface will contain: + * char *data = "bgrabgrabgra...." + * int *data = { 0xAARRGGBB, 0xAARRGGBB, 0xAARRGGBB, ... } + * + * It is possible to convert between these two formats (almost) losslessly. + * Some color information from partially transparent regions of the image + * is lost, but the result when displaying this image will remain the same. + * + * The functions below allow interoperation between GdkPixbuf + * and Cairo surfaces, allowing pixbufs to be used as Cairo sources, + * and saving Cairo surfaces using GdkPixbuf APIs. + * This is implemented by creating a GdkPixbuf and a Cairo image surface + * which share their data. Depending on what is needed at a given time, + * the pixels are converted in place to the Cairo or the GdkPixbuf format. + * In this way, only one copy of the image data is needed. + * + * Given either a GdkPixbuf or a Cairo surface, these functions create + * the other object and convert to its format. The returned object should be + * freed using cairo_surface_destroy or g_object_unref when it's no longer + * needed. + * + * Memory ownership semantics: + * Regardless of whether the pixels are stored in memory originally belonging + * to Cairo surface or to GdkPixbuf, the GdkPixbuf is the master object. + * To free the memory, unref the GdkPixbuf ONLY. + */ + +/** + * Converts the pixbuf to Cairo pixel format and returns an image surface + * which can be used as a source. + * + * The returned surface should be unreferenced + * with cairo_surface_destroy() once it's no longer needed. + * Calling this function causes the pixbuf to be unsuitable for use + * with GTK drawing functions. + */ cairo_surface_t * -ink_cairo_surface_create_for_argb32_pixbuf(GdkPixbuf *pb) +ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) { - guchar *data = gdk_pixbuf_get_pixels(pb); - int w = gdk_pixbuf_get_width(pb); - int h = gdk_pixbuf_get_height(pb); - int stride = gdk_pixbuf_get_rowstride(pb); + cairo_surface_t *pbs = + reinterpret_cast(g_object_get_data(G_OBJECT(pb), "cairo_surface")); + + ink_pixbuf_ensure_argb32(pb); + + if (pbs == NULL) { + guchar *data = gdk_pixbuf_get_pixels(pb); + int w = gdk_pixbuf_get_width(pb); + int h = gdk_pixbuf_get_height(pb); + int stride = gdk_pixbuf_get_rowstride(pb); + + // create a surface that stores the data + cairo_surface_t *pbs = cairo_image_surface_create_for_data( + data, CAIRO_FORMAT_ARGB32, w, h, stride); + + g_object_set_data_full(G_OBJECT(pb), "cairo_surface", pbs, (GDestroyNotify) cairo_surface_destroy); + cairo_surface_set_user_data(pbs, &ink_pixbuf_key, pb, NULL); + } - cairo_surface_t *pbs = cairo_image_surface_create_for_data( - data, CAIRO_FORMAT_ARGB32, w, h, stride); return pbs; } +/** + * Converts the Cairo surface to GdkPixbuf pixel format. + * GdkPixbuf takes ownership of the passed surface reference, + * so it should NOT be freed after calling this function. + */ +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s) +{ + GdkPixbuf *pb = reinterpret_cast(cairo_surface_get_user_data(s, &ink_pixbuf_key)); + if (pb == NULL) { + pb = gdk_pixbuf_new_from_data( + cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8, + cairo_image_surface_get_width(s), cairo_image_surface_get_height(s), + cairo_image_surface_get_stride(s), NULL, NULL); + + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); + g_object_set_data_full(G_OBJECT(pb), "cairo_surface", s, (GDestroyNotify) cairo_surface_destroy); + + cairo_surface_set_user_data(s, &ink_pixbuf_key, pb, NULL); + } else { + g_warning("Received surface which is already owned by GdkPixbuf"); + g_object_ref(pb); + } + + ink_pixbuf_ensure_normal(pb); + + return pb; +} + /** * Cleanup function for GdkPixbuf. * This function should be passed as the GdkPixbufDestroyNotify parameter @@ -445,7 +528,7 @@ cairo_surface_t * ink_cairo_surface_create_identical(cairo_surface_t *s) { cairo_surface_t *ns = ink_cairo_surface_create_same_size(s, cairo_surface_get_content(s)); - cairo_surface_set_user_data(ns, &ci_key, cairo_surface_get_user_data(s, &ci_key), NULL); + cairo_surface_set_user_data(ns, &ink_color_interpolation_key, cairo_surface_get_user_data(s, &ink_color_interpolation_key), NULL); return ns; } @@ -845,13 +928,20 @@ convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int stride) * using it with GTK will result in corrupted drawings. */ void -convert_pixbuf_normal_to_argb32(GdkPixbuf *pb) +ink_pixbuf_ensure_argb32(GdkPixbuf *pb) { + gchar *pixel_format = reinterpret_cast(g_object_get_data(G_OBJECT(pb), "pixel_format")); + if (pixel_format != NULL && strcmp(pixel_format, "argb32") == 0) { + // nothing to do + return; + } + convert_pixels_pixbuf_to_argb32( gdk_pixbuf_get_pixels(pb), gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb), gdk_pixbuf_get_rowstride(pb)); + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); } /** @@ -859,13 +949,20 @@ convert_pixbuf_normal_to_argb32(GdkPixbuf *pb) * Once this is done, the pixbuf can be used with GTK again. */ void -convert_pixbuf_argb32_to_normal(GdkPixbuf *pb) +ink_pixbuf_ensure_normal(GdkPixbuf *pb) { + gchar *pixel_format = reinterpret_cast(g_object_get_data(G_OBJECT(pb), "pixel_format")); + if (pixel_format == NULL || strcmp(pixel_format, "pixbuf") == 0) { + // nothing to do + return; + } + convert_pixels_argb32_to_pixbuf( gdk_pixbuf_get_pixels(pb), gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb), gdk_pixbuf_get_rowstride(pb)); + g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("pixbuf"), g_free); } guint32 argb32_from_rgba(guint32 in) diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index 016f72d00..289d4e01f 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -82,6 +82,17 @@ public: } // namespace Inkscape +enum InkPixelFormat { + INK_PIXEL_FORMAT_NONE, + INK_PIXEL_FORMAT_CAIRO, + INK_PIXEL_FORMAT_PIXBUF, + INK_PIXEL_FORMAT_LAST +}; + +// TODO: these declarations may not be needed in the header +extern cairo_user_data_key_t ink_color_interpolation_key; +extern cairo_user_data_key_t ink_pixbuf_key; + SPColorInterpolation get_cairo_surface_ci(cairo_surface_t *surface); void set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation cif); void copy_cairo_surface_ci(cairo_surface_t *in, cairo_surface_t *out); @@ -91,7 +102,7 @@ void ink_cairo_set_source_color(cairo_t *ct, SPColor const &color, double opacit void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba); void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m); void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m); -void ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); +void ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); void ink_matrix_to_2geom(Geom::Affine &, cairo_matrix_t const &); void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Affine const &); @@ -116,9 +127,10 @@ cairo_pattern_t *ink_cairo_pattern_create_checkerboard(); void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int rs); void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs); -void convert_pixbuf_normal_to_argb32(GdkPixbuf *); -void convert_pixbuf_argb32_to_normal(GdkPixbuf *); -cairo_surface_t *ink_cairo_surface_create_for_argb32_pixbuf(GdkPixbuf *pb); +void ink_pixbuf_ensure_argb32(GdkPixbuf *); +void ink_pixbuf_ensure_normal(GdkPixbuf *); +cairo_surface_t *ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb); +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s); void ink_cairo_pixbuf_cleanup(guchar *pixels, void *surface); G_GNUC_CONST guint32 argb32_from_pixbuf(guint32 in); diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index bdb7c15b0..b94d48774 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -22,7 +22,7 @@ namespace Inkscape { DrawingImage::DrawingImage(Drawing &drawing) : DrawingItem(drawing) , _pixbuf(NULL) - , _surface(NULL) + , _surface(NULL) // this is owned by _pixbuf! , _style(NULL) , _new_surface(NULL) {} @@ -33,7 +33,6 @@ DrawingImage::~DrawingImage() sp_style_unref(_style); if (_pixbuf) { if (_new_surface) cairo_surface_destroy(_new_surface); - cairo_surface_destroy(_surface); g_object_unref(_pixbuf); } } @@ -50,7 +49,7 @@ DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb) cairo_surface_destroy(_surface); } _pixbuf = pb; - _surface = pb ? ink_cairo_surface_create_for_argb32_pixbuf(pb) : NULL; + _surface = pb ? ink_cairo_surface_get_for_pixbuf(pb) : NULL; _markForUpdate(STATE_ALL, false); } diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 7a27d857e..8b307ac00 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -30,7 +30,6 @@ FilterImage::FilterImage() : SVGElem(0) , document(0) , feImageHref(0) - , image_surface(0) , broken_ref(false) { } @@ -172,18 +171,10 @@ void FilterImage::render_cairo(FilterSlot &slot) if (!has_alpha) { image = image->add_alpha(false, 0, 0, 0); } - - // Native size of image - // width = image->get_width(); - // height = image->get_height(); - // rowstride = image->get_rowstride(); - - convert_pixbuf_normal_to_argb32(image->gobj()); - - image_surface = cairo_image_surface_create_for_data(image->get_pixels(), - CAIRO_FORMAT_ARGB32, image->get_width(), image->get_height(), image->get_rowstride()); } + cairo_surface_t *image_surface = ink_cairo_surface_get_for_pixbuf(image->gobj()); + Geom::Rect sa = slot.get_slot_area(); cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sa.width(), sa.height()); @@ -310,9 +301,6 @@ void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; - if (image_surface) { - cairo_surface_destroy(image_surface); - } image.reset(); broken_ref = false; } diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index 05b7d65a8..f45f42265 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -44,7 +44,6 @@ private: SPDocument *document; gchar *feImageHref; Glib::RefPtr image; - cairo_surface_t *image_surface; float feImageX, feImageY, feImageWidth, feImageHeight; unsigned int aspect_align, aspect_clip; bool broken_ref; -- cgit v1.2.3 From 28840aad6554556231882cfd8c4fd85ede197a24 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 14 Sep 2013 02:53:34 +0200 Subject: Fix serious bug in recent GdkPixbuf / Cairo interop rework (bzr r12515) --- src/display/cairo-utils.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/display') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 2726c9d5a..2d94d024f 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -420,10 +420,9 @@ ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) * Converts the pixbuf to Cairo pixel format and returns an image surface * which can be used as a source. * - * The returned surface should be unreferenced - * with cairo_surface_destroy() once it's no longer needed. + * The returned surface is owned by the GdkPixbuf and should not be freed. * Calling this function causes the pixbuf to be unsuitable for use - * with GTK drawing functions. + * with GTK drawing functions until ink_pixbuf_ensure_normal() is called. */ cairo_surface_t * ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) @@ -440,7 +439,7 @@ ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) int stride = gdk_pixbuf_get_rowstride(pb); // create a surface that stores the data - cairo_surface_t *pbs = cairo_image_surface_create_for_data( + pbs = cairo_image_surface_create_for_data( data, CAIRO_FORMAT_ARGB32, w, h, stride); g_object_set_data_full(G_OBJECT(pb), "cairo_surface", pbs, (GDestroyNotify) cairo_surface_destroy); -- cgit v1.2.3 From 35dc2e5a640375d51119f2051a240454b5f5b8c8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 14 Sep 2013 03:59:43 +0200 Subject: Do not recompress images when embedding and generating PDFs. Fixes blocker bug #871563. Fixed bugs: - https://launchpad.net/bugs/871563 (bzr r12516) --- src/display/cairo-utils.cpp | 5 +++++ src/display/drawing-image.cpp | 4 ++-- src/display/nr-filter-image.cpp | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/display') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 2d94d024f..755553033 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -423,6 +423,11 @@ ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) * The returned surface is owned by the GdkPixbuf and should not be freed. * Calling this function causes the pixbuf to be unsuitable for use * with GTK drawing functions until ink_pixbuf_ensure_normal() is called. + * + * @bug You have to call g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL) + * when unrefing the last reference to the pixbuf. Otherwise there will be + * crashes, because cairo_surface_destroy is called after the pixbuf data + * is already freed. */ cairo_surface_t * ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index b94d48774..46f066b8e 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -46,7 +46,7 @@ DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb) } if (_pixbuf != NULL) { g_object_unref(_pixbuf); - cairo_surface_destroy(_surface); + // unrefing the pixbuf also destroys surface } _pixbuf = pb; _surface = pb ? ink_cairo_surface_get_for_pixbuf(pb) : NULL; @@ -206,7 +206,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar int orgstride = cairo_image_surface_get_stride(_surface); int newstride = cairo_image_surface_get_stride(_new_surface); - cairo_surface_flush(_surface); + //cairo_surface_flush(_surface); cairo_surface_flush(_new_surface); for(int y=0; ygobj()), "cairo_surface", NULL); } void FilterImage::render_cairo(FilterSlot &slot) @@ -301,6 +302,7 @@ void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; + g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); image.reset(); broken_ref = false; } -- cgit v1.2.3 From 54482403aebd77dc3fadcc5cc99740defda51aeb Mon Sep 17 00:00:00 2001 From: Diederik van Lierop <> Date: Sun, 15 Sep 2013 21:27:42 +0200 Subject: Scale rendering of pattern fill of text when chaning zoom level; partial fix for blocker bug #1005892; this reinstates a line that was commented out in rev. 12488 Fixed bugs: - https://launchpad.net/bugs/1005892 (bzr r12523) --- src/display/drawing-text.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/display') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 234006983..55d54b770 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -441,7 +441,7 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are } Inkscape::DrawingContext::Save save(ct); -// ct.transform(_ctm); // Seems to work fine without this line, which was in the original. + ct.transform(_ctm); // For one thing, this is needed to scale a fill-pattern when zooming in if (has_fill) { _nrstyle.applyFill(ct); ct.fillPreserve(); -- cgit v1.2.3 From 5e05c910c59854938df73ba276b090773e9f6d0c Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Tue, 17 Sep 2013 11:41:39 -0400 Subject: Remove compute drawbox and replace with area_elarge, make sure we use bbox (bzr r12525) --- src/display/drawing-item.cpp | 4 +++- src/display/nr-filter.cpp | 14 -------------- src/display/nr-filter.h | 6 ------ 3 files changed, 3 insertions(+), 21 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 80664d822..1814dd615 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -353,7 +353,9 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if (to_update & STATE_BBOX) { // compute drawbox if (_filter && render_filters) { - _drawbox = _filter->compute_drawbox(this, _item_bbox); + Geom::IntRect newbox(*_bbox); + _filter->area_enlarge(newbox, this); + _drawbox = Geom::OptIntRect(newbox); } else { _drawbox = _bbox; } diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index f0965c460..4f2a18531 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -220,20 +220,6 @@ void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item */ } -Geom::OptIntRect Filter::compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox) { - -// Geom::OptRect enlarged = filter_effect_area(item_bbox); // disabled, already done in visualBounds - Geom::OptRect enlarged = item_bbox; // see LP Bug 1188336 - if (enlarged) { - *enlarged *= item->ctm(); - - Geom::OptIntRect ret(enlarged->roundOutwards()); - return ret; - } else { - return Geom::OptIntRect(); - } -} - Geom::OptRect Filter::filter_effect_area(Geom::OptRect const &bbox) { Geom::Point minp, maxp; diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index d53005c5d..5df38ffe9 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -150,12 +150,6 @@ public: * drawn correctly. */ void area_enlarge(Geom::IntRect &area, Inkscape::DrawingItem const *item) const; - /** - * Given an item bounding box (in user coords), this function enlarges it - * to contain the filter effects region and transforms it to screen - * coordinates - */ - Geom::OptIntRect compute_drawbox(Inkscape::DrawingItem const *item, Geom::OptRect const &item_bbox); /** * Returns the filter effects area in user coordinate system. * The given bounding box should be a bounding box as specified in -- cgit v1.2.3 From 0f85e2c60c4406eaddc7a96d8ddcc05d36d458f2 Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Wed, 18 Sep 2013 14:46:36 -0400 Subject: Remove setItemBounds and _item_bbox because aren't sensible, replace with bbox. Fixed bugs: - https://launchpad.net/bugs/243729 (bzr r12528) --- src/display/drawing-item.cpp | 6 ------ src/display/drawing-item.h | 2 -- src/display/drawing-shape.cpp | 4 ++-- src/display/drawing-text.cpp | 4 ++-- src/display/nr-filter.cpp | 8 ++++---- 5 files changed, 8 insertions(+), 16 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 1814dd615..097a5fe76 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -281,12 +281,6 @@ DrawingItem::setZOrder(unsigned z) _markForRendering(); } -void -DrawingItem::setItemBounds(Geom::OptRect const &bounds) -{ - _item_bbox = bounds; -} - /** * Update derived data before operations. * The purpose of this call is to recompute internal data which depends diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index 4a516512b..650653ce2 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -89,7 +89,6 @@ public: Geom::OptIntRect geometricBounds() const { return _bbox; } Geom::OptIntRect visualBounds() const { return _drawbox; } - Geom::OptRect itemBounds() const { return _item_bbox; } Geom::Affine ctm() const { return _ctm; } Geom::Affine transform() const { return _transform ? *_transform : Geom::identity(); } Drawing &drawing() const { return _drawing; } @@ -175,7 +174,6 @@ protected: Geom::Affine _ctm; ///< Total transform from item coords to display coords Geom::OptIntRect _bbox; ///< Bounding box in display (pixel) coords including stroke Geom::OptIntRect _drawbox; ///< Full visual bounding box - enlarged by filters, shrunk by clips and masks - Geom::OptRect _item_bbox; ///< Geometric bounding box in item coordinates DrawingItem *_clip; DrawingItem *_mask; diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index e80f12486..e689d0755 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -179,8 +179,8 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne // update fill and stroke paints. // this cannot be done during nr_arena_shape_update, because we need a Cairo context // to render svg:pattern - has_fill = _nrstyle.prepareFill(ct, _item_bbox); - has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); + has_fill = _nrstyle.prepareFill(ct, _bbox); + has_stroke = _nrstyle.prepareStroke(ct, _bbox); has_stroke &= (_nrstyle.stroke_width != 0); if (has_fill || has_stroke) { diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 55d54b770..fa9ce4ff8 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -398,8 +398,8 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are using Geom::X; using Geom::Y; - has_fill = _nrstyle.prepareFill( ct, _item_bbox); - has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); + has_fill = _nrstyle.prepareFill( ct, _bbox); + has_stroke = _nrstyle.prepareStroke(ct, _bbox); if (has_fill || has_stroke) { Geom::Affine rotinv; diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 4f2a18531..54bd36168 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -114,13 +114,13 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D Geom::Affine trans = item->ctm(); -// Geom::OptRect filter_area = filter_effect_area(item->itemBounds()); // disabled, already done in visualBounds - Geom::OptRect filter_area = item->itemBounds(); // see LP Bug 1188336 + // Get filter are, the filter_effect_area is already done in visualBounds + Geom::OptRect filter_area = item->geometricBounds(); if (!filter_area) return 1; FilterUnits units(_filter_units, _primitive_units); units.set_ctm(trans); - units.set_item_bbox(item->itemBounds()); + units.set_item_bbox(item->geometricBounds()); units.set_filter_area(*filter_area); std::pair resolution @@ -200,7 +200,7 @@ void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item } Geom::Rect item_bbox; - Geom::OptRect maybe_bbox = item->itemBounds(); + Geom::OptRect maybe_bbox = item->geometricBounds(); if (maybe_bbox.isEmpty()) { // Code below needs a bounding box return; -- cgit v1.2.3 From 083367b313247a4cf0c082fff25e993892dc38d1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 19 Sep 2013 02:57:10 +0200 Subject: Encapsulate the shared memory hack for Cairo and GdkPixbuf in a class called Inkscape::Pixbuf. Replace usage in the code as appropriate. (bzr r12531) --- src/display/cairo-utils.cpp | 539 +++++++++++++++++++++++++++++++--------- src/display/cairo-utils.h | 70 ++++-- src/display/drawing-image.cpp | 64 ++--- src/display/drawing-image.h | 6 +- src/display/nr-filter-image.cpp | 69 +++-- src/display/nr-filter-image.h | 6 +- 6 files changed, 539 insertions(+), 215 deletions(-) (limited to 'src/display') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 755553033..2c7b543c1 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -15,6 +15,8 @@ #include "display/cairo-utils.h" #include +#include +#include #include <2geom/pathvector.h> #include <2geom/bezier-curve.h> #include <2geom/hvlinesegment.h> @@ -28,6 +30,8 @@ #include "helper/geom-curves.h" #include "display/cairo-templates.h" +static void ink_cairo_pixbuf_cleanup(guchar *, void *); + /** * Key for cairo_surface_t to keep track of current color interpolation value * Only the address of the structure is used, it is never initialized. See: @@ -116,6 +120,380 @@ Cairo::RefPtr CairoContext::create(Cairo::RefPtr c return ret; } + +/* The class below implement the following hack: + * + * The pixels formats of Cairo and GdkPixbuf are different. + * GdkPixbuf accesses pixels as bytes, alpha is not premultiplied, + * and successive bytes of a single pixel contain R, G, B and A components. + * Cairo accesses pixels as 32-bit ints, alpha is premultiplied, + * and each int contains as 0xAARRGGBB, accessed with bitwise operations. + * + * In other words, on a little endian system, a GdkPixbuf will contain: + * char *data = "rgbargbargba...." + * int *data = { 0xAABBGGRR, 0xAABBGGRR, 0xAABBGGRR, ... } + * while a Cairo image surface will contain: + * char *data = "bgrabgrabgra...." + * int *data = { 0xAARRGGBB, 0xAARRGGBB, 0xAARRGGBB, ... } + * + * It is possible to convert between these two formats (almost) losslessly. + * Some color information from partially transparent regions of the image + * is lost, but the result when displaying this image will remain the same. + * + * The class allows interoperation between GdkPixbuf + * and Cairo surfaces without creating a copy of the image. + * This is implemented by creating a GdkPixbuf and a Cairo image surface + * which share their data. Depending on what is needed at a given time, + * the pixels are converted in place to the Cairo or the GdkPixbuf format. + */ + +/** Create a pixbuf from a Cairo surface. + * The constructor takes ownership of the passed surface, + * so it should not be destroyed. */ +Pixbuf::Pixbuf(cairo_surface_t *s) + : _pixbuf(gdk_pixbuf_new_from_data( + cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8, + cairo_image_surface_get_width(s), cairo_image_surface_get_height(s), + cairo_image_surface_get_stride(s), NULL, NULL)) + , _surface(s) + , _mod_time(0) + , _pixel_format(PF_CAIRO) + , _cairo_store(true) +{} + +/** Create a pixbuf from a GdkPixbuf. + * The constructor takes ownership of the passed GdkPixbuf reference, + * so it should not be unrefed. */ +Pixbuf::Pixbuf(GdkPixbuf *pb) + : _pixbuf(pb) + , _surface(0) + , _mod_time(0) + , _pixel_format(PF_GDK) + , _cairo_store(false) +{ + _forceAlpha(); + _surface = cairo_image_surface_create_for_data( + gdk_pixbuf_get_pixels(_pixbuf), CAIRO_FORMAT_ARGB32, + gdk_pixbuf_get_width(_pixbuf), gdk_pixbuf_get_height(_pixbuf), gdk_pixbuf_get_rowstride(_pixbuf)); +} + +Pixbuf::Pixbuf(Inkscape::Pixbuf const &other) + : _pixbuf(gdk_pixbuf_copy(other._pixbuf)) + , _surface(cairo_image_surface_create_for_data( + gdk_pixbuf_get_pixels(_pixbuf), CAIRO_FORMAT_ARGB32, + gdk_pixbuf_get_width(_pixbuf), gdk_pixbuf_get_height(_pixbuf), gdk_pixbuf_get_rowstride(_pixbuf))) + , _mod_time(other._mod_time) + , _path(other._path) + , _pixel_format(other._pixel_format) + , _cairo_store(false) +{} + +Pixbuf::~Pixbuf() +{ + if (_cairo_store) { + g_object_unref(_pixbuf); + cairo_surface_destroy(_surface); + } else { + cairo_surface_destroy(_surface); + g_object_unref(_pixbuf); + } +} + +Pixbuf *Pixbuf::create_from_data_uri(gchar const *uri_data) +{ + Pixbuf *pixbuf = NULL; + + bool data_is_image = false; + bool data_is_base64 = false; + + gchar const *data = uri_data; + + while (*data) { + if (strncmp(data,"base64",6) == 0) { + /* base64-encoding */ + data_is_base64 = true; + data_is_image = true; // Illustrator produces embedded images without MIME type, so we assume it's image no matter what + data += 6; + } + else if (strncmp(data,"image/png",9) == 0) { + /* PNG image */ + data_is_image = true; + data += 9; + } + else if (strncmp(data,"image/jpg",9) == 0) { + /* JPEG image */ + data_is_image = true; + data += 9; + } + else if (strncmp(data,"image/jpeg",10) == 0) { + /* JPEG image */ + data_is_image = true; + data += 10; + } + else if (strncmp(data,"image/jp2",9) == 0) { + /* JPEG2000 image */ + data_is_image = true; + data += 9; + } + else { /* unrecognized option; skip it */ + while (*data) { + if (((*data) == ';') || ((*data) == ',')) { + break; + } + data++; + } + } + if ((*data) == ';') { + data++; + continue; + } + if ((*data) == ',') { + data++; + break; + } + } + + if ((*data) && data_is_image && data_is_base64) { + GdkPixbuf *buf = NULL; + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + + if (!loader) return NULL; + + gsize decoded_len = 0; + guchar *decoded = g_base64_decode(data, &decoded_len); + + if (gdk_pixbuf_loader_write(loader, decoded, decoded_len, NULL)) { + gdk_pixbuf_loader_close(loader, NULL); + buf = gdk_pixbuf_loader_get_pixbuf(loader); + if (buf) { + g_object_ref(buf); + pixbuf = new Pixbuf(buf); + + GdkPixbufFormat *fmt = gdk_pixbuf_loader_get_format(loader); + gchar *fmt_name = gdk_pixbuf_format_get_name(fmt); + pixbuf->_setMimeData(decoded, decoded_len, fmt_name); + g_free(fmt_name); + } else { + g_free(decoded); + } + } else { + g_free(decoded); + } + g_object_unref(loader); + } + + return pixbuf; +} + +Pixbuf *Pixbuf::create_from_file(std::string const &fn) +{ + Pixbuf *pb = NULL; + // test correctness of filename + if (!g_file_test(fn.c_str(), G_FILE_TEST_EXISTS)) { + return NULL; + } + struct stat stdir; + int val = g_stat(fn.c_str(), &stdir); + if (val == 0 && stdir.st_mode & S_IFDIR){ + return NULL; + } + + // we need to load the entire file into memory, + // since we'll store it as MIME data + gchar *data = NULL; + gsize len = 0; + GError *error; + + if (g_file_get_contents(fn.c_str(), &data, &len, &error)) { + + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(loader, (guchar *) data, len, NULL); + gdk_pixbuf_loader_close(loader, NULL); + + GdkPixbuf *buf = gdk_pixbuf_loader_get_pixbuf(loader); + if (buf) { + g_object_ref(buf); + pb = new Pixbuf(buf); + pb->_mod_time = stdir.st_mtime; + pb->_path = fn; + + GdkPixbufFormat *fmt = gdk_pixbuf_loader_get_format(loader); + gchar *fmt_name = gdk_pixbuf_format_get_name(fmt); + pb->_setMimeData((guchar *) data, len, fmt_name); + g_free(fmt_name); + } else { + g_free(data); + } + g_object_unref(loader); + + // TODO: we could also read DPI, ICC profile, gamma correction, and other information + // from the file. This can be done by using format-specific libraries e.g. libpng. + } else { + return NULL; + } + + return pb; +} + +/** + * Converts the pixbuf to GdkPixbuf pixel format. + * The returned pixbuf can be used e.g. in calls to gdk_pixbuf_save(). + */ +GdkPixbuf *Pixbuf::getPixbufRaw(bool convert_format) +{ + if (convert_format) { + ensurePixelFormat(PF_GDK); + } + return _pixbuf; +} + +/** + * Converts the pixbuf to Cairo pixel format and returns an image surface + * which can be used as a source. + * + * The returned surface is owned by the GdkPixbuf and should not be freed. + * Calling this function causes the pixbuf to be unsuitable for use + * with GTK drawing functions until ensurePixelFormat(Pixbuf::PIXEL_FORMAT_PIXBUF) is called. + */ +cairo_surface_t *Pixbuf::getSurfaceRaw(bool convert_format) +{ + if (convert_format) { + ensurePixelFormat(PF_CAIRO); + } + return _surface; +} + +/* Declaring this function in the header requires including , + * which stupidly includes which in turn pulls in . + * However, since glib 2.32, has to be included before + * when compiling with G_DISABLE_DEPRECATED, as we do in non-release builds. + * This necessitates spamming a lot of files with #include + * at the top. + * + * Since we don't really use gdkmm, do not define this function for now. */ + +/* +Glib::RefPtr Pixbuf::getPixbuf(bool convert_format = true) +{ + g_object_ref(_pixbuf); + Glib::RefPtr p(getPixbuf(convert_format)); + return p; +} +*/ + +Cairo::RefPtr Pixbuf::getSurface(bool convert_format) +{ + Cairo::RefPtr p(new Cairo::Surface(getSurfaceRaw(convert_format), false)); + return p; +} + +/** Retrieves the original compressed data for the surface, if any. + * The returned data belongs to the object and should not be freed. */ +guchar const *Pixbuf::getMimeData(gsize &len, std::string &mimetype) const +{ + static gchar const *mimetypes[] = { + CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_PNG, NULL }; + static guint mimetypes_len = g_strv_length(const_cast(mimetypes)); + + guchar const *data = NULL; + + for (guint i = 0; i < mimetypes_len; ++i) { + unsigned long len_long = 0; + cairo_surface_get_mime_data(const_cast(_surface), mimetypes[i], &data, &len); + len = len_long; // this assumes that the added range of long is not needed. the code below assumes gsize range of values is sufficient. + if (data != NULL) { + mimetype = mimetypes[i]; + break; + } + } + + return data; +} + +int Pixbuf::width() const { + return gdk_pixbuf_get_width(const_cast(_pixbuf)); +} +int Pixbuf::height() const { + return gdk_pixbuf_get_height(const_cast(_pixbuf)); +} +int Pixbuf::rowstride() const { + return gdk_pixbuf_get_rowstride(const_cast(_pixbuf)); +} +guchar const *Pixbuf::pixels() const { + return gdk_pixbuf_get_pixels(const_cast(_pixbuf)); +} +guchar *Pixbuf::pixels() { + return gdk_pixbuf_get_pixels(_pixbuf); +} +void Pixbuf::markDirty() { + cairo_surface_mark_dirty(_surface); +} + +void Pixbuf::_forceAlpha() +{ + if (gdk_pixbuf_get_has_alpha(_pixbuf)) return; + + GdkPixbuf *old = _pixbuf; + _pixbuf = gdk_pixbuf_add_alpha(old, FALSE, 0, 0, 0); + g_object_unref(old); +} + +void Pixbuf::_setMimeData(guchar *data, gsize len, Glib::ustring const &format) +{ + gchar const *mimetype = NULL; + + if (format == "jpeg") { + mimetype = CAIRO_MIME_TYPE_JPEG; + } else if (format == "jpeg2000") { + mimetype = CAIRO_MIME_TYPE_JP2; + } else if (format == "png") { + mimetype = CAIRO_MIME_TYPE_PNG; + } + + if (mimetype != NULL) { + cairo_surface_set_mime_data(_surface, mimetype, data, len, g_free, data); + //g_message("Setting Cairo MIME data: %s", mimetype); + } else { + g_free(data); + //g_message("Not setting Cairo MIME data: unknown format %s", name.c_str()); + } +} + +void Pixbuf::ensurePixelFormat(PixelFormat fmt) +{ + if (_pixel_format == PF_GDK) { + if (fmt == PF_GDK) { + return; + } + if (fmt == PF_CAIRO) { + convert_pixels_pixbuf_to_argb32( + gdk_pixbuf_get_pixels(_pixbuf), + gdk_pixbuf_get_width(_pixbuf), + gdk_pixbuf_get_height(_pixbuf), + gdk_pixbuf_get_rowstride(_pixbuf)); + _pixel_format = fmt; + return; + } + g_assert_not_reached(); + } + if (_pixel_format == PF_CAIRO) { + if (fmt == PF_GDK) { + convert_pixels_argb32_to_pixbuf( + gdk_pixbuf_get_pixels(_pixbuf), + gdk_pixbuf_get_width(_pixbuf), + gdk_pixbuf_get_height(_pixbuf), + gdk_pixbuf_get_rowstride(_pixbuf)); + _pixel_format = fmt; + return; + } + if (fmt == PF_CAIRO) { + return; + } + g_assert_not_reached(); + } + g_assert_not_reached(); +} + } // namespace Inkscape /* @@ -371,129 +749,6 @@ ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m) cairo_pattern_set_matrix(cp, &cm); } -void -ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y) -{ - cairo_surface_t *pbs = ink_cairo_surface_get_for_pixbuf(pb); - cairo_set_source_surface(ct, pbs, x, y); -} - -/* The functions below implement the following hack: - * - * The pixels formats of Cairo and GdkPixbuf are different. - * GdkPixbuf accesses pixels as bytes, alpha is not premultiplied, - * and successive bytes of a single pixel contain R, G, B and A components. - * Cairo accesses pixels as 32-bit ints, alpha is premultiplied, - * and each int contains as 0xAARRGGBB, accessed with bitwise operations. - * - * In other words, on a little endian system, a GdkPixbuf will contain: - * char *data = "rgbargbargba...." - * int *data = { 0xAABBGGRR, 0xAABBGGRR, 0xAABBGGRR, ... } - * while a Cairo image surface will contain: - * char *data = "bgrabgrabgra...." - * int *data = { 0xAARRGGBB, 0xAARRGGBB, 0xAARRGGBB, ... } - * - * It is possible to convert between these two formats (almost) losslessly. - * Some color information from partially transparent regions of the image - * is lost, but the result when displaying this image will remain the same. - * - * The functions below allow interoperation between GdkPixbuf - * and Cairo surfaces, allowing pixbufs to be used as Cairo sources, - * and saving Cairo surfaces using GdkPixbuf APIs. - * This is implemented by creating a GdkPixbuf and a Cairo image surface - * which share their data. Depending on what is needed at a given time, - * the pixels are converted in place to the Cairo or the GdkPixbuf format. - * In this way, only one copy of the image data is needed. - * - * Given either a GdkPixbuf or a Cairo surface, these functions create - * the other object and convert to its format. The returned object should be - * freed using cairo_surface_destroy or g_object_unref when it's no longer - * needed. - * - * Memory ownership semantics: - * Regardless of whether the pixels are stored in memory originally belonging - * to Cairo surface or to GdkPixbuf, the GdkPixbuf is the master object. - * To free the memory, unref the GdkPixbuf ONLY. - */ - -/** - * Converts the pixbuf to Cairo pixel format and returns an image surface - * which can be used as a source. - * - * The returned surface is owned by the GdkPixbuf and should not be freed. - * Calling this function causes the pixbuf to be unsuitable for use - * with GTK drawing functions until ink_pixbuf_ensure_normal() is called. - * - * @bug You have to call g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL) - * when unrefing the last reference to the pixbuf. Otherwise there will be - * crashes, because cairo_surface_destroy is called after the pixbuf data - * is already freed. - */ -cairo_surface_t * -ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb) -{ - cairo_surface_t *pbs = - reinterpret_cast(g_object_get_data(G_OBJECT(pb), "cairo_surface")); - - ink_pixbuf_ensure_argb32(pb); - - if (pbs == NULL) { - guchar *data = gdk_pixbuf_get_pixels(pb); - int w = gdk_pixbuf_get_width(pb); - int h = gdk_pixbuf_get_height(pb); - int stride = gdk_pixbuf_get_rowstride(pb); - - // create a surface that stores the data - pbs = cairo_image_surface_create_for_data( - data, CAIRO_FORMAT_ARGB32, w, h, stride); - - g_object_set_data_full(G_OBJECT(pb), "cairo_surface", pbs, (GDestroyNotify) cairo_surface_destroy); - cairo_surface_set_user_data(pbs, &ink_pixbuf_key, pb, NULL); - } - - return pbs; -} - -/** - * Converts the Cairo surface to GdkPixbuf pixel format. - * GdkPixbuf takes ownership of the passed surface reference, - * so it should NOT be freed after calling this function. - */ -GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s) -{ - GdkPixbuf *pb = reinterpret_cast(cairo_surface_get_user_data(s, &ink_pixbuf_key)); - if (pb == NULL) { - pb = gdk_pixbuf_new_from_data( - cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8, - cairo_image_surface_get_width(s), cairo_image_surface_get_height(s), - cairo_image_surface_get_stride(s), NULL, NULL); - - g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free); - g_object_set_data_full(G_OBJECT(pb), "cairo_surface", s, (GDestroyNotify) cairo_surface_destroy); - - cairo_surface_set_user_data(s, &ink_pixbuf_key, pb, NULL); - } else { - g_warning("Received surface which is already owned by GdkPixbuf"); - g_object_ref(pb); - } - - ink_pixbuf_ensure_normal(pb); - - return pb; -} - -/** - * Cleanup function for GdkPixbuf. - * This function should be passed as the GdkPixbufDestroyNotify parameter - * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by - * a Cairo surface. - */ -void ink_cairo_pixbuf_cleanup(guchar * /*pixels*/, void *data) -{ - cairo_surface_t *surface = reinterpret_cast(data); - cairo_surface_destroy(surface); -} - /** * Create an exact copy of a surface. * Creates a surface that has the same type, content type, dimensions and contents @@ -833,6 +1088,44 @@ ink_cairo_pattern_create_checkerboard() return p; } +/** + * Converts the Cairo surface to a GdkPixbuf pixel format, + * without allocating extra memory. + * + * This function is intended mainly for creating previews displayed by GTK. + * For loading images for display on the canvas, use the Inkscape::Pixbuf object. + * + * The returned GdkPixbuf takes ownership of the passed surface reference, + * so it should NOT be freed after calling this function. + */ +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s) +{ + guchar *pixels = cairo_image_surface_get_data(s); + int w = cairo_image_surface_get_width(s); + int h = cairo_image_surface_get_height(s); + int rs = cairo_image_surface_get_stride(s); + + convert_pixels_argb32_to_pixbuf(pixels, w, h, rs); + + GdkPixbuf *pb = gdk_pixbuf_new_from_data( + pixels, GDK_COLORSPACE_RGB, TRUE, 8, + w, h, rs, ink_cairo_pixbuf_cleanup, s); + + return pb; +} + +/** + * Cleanup function for GdkPixbuf. + * This function should be passed as the GdkPixbufDestroyNotify parameter + * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by + * a Cairo surface. + */ +static void ink_cairo_pixbuf_cleanup(guchar * /*pixels*/, void *data) +{ + cairo_surface_t *surface = static_cast(data); + cairo_surface_destroy(surface); +} + /* The following two functions use "from" instead of "to", because when you write: val1 = argb32_from_pixbuf(val1); the name of the format is closer to the value in that format. */ diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index 289d4e01f..505e2ca77 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -12,14 +12,15 @@ #ifndef SEEN_INKSCAPE_DISPLAY_CAIRO_UTILS_H #define SEEN_INKSCAPE_DISPLAY_CAIRO_UTILS_H +#include +//#include // workaround #include #include +//#include #include <2geom/forward.h> #include "style.h" struct SPColor; -struct _GdkPixbuf; -typedef struct _GdkPixbuf GdkPixbuf; namespace Inkscape { @@ -80,15 +81,61 @@ public: static Cairo::RefPtr create(Cairo::RefPtr const &target); }; -} // namespace Inkscape +/** Class to hold image data for raster images. + * Allows easy interoperation with GdkPixbuf and Cairo. */ +class Pixbuf { +public: + enum PixelFormat { + PF_CAIRO = 1, + PF_GDK = 2, + PF_LAST + }; + + explicit Pixbuf(cairo_surface_t *s); + explicit Pixbuf(GdkPixbuf *pb); + Pixbuf(Inkscape::Pixbuf const &other); + ~Pixbuf(); + + GdkPixbuf *getPixbufRaw(bool convert_format = true); + //Glib::RefPtr getPixbuf(bool convert_format = true); + + cairo_surface_t *getSurfaceRaw(bool convert_format = true); + Cairo::RefPtr getSurface(bool convert_format = true); + + int width() const; + int height() const; + int rowstride() const; + guchar const *pixels() const; + guchar *pixels(); + void markDirty(); + + bool hasMimeData() const; + guchar const *getMimeData(gsize &len, std::string &mimetype) const; + std::string const &originalPath() const { return _path; } + time_t modificationTime() const { return _mod_time; } -enum InkPixelFormat { - INK_PIXEL_FORMAT_NONE, - INK_PIXEL_FORMAT_CAIRO, - INK_PIXEL_FORMAT_PIXBUF, - INK_PIXEL_FORMAT_LAST + PixelFormat pixelFormat() const { return _pixel_format; } + void ensurePixelFormat(PixelFormat fmt); + + static Pixbuf *create_from_data_uri(gchar const *uri); + static Pixbuf *create_from_file(std::string const &fn); + +private: + void _ensurePixelsARGB32(); + void _ensurePixelsPixbuf(); + void _forceAlpha(); + void _setMimeData(guchar *data, gsize len, Glib::ustring const &format); + + GdkPixbuf *_pixbuf; + cairo_surface_t *_surface; + time_t _mod_time; + std::string _path; + PixelFormat _pixel_format; + bool _cairo_store; }; +} // namespace Inkscape + // TODO: these declarations may not be needed in the header extern cairo_user_data_key_t ink_color_interpolation_key; extern cairo_user_data_key_t ink_pixbuf_key; @@ -102,7 +149,6 @@ void ink_cairo_set_source_color(cairo_t *ct, SPColor const &color, double opacit void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba); void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m); void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m); -void ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); void ink_matrix_to_2geom(Geom::Affine &, cairo_matrix_t const &); void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Affine const &); @@ -125,13 +171,9 @@ int ink_cairo_surface_linear_to_srgb(cairo_surface_t *surface); cairo_pattern_t *ink_cairo_pattern_create_checkerboard(); +GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s); void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int rs); void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs); -void ink_pixbuf_ensure_argb32(GdkPixbuf *); -void ink_pixbuf_ensure_normal(GdkPixbuf *); -cairo_surface_t *ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb); -GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s); -void ink_cairo_pixbuf_cleanup(guchar *pixels, void *surface); G_GNUC_CONST guint32 argb32_from_pixbuf(guint32 in); G_GNUC_CONST guint32 pixbuf_from_argb32(guint32 in); diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 46f066b8e..0b661a450 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -22,34 +22,23 @@ namespace Inkscape { DrawingImage::DrawingImage(Drawing &drawing) : DrawingItem(drawing) , _pixbuf(NULL) - , _surface(NULL) // this is owned by _pixbuf! , _style(NULL) , _new_surface(NULL) {} DrawingImage::~DrawingImage() { - if (_style) + if (_style) { sp_style_unref(_style); - if (_pixbuf) { - if (_new_surface) cairo_surface_destroy(_new_surface); - g_object_unref(_pixbuf); } + + // _pixbuf is owned by SPImage - do not delete it } void -DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb) +DrawingImage::setPixbuf(Inkscape::Pixbuf *pb) { - // when done in this order, it won't break if pb == image->pixbuf and the refcount is 1 - if (pb != NULL) { - g_object_ref (pb); - } - if (_pixbuf != NULL) { - g_object_unref(_pixbuf); - // unrefing the pixbuf also destroys surface - } _pixbuf = pb; - _surface = pb ? ink_cairo_surface_get_for_pixbuf(pb) : NULL; _markForUpdate(STATE_ALL, false); } @@ -86,8 +75,8 @@ DrawingImage::bounds() const { if (!_pixbuf) return _clipbox; - double pw = gdk_pixbuf_get_width(_pixbuf); - double ph = gdk_pixbuf_get_height(_pixbuf); + double pw = _pixbuf->width(); + double ph = _pixbuf->height(); double vw = pw * _scale[Geom::X]; double vh = ph * _scale[Geom::Y]; Geom::Point wh(vw, vh); @@ -143,14 +132,16 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar // See https://bugs.launchpad.net/inkscape/+bug/804162 Geom::Scale expansion(_ctm.expansion()); - int orgwidth = cairo_image_surface_get_width(_surface); - int orgheight = cairo_image_surface_get_height(_surface); + int orgwidth = _pixbuf->width(); + int orgheight = _pixbuf->height(); if (_scale[Geom::X]*expansion[Geom::X]*orgwidth*255.0<1.0 || _scale[Geom::Y]*expansion[Geom::Y]*orgheight*255.0<1.0) { // Resized image too small to actually see anything return RENDER_OK; } - + + _pixbuf->ensurePixelFormat(Inkscape::Pixbuf::PF_CAIRO); + // Split scale*expansion in a part that is <= 1.0 and a part that is >= 1.0. We only take care of the part <= 1.0. Geom::Scale scaleExpansionSmall(std::min(fabs(_scale[Geom::X]*expansion[Geom::X]),1),std::min(fabs(_scale[Geom::Y]*expansion[Geom::Y]),1)); Geom::Scale scaleExpansionLarge(_scale[Geom::X]*expansion[Geom::X]/scaleExpansionSmall[Geom::X],_scale[Geom::Y]*expansion[Geom::Y]/scaleExpansionSmall[Geom::Y]); @@ -161,7 +152,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar ct.scale(expansion.inverse()); // This should not include scale (see derivation above) ct.translate(_origin*expansion); ct.scale(scaleExpansionLarge); - ct.setSource(_surface, 0, 0); + ct.setSource(_pixbuf->getSurfaceRaw(), 0, 0); } else if (!_new_surface || (newSize-_rescaledSize).length()>0.1) { // Rescaled image is sufficiently different from cached image to recompute if (_new_surface) cairo_surface_destroy(_new_surface); @@ -200,13 +191,13 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar } } + cairo_surface_t *surface = _pixbuf->getSurfaceRaw(); _new_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, newwidth,newheight); - unsigned char * orgdata = cairo_image_surface_get_data(_surface); + unsigned char * orgdata = cairo_image_surface_get_data(surface); unsigned char * newdata = cairo_image_surface_get_data(_new_surface); - int orgstride = cairo_image_surface_get_stride(_surface); + int orgstride = cairo_image_surface_get_stride(surface); int newstride = cairo_image_surface_get_stride(_new_surface); - - //cairo_surface_flush(_surface); + cairo_surface_flush(_new_surface); for(int y=0; ygetSurfaceRaw(), 0, 0); //ct.paint(_opacity); ct.paint(); @@ -315,10 +306,10 @@ DrawingImage::_pickItem(Geom::Point const &p, double delta, unsigned /*sticky*/) return NULL; } else { - unsigned char *const pixels = gdk_pixbuf_get_pixels(_pixbuf); - int width = gdk_pixbuf_get_width(_pixbuf); - int height = gdk_pixbuf_get_height(_pixbuf); - int rowstride = gdk_pixbuf_get_rowstride(_pixbuf); + unsigned char *const pixels = _pixbuf->pixels(); + int width = _pixbuf->width(); + int height = _pixbuf->height(); + int rowstride = _pixbuf->rowstride(); Geom::Point tp = p * _ctm.inverse(); Geom::Rect r = bounds(); @@ -336,8 +327,17 @@ DrawingImage::_pickItem(Geom::Point const &p, double delta, unsigned /*sticky*/) unsigned char *pix_ptr = pixels + iy * rowstride + ix * 4; // pick if the image is less than 99% transparent - float alpha = (pix_ptr[3] / 255.0f) * _opacity; - return alpha > 0.01 ? this : NULL; + guint32 alpha = 0; + if (_pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) { + guint32 px = *reinterpret_cast(pix_ptr); + alpha = (px & 0xff000000) >> 24; + } else if (_pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_GDK) { + alpha = pix_ptr[3]; + } else { + throw std::runtime_error("Unrecognized pixel format"); + } + float alpha_f = (alpha / 255.0f) * _opacity; + return alpha_f > 0.01 ? this : NULL; } } diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h index 593185c97..58e6de72e 100644 --- a/src/display/drawing-image.h +++ b/src/display/drawing-image.h @@ -19,6 +19,7 @@ #include "display/drawing-item.h" namespace Inkscape { +class Pixbuf; class DrawingImage : public DrawingItem @@ -27,7 +28,7 @@ public: DrawingImage(Drawing &drawing); ~DrawingImage(); - void setARGB32Pixbuf(GdkPixbuf *pb); + void setPixbuf(Inkscape::Pixbuf *pb); void setStyle(SPStyle *style); void setScale(double sx, double sy); void setOrigin(Geom::Point const &o); @@ -41,8 +42,7 @@ protected: DrawingItem *stop_at); virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); - GdkPixbuf *_pixbuf; - cairo_surface_t *_surface; + Inkscape::Pixbuf *_pixbuf; SPStyle *_style; cairo_surface_t *_new_surface; // Part of hack around Cairo bug diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index b9d73f0ad..4ca4cd07c 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -30,6 +30,7 @@ FilterImage::FilterImage() : SVGElem(0) , document(0) , feImageHref(0) + , image(0) , broken_ref(false) { } @@ -41,7 +42,7 @@ FilterImage::~FilterImage() { if (feImageHref) g_free(feImageHref); - g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); + delete image; } void FilterImage::render_cairo(FilterSlot &slot) @@ -131,50 +132,38 @@ void FilterImage::render_cairo(FilterSlot &slot) // External image, like if (!image && !broken_ref) { broken_ref = true; - try { - /* TODO: If feImageHref is absolute, then use that (preferably handling the - * case that it's not a file URI). Otherwise, go up the tree looking - * for an xml:base attribute, and use that as the base URI for resolving - * the relative feImageHref URI. Otherwise, if document->base is valid, - * then use that as the base URI. Otherwise, use feImageHref directly - * (i.e. interpreting it as relative to our current working directory). - * (See http://www.w3.org/TR/xmlbase/#resolution .) */ - gchar *fullname = feImageHref; - if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) { - // Try to load from relative postion combined with document base - if( document ) { - fullname = g_build_filename( document->getBase(), feImageHref, NULL ); - } - } - if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) { - // Should display Broken Image png. - g_warning("FilterImage::render: Can not find: %s", feImageHref ); - return; + + /* TODO: If feImageHref is absolute, then use that (preferably handling the + * case that it's not a file URI). Otherwise, go up the tree looking + * for an xml:base attribute, and use that as the base URI for resolving + * the relative feImageHref URI. Otherwise, if document->base is valid, + * then use that as the base URI. Otherwise, use feImageHref directly + * (i.e. interpreting it as relative to our current working directory). + * (See http://www.w3.org/TR/xmlbase/#resolution .) */ + gchar *fullname = feImageHref; + if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) { + // Try to load from relative postion combined with document base + if( document ) { + fullname = g_build_filename( document->getBase(), feImageHref, NULL ); } - image = Gdk::Pixbuf::create_from_file(fullname); - if( fullname != feImageHref ) g_free( fullname ); } - catch (const Glib::FileError & e) - { - g_warning("caught Glib::FileError in FilterImage::render: %s", e.what().data() ); + if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) { + // Should display Broken Image png. + g_warning("FilterImage::render: Can not find: %s", feImageHref ); return; } - catch (const Gdk::PixbufError & e) - { - g_warning("Gdk::PixbufError in FilterImage::render: %s", e.what().data() ); + image = Inkscape::Pixbuf::create_from_file(fullname); + if( fullname != feImageHref ) g_free( fullname ); + + if ( !image ) { + g_warning("FilterImage::render: failed to load image: %s", feImageHref); return; } - if ( !image ) return; broken_ref = false; - - bool has_alpha = image->get_has_alpha(); - if (!has_alpha) { - image = image->add_alpha(false, 0, 0, 0); - } } - cairo_surface_t *image_surface = ink_cairo_surface_get_for_pixbuf(image->gobj()); + cairo_surface_t *image_surface = image->getSurfaceRaw(); Geom::Rect sa = slot.get_slot_area(); cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, @@ -199,7 +188,7 @@ void FilterImage::render_cairo(FilterSlot &slot) // Check aspect ratio of image vs. viewport double feAspect = feImageHeight/feImageWidth; - double aspect = (double)image->get_height()/(double)image->get_width(); + double aspect = (double)image->height()/(double)image->width(); bool ratio = (feAspect < aspect); double ax, ay; // Align side @@ -274,8 +263,8 @@ void FilterImage::render_cairo(FilterSlot &slot) } } - double scaleX = feImageWidth / image->get_width(); - double scaleY = feImageHeight / image->get_height(); + double scaleX = feImageWidth / image->width(); + double scaleY = feImageHeight / image->height(); cairo_translate(ct, feImageX, feImageY); cairo_scale(ct, scaleX, scaleY); @@ -302,8 +291,8 @@ void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; - g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL); - image.reset(); + delete image; + image = NULL; broken_ref = false; } diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index f45f42265..69691ac99 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -12,14 +12,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include #include "display/nr-filter-primitive.h" -#include class SPDocument; class SPItem; namespace Inkscape { +class Pixbuf; + namespace Filters { class FilterSlot; @@ -43,7 +43,7 @@ public: private: SPDocument *document; gchar *feImageHref; - Glib::RefPtr image; + Inkscape::Pixbuf *image; float feImageX, feImageY, feImageWidth, feImageHeight; unsigned int aspect_align, aspect_clip; bool broken_ref; -- cgit v1.2.3 From 23b4c7fcb81ee195acb9bfd470723728f89bfc4a Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Thu, 19 Sep 2013 08:35:32 -0400 Subject: Revert some agressive changes and allow a seperate filter bbox for FER, should be refactored at some point. (bzr r12536) --- src/display/drawing-item.cpp | 8 +++++++- src/display/drawing-item.h | 2 ++ src/display/nr-filter.cpp | 9 ++++++--- 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 097a5fe76..a9836a9e3 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -281,6 +281,12 @@ DrawingItem::setZOrder(unsigned z) _markForRendering(); } +void +DrawingItem::setItemBounds(Geom::OptRect const &bounds) +{ + if (bounds) _filter_bbox = bounds; +} + /** * Update derived data before operations. * The purpose of this call is to recompute internal data which depends @@ -346,7 +352,7 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if (to_update & STATE_BBOX) { // compute drawbox - if (_filter && render_filters) { + if (_filter && render_filters && _bbox) { Geom::IntRect newbox(*_bbox); _filter->area_enlarge(newbox, this); _drawbox = Geom::OptIntRect(newbox); diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index 650653ce2..8020659db 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -89,6 +89,7 @@ public: Geom::OptIntRect geometricBounds() const { return _bbox; } Geom::OptIntRect visualBounds() const { return _drawbox; } + Geom::OptRect filterBounds() const { return _filter_bbox; } Geom::Affine ctm() const { return _ctm; } Geom::Affine transform() const { return _transform ? *_transform : Geom::identity(); } Drawing &drawing() const { return _drawing; } @@ -174,6 +175,7 @@ protected: Geom::Affine _ctm; ///< Total transform from item coords to display coords Geom::OptIntRect _bbox; ///< Bounding box in display (pixel) coords including stroke Geom::OptIntRect _drawbox; ///< Full visual bounding box - enlarged by filters, shrunk by clips and masks + Geom::OptRect _filter_bbox; ///< Used by filters when settings bounds DrawingItem *_clip; DrawingItem *_mask; diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 54bd36168..a0103cbb0 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -115,12 +115,15 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D Geom::Affine trans = item->ctm(); // Get filter are, the filter_effect_area is already done in visualBounds - Geom::OptRect filter_area = item->geometricBounds(); - if (!filter_area) return 1; + Geom::OptRect filter_area = item->filterBounds(); + // Use the geometricBounds as a backup solution + if (!filter_area || (filter_area->hasZeroArea() && + filter_area->min()[Geom::X] == 0 && filter_area->min()[Geom::Y] == 0)) + filter_area = item->geometricBounds(); FilterUnits units(_filter_units, _primitive_units); units.set_ctm(trans); - units.set_item_bbox(item->geometricBounds()); + units.set_item_bbox(filter_area); units.set_filter_area(*filter_area); std::pair resolution -- cgit v1.2.3 From 0191af5c169ac3e3086873f6edbe33dd17800773 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 19 Sep 2013 15:23:02 +0200 Subject: Fix type mismatch for platforms where gsize is not unsigned long (bzr r12537) --- src/display/cairo-utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/display') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 2c7b543c1..451f0b509 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -399,9 +399,9 @@ guchar const *Pixbuf::getMimeData(gsize &len, std::string &mimetype) const for (guint i = 0; i < mimetypes_len; ++i) { unsigned long len_long = 0; - cairo_surface_get_mime_data(const_cast(_surface), mimetypes[i], &data, &len); - len = len_long; // this assumes that the added range of long is not needed. the code below assumes gsize range of values is sufficient. + cairo_surface_get_mime_data(const_cast(_surface), mimetypes[i], &data, &len_long); if (data != NULL) { + len = len_long; mimetype = mimetypes[i]; break; } -- cgit v1.2.3 From d332b7a8d0e55612abc377a107bb1768fc657637 Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Fri, 20 Sep 2013 16:27:08 -0400 Subject: Fix the text filter issue and revert many changes. (bzr r12556) --- src/display/drawing-item.cpp | 19 +++++++++++++------ src/display/drawing-item.h | 1 + src/display/nr-filter.cpp | 4 +--- 3 files changed, 15 insertions(+), 9 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index a9836a9e3..1af07cb44 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -281,8 +281,15 @@ DrawingItem::setZOrder(unsigned z) _markForRendering(); } -void -DrawingItem::setItemBounds(Geom::OptRect const &bounds) +void DrawingItem::setItemBounds(Geom::OptRect const &bounds) +{ + if (!bounds) return; + Geom::IntRect copy = bounds->roundOutwards(); + if (_filter) _filter->area_enlarge(copy, this); + this->setFilterBounds(copy); +} + +void DrawingItem::setFilterBounds(Geom::OptRect const &bounds) { if (bounds) _filter_bbox = bounds; } @@ -352,10 +359,10 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if (to_update & STATE_BBOX) { // compute drawbox - if (_filter && render_filters && _bbox) { - Geom::IntRect newbox(*_bbox); - _filter->area_enlarge(newbox, this); - _drawbox = Geom::OptIntRect(newbox); + if (_filter && render_filters && _filter_bbox) { + Geom::OptRect enlarged = _filter_bbox; + *enlarged *= ctm(); + _drawbox = enlarged->roundOutwards(); } else { _drawbox = _bbox; } diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index 8020659db..c69b996b4 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -113,6 +113,7 @@ public: void setMask(DrawingItem *item); void setZOrder(unsigned z); void setItemBounds(Geom::OptRect const &bounds); + void setFilterBounds(Geom::OptRect const &bounds); void setKey(unsigned key) { _key = key; } unsigned key() const { return _key; } diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index a0103cbb0..c0044c5d8 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -117,9 +117,7 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D // Get filter are, the filter_effect_area is already done in visualBounds Geom::OptRect filter_area = item->filterBounds(); // Use the geometricBounds as a backup solution - if (!filter_area || (filter_area->hasZeroArea() && - filter_area->min()[Geom::X] == 0 && filter_area->min()[Geom::Y] == 0)) - filter_area = item->geometricBounds(); + if (!filter_area) return 1; FilterUnits units(_filter_units, _primitive_units); units.set_ctm(trans); -- cgit v1.2.3 From e6f45cc425825b4326f1c312a84e4845f84b599a Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 25 Sep 2013 12:00:17 +0200 Subject: Proper fix for bug 1127103 (Filter changes color when object flipped.) (bzr r12590) --- src/display/nr-filter-slot.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index fe67972d6..755a30a74 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -83,11 +83,15 @@ cairo_surface_t *FilterSlot::getcairo(int slot_nr) switch (slot_nr) { case NR_FILTER_SOURCEGRAPHIC: { cairo_surface_t *tr = _get_transformed_source_graphic(); + // Assume all source graphics are sRGB + set_cairo_surface_ci( tr, SP_CSS_COLOR_INTERPOLATION_SRGB ); _set_internal(NR_FILTER_SOURCEGRAPHIC, tr); cairo_surface_destroy(tr); } break; case NR_FILTER_BACKGROUNDIMAGE: { cairo_surface_t *bg = _get_transformed_background(); + // Assume all backgrounds are sRGB + set_cairo_surface_ci( bg, SP_CSS_COLOR_INTERPOLATION_SRGB ); _set_internal(NR_FILTER_BACKGROUNDIMAGE, bg); cairo_surface_destroy(bg); } break; @@ -129,9 +133,6 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic() if (trans.isTranslation()) { cairo_surface_reference(_source_graphic); - - // Assume all source graphics are sRGB - set_cairo_surface_ci( _source_graphic, SP_CSS_COLOR_INTERPOLATION_SRGB ); return _source_graphic; } @@ -148,8 +149,6 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic() cairo_paint(tsg_ct); cairo_destroy(tsg_ct); - // Assume all source graphics are sRGB - set_cairo_surface_ci( tsg, SP_CSS_COLOR_INTERPOLATION_SRGB ); return tsg; } @@ -177,17 +176,15 @@ cairo_surface_t *FilterSlot::_get_transformed_background() tbg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _slot_w, _slot_h); } - // Assume all source graphics are sRGB - set_cairo_surface_ci( tbg, SP_CSS_COLOR_INTERPOLATION_SRGB ); - return tbg; } cairo_surface_t *FilterSlot::get_result(int res) { + cairo_surface_t *result = getcairo(res); + Geom::Affine trans = _units.get_matrix_pb2display(); if (trans.isIdentity()) { - cairo_surface_t *result = getcairo(res); cairo_surface_reference(result); return result; } @@ -196,12 +193,13 @@ cairo_surface_t *FilterSlot::get_result(int res) cairo_surface_get_content(_source_graphic), _source_graphic_area.width(), _source_graphic_area.height()); + copy_cairo_surface_ci( result, r ); cairo_t *r_ct = cairo_create(r); cairo_translate(r_ct, -_source_graphic_area.left(), -_source_graphic_area.top()); ink_cairo_transform(r_ct, trans); cairo_translate(r_ct, _slot_x, _slot_y); - cairo_set_source_surface(r_ct, getcairo(res), 0, 0); + cairo_set_source_surface(r_ct, result, 0, 0); cairo_set_operator(r_ct, CAIRO_OPERATOR_SOURCE); cairo_paint(r_ct); cairo_destroy(r_ct); -- cgit v1.2.3 From 2faa250b2e8a9ce2f1bd29a38024a368d5d379c9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 27 Sep 2013 00:19:14 +0200 Subject: The downscaling fix is already in Cairo trunk. Therefore, remove the image scaling hack from drawing-image.cpp. (bzr r12599) --- src/display/drawing-image.cpp | 121 ++---------------------------------------- src/display/drawing-image.h | 3 -- 2 files changed, 4 insertions(+), 120 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 0b661a450..a9c0499c2 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -23,7 +23,6 @@ DrawingImage::DrawingImage(Drawing &drawing) : DrawingItem(drawing) , _pixbuf(NULL) , _style(NULL) - , _new_surface(NULL) {} DrawingImage::~DrawingImage() @@ -123,123 +122,11 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar ct.rectangle(_clipbox); ct.clip(); - ///////////////////////////////////////////////////////////////////////////// - // BEGIN: Hack to avoid Cairo bug - // The total transform (which is RIGHT-multiplied with the item points to get display points) equals: - // scale*translate_origin*_ctm = scale*translate(origin)*expansion*expansionInv*_ctm - // = scale*expansion*translate(origin*expansion)*expansionInv*_ctm - // To avoid a Cairo bug, we handle the scale*expansion part ourselves. - // See https://bugs.launchpad.net/inkscape/+bug/804162 - - Geom::Scale expansion(_ctm.expansion()); - int orgwidth = _pixbuf->width(); - int orgheight = _pixbuf->height(); - - if (_scale[Geom::X]*expansion[Geom::X]*orgwidth*255.0<1.0 || _scale[Geom::Y]*expansion[Geom::Y]*orgheight*255.0<1.0) { - // Resized image too small to actually see anything - return RENDER_OK; - } - - _pixbuf->ensurePixelFormat(Inkscape::Pixbuf::PF_CAIRO); - - // Split scale*expansion in a part that is <= 1.0 and a part that is >= 1.0. We only take care of the part <= 1.0. - Geom::Scale scaleExpansionSmall(std::min(fabs(_scale[Geom::X]*expansion[Geom::X]),1),std::min(fabs(_scale[Geom::Y]*expansion[Geom::Y]),1)); - Geom::Scale scaleExpansionLarge(_scale[Geom::X]*expansion[Geom::X]/scaleExpansionSmall[Geom::X],_scale[Geom::Y]*expansion[Geom::Y]/scaleExpansionSmall[Geom::Y]); - - Geom::Point newSize(Geom::Point(orgwidth,orgheight)*scaleExpansionSmall); - if ((newSize-Geom::Point(orgwidth,orgheight)).length()<0.1) { - // Just use _surface directly. - ct.scale(expansion.inverse()); // This should not include scale (see derivation above) - ct.translate(_origin*expansion); - ct.scale(scaleExpansionLarge); - ct.setSource(_pixbuf->getSurfaceRaw(), 0, 0); - } else if (!_new_surface || (newSize-_rescaledSize).length()>0.1) { - // Rescaled image is sufficiently different from cached image to recompute - if (_new_surface) cairo_surface_destroy(_new_surface); - _rescaledSize = newSize; - - // This essentially considers an image to be composed of rectangular pixels (box kernel) and computes the least-squares approximation of the original. - // When the scale factor is really large or small this essentially results in using a box filter, while for scale factors approaching 1 it is more like a "tent" kernel. - // Although the quality of the result is not great, it is typically better than an ordinary box filter, and it is guaranteed to preserve the overall brightness of the image. - // The best improvement would probably be to do the same kind of thing based on a tent kernel, but that's quite a bit more complicated, and probably not worth the trouble for a hack like this. - int newwidth = static_cast(floor(orgwidth*scaleExpansionSmall[Geom::X])+1); - int newheight = static_cast(floor(orgheight*scaleExpansionSmall[Geom::Y])+1); - std::vector xBegin(newwidth, -1), yBegin(newheight, -1); - std::vector< std::vector > xCoefs(xBegin.size()), yCoefs(yBegin.size()); - for(int x=0; x(scaleExpansionSmall[Geom::X]); // x-coord in target coordinates where the current source pixel begins - double coordEnd = (x+1)*static_cast(scaleExpansionSmall[Geom::X]); // x-coord in target coordinates where the current source pixel ends - int begin = static_cast(floor(coordBegin)); // First pixel (x-coord) affected by the current source pixel - int end = static_cast(ceil(coordEnd)); // First pixel (x-coord) NOT affected by the current source pixel (a zero contribution is counted as not affecting the pixel) - for(int nx=begin; nx(std::min(nx+1,coordEnd) - std::max(nx,coordBegin))); - } - } - for(int y=0; y(scaleExpansionSmall[Geom::Y]); // y-coord in target coordinates where the current source pixel begins - double coordEnd = (y+1)*static_cast(scaleExpansionSmall[Geom::Y]); // y-coord in target coordinates where the current source pixel ends - int begin = static_cast(floor(coordBegin)); // First pixel (y-coord) affected by the current source pixel - int end = static_cast(ceil(coordEnd)); // First pixel (y-coord) NOT affected by the current source pixel (a zero contribution is counted as not affecting the pixel) - for(int ny=begin; ny(std::min(ny+1,coordEnd) - std::max(ny,coordBegin))); - } - } - - cairo_surface_t *surface = _pixbuf->getSurfaceRaw(); - _new_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, newwidth,newheight); - unsigned char * orgdata = cairo_image_surface_get_data(surface); - unsigned char * newdata = cairo_image_surface_get_data(_new_surface); - int orgstride = cairo_image_surface_get_stride(surface); - int newstride = cairo_image_surface_get_stride(_new_surface); - - cairo_surface_flush(_new_surface); - - for(int y=0; y(yCoefs[y].size()); oy++) { - for(int ox=0; ox(xCoefs[x].size()); ox++) { - for(int c=0; c<4; c++) { - tempSum[c] += xCoefs[x][ox]*yCoefs[y][oy]*orgdata[c+4*(xBegin[x]+ox)+orgstride*(yBegin[y]+oy)]; - } - } - } - for(int c=0; c<4; c++) { - newdata[c+4*x+newstride*y] = static_cast(tempSum[c]); - } - } - } - - cairo_surface_mark_dirty(_new_surface); - - ct.scale(expansion.inverse()); // This should not include scale (see derivation above) - ct.translate(_origin*expansion); - ct.scale(scaleExpansionLarge); - ct.setSource(_new_surface, 0, 0); - } else { - // No need to regenerate, but we do draw from _new_surface. - ct.scale(expansion.inverse()); // This should not include scale (see derivation above) - ct.translate(_origin*expansion); - ct.scale(scaleExpansionLarge); - ct.setSource(_new_surface, 0, 0); - } - - // END: Hack to avoid Cairo bug - ///////////////////////////////////////////////////////////////////////////// - - // TODO: If Cairo's problems are gone, uncomment the following: - //ct.translate(_origin); - //ct.scale(_scale); - //ct.setSource(_pixbuf->getSurfaceRaw(), 0, 0); + ct.translate(_origin); + ct.scale(_scale); + ct.setSource(_pixbuf->getSurfaceRaw(), 0, 0); - //ct.paint(_opacity); - ct.paint(); + ct.paint(_opacity); } else { // outline; draw a rect instead Inkscape::Preferences *prefs = Inkscape::Preferences::get(); diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h index 58e6de72e..cebaafc85 100644 --- a/src/display/drawing-image.h +++ b/src/display/drawing-image.h @@ -45,9 +45,6 @@ protected: Inkscape::Pixbuf *_pixbuf; SPStyle *_style; - cairo_surface_t *_new_surface; // Part of hack around Cairo bug - Geom::Point _rescaledSize; // Part of hack around Cairo bug - // TODO: the following three should probably be merged into a new Geom::Viewbox object Geom::Rect _clipbox; ///< for preserveAspectRatio Geom::Point _origin; -- cgit v1.2.3 From 81209cb6fe83ccf8cb1244fe63f93361f68cc7c0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 27 Sep 2013 00:42:32 +0200 Subject: Use Cairo 1.10 blend operators to render feBlend (bzr r12600) --- src/display/nr-filter-blend.cpp | 164 ++++++++-------------------------------- 1 file changed, 30 insertions(+), 134 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index a08191f67..bff7405b7 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -1,6 +1,6 @@ -/* +/** @file * SVG feBlend renderer - * + *//* * "This filter composites two objects together using commonly used * imaging software blending modes. It performs a pixel-wise combination * of two input images." @@ -9,6 +9,7 @@ * Authors: * Niko Kiirala * Jasper van de Gronde + * Krzysztof KosiƄski * * Copyright (C) 2007-2008 authors * @@ -30,20 +31,6 @@ namespace Inkscape { namespace Filters { -/* - * From http://www.w3.org/TR/SVG11/filters.html#feBlend - * - * For all feBlend modes, the result opacity is computed as follows: - * qr = 1 - (1-qa)*(1-qb) - * - * For the compositing formulas below, the following definitions apply: - * cr = Result color (RGB) - premultiplied - * qa = Opacity value at a given pixel for image A - * qb = Opacity value at a given pixel for image B - * ca = Color (RGB) at a given pixel for image A - premultiplied - * cb = Color (RGB) at a given pixel for image B - premultiplied - */ - FilterBlend::FilterBlend() : _blend_mode(BLEND_NORMAL), _input2(NR_FILTER_SLOT_NOT_SET) @@ -56,91 +43,6 @@ FilterPrimitive * FilterBlend::create() { FilterBlend::~FilterBlend() {} -// cr = (1-qa)*cb + (1-qb)*ca + ca*cb -struct BlendMultiply { - guint32 operator()(guint32 in1, guint32 in2) - { - EXTRACT_ARGB32(in1, aa, ra, ga, ba) - EXTRACT_ARGB32(in2, ab, rb, gb, bb) - - guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255; - guint32 ro = (255-aa)*rb + (255-ab)*ra + ra*rb; ro = (ro + 127) / 255; - guint32 go = (255-aa)*gb + (255-ab)*ga + ga*gb; go = (go + 127) / 255; - guint32 bo = (255-aa)*bb + (255-ab)*ba + ba*bb; bo = (bo + 127) / 255; - - ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) - return pxout; - } -}; - -// cr = cb + ca - ca * cb -struct BlendScreen { - guint32 operator()(guint32 in1, guint32 in2) - { - EXTRACT_ARGB32(in1, aa, ra, ga, ba) - EXTRACT_ARGB32(in2, ab, rb, gb, bb) - - guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255; - guint32 ro = 255*(rb + ra) - ra * rb; ro = (ro + 127) / 255; - guint32 go = 255*(gb + ga) - ga * gb; go = (go + 127) / 255; - guint32 bo = 255*(bb + ba) - ba * bb; bo = (bo + 127) / 255; - - ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) - return pxout; - } -}; - -// cr = Min ((1 - qa) * cb + ca, (1 - qb) * ca + cb) -struct BlendDarken { - guint32 operator()(guint32 in1, guint32 in2) - { - EXTRACT_ARGB32(in1, aa, ra, ga, ba) - EXTRACT_ARGB32(in2, ab, rb, gb, bb) - - guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255; - guint32 ro = std::min((255-aa)*rb + 255*ra, (255-ab)*ra + 255*rb); ro = (ro + 127) / 255; - guint32 go = std::min((255-aa)*gb + 255*ga, (255-ab)*ga + 255*gb); go = (go + 127) / 255; - guint32 bo = std::min((255-aa)*bb + 255*ba, (255-ab)*ba + 255*bb); bo = (bo + 127) / 255; - - ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) - return pxout; - } -}; - -// cr = Max ((1 - qa) * cb + ca, (1 - qb) * ca + cb) -struct BlendLighten { - guint32 operator()(guint32 in1, guint32 in2) - { - EXTRACT_ARGB32(in1, aa, ra, ga, ba) - EXTRACT_ARGB32(in2, ab, rb, gb, bb) - - guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255; - guint32 ro = std::max((255-aa)*rb + 255*ra, (255-ab)*ra + 255*rb); ro = (ro + 127) / 255; - guint32 go = std::max((255-aa)*gb + 255*ga, (255-ab)*ga + 255*gb); go = (go + 127) / 255; - guint32 bo = std::max((255-aa)*bb + 255*ba, (255-ab)*ba + 255*bb); bo = (bo + 127) / 255; - - ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) - return pxout; - } -}; - -/* -struct BlendAlpha -static inline void blend_alpha(guint32 in1, guint32 in2, guint32 *out) -{ - EXTRACT_ARGB32(in1, a1, a2, a3, a4); - EXTRACT_ARGB32(in2, b1, b2, b3, b4); - - guint32 o1 = 255*255 - (255-a1)*(255-b1); o1 = (o1+127) / 255; - guint32 o2 = 255*255 - (255-a2)*(255-b2); o2 = (o2+127) / 255; - guint32 o3 = 255*255 - (255-a3)*(255-b3); o3 = (o3+127) / 255; - guint32 o4 = 255*255 - (255-a4)*(255-b4); o4 = (o4+127) / 255; - - ASSEMBLE_ARGB32(pxout, o1, o2, o3, o4); - *out = pxout; -} -*/ - void FilterBlend::render_cairo(FilterSlot &slot) { cairo_surface_t *input1 = slot.getcairo(_input); @@ -161,41 +63,35 @@ void FilterBlend::render_cairo(FilterSlot &slot) cairo_surface_t *out = ink_cairo_surface_create_output(input1, input2); set_cairo_surface_ci( out, ci_fp ); - cairo_content_t ct1 = cairo_surface_get_content(input1); - cairo_content_t ct2 = cairo_surface_get_content(input2); - if ((ct1 == CAIRO_CONTENT_ALPHA && ct2 == CAIRO_CONTENT_ALPHA) - || _blend_mode == BLEND_NORMAL) - { - ink_cairo_surface_blit(input2, out); - cairo_t *out_ct = cairo_create(out); - cairo_set_source_surface(out_ct, input1, 0, 0); - cairo_paint(out_ct); - cairo_destroy(out_ct); - } else { - // blend mode != normal and at least 1 surface is not pure alpha - - // TODO: convert to Cairo blending operators once we start using the 1.10 series - switch (_blend_mode) { - case BLEND_MULTIPLY: - ink_cairo_surface_blend(input1, input2, out, BlendMultiply()); - break; - case BLEND_SCREEN: - ink_cairo_surface_blend(input1, input2, out, BlendScreen()); - break; - case BLEND_DARKEN: - ink_cairo_surface_blend(input1, input2, out, BlendDarken()); - break; - case BLEND_LIGHTEN: - ink_cairo_surface_blend(input1, input2, out, BlendLighten()); - break; - case BLEND_NORMAL: - default: - // this was handled before - g_assert_not_reached(); - break; - } + ink_cairo_surface_blit(input2, out); + cairo_t *out_ct = cairo_create(out); + cairo_set_source_surface(out_ct, input1, 0, 0); + + // All of the blend modes are implemented in Cairo as of 1.10. + // For a detailed description, see: + // http://cairographics.org/operators/ + switch (_blend_mode) { + case BLEND_MULTIPLY: + cairo_set_operator(out_ct, CAIRO_OPERATOR_MULTIPLY); + break; + case BLEND_SCREEN: + cairo_set_operator(out_ct, CAIRO_OPERATOR_SCREEN); + break; + case BLEND_DARKEN: + cairo_set_operator(out_ct, CAIRO_OPERATOR_DARKEN); + break; + case BLEND_LIGHTEN: + cairo_set_operator(out_ct, CAIRO_OPERATOR_LIGHTEN); + break; + case BLEND_NORMAL: + default: + cairo_set_operator(out_ct, CAIRO_OPERATOR_OVER); + break; } + cairo_paint(out_ct); + cairo_destroy(out_ct); + slot.set(_output, out); cairo_surface_destroy(out); } -- cgit v1.2.3 From a5e764ae43d4b3ba1d7cb63c9cfdb3f1b9e1b13e Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Sat, 28 Sep 2013 00:12:30 -0400 Subject: Allow pixmaps to specify their width and height to control/knots. Allows non-square nodes. (bzr r12605) --- src/display/sodipodi-ctrl.cpp | 191 +++++++++++++++++------------------------- src/display/sodipodi-ctrl.h | 4 +- 2 files changed, 78 insertions(+), 117 deletions(-) (limited to 'src/display') diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index 45dc38a37..3636319df 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -108,81 +108,50 @@ sp_ctrl_set_property(GObject *object, guint prop_id, const GValue *value, GParam ctrl = SP_CTRL (object); switch (prop_id) { - case ARG_SHAPE: { - ctrl->shape = (SPCtrlShapeType) g_value_get_int(value); - ctrl->build = FALSE; - sp_canvas_item_request_update(item); - } - break; - - case ARG_MODE: { - ctrl->mode = (SPCtrlModeType) g_value_get_int(value); - ctrl->build = FALSE; - sp_canvas_item_request_update(item); - } - break; - - case ARG_ANCHOR: { - ctrl->anchor = (SPAnchorType) g_value_get_int(value); - ctrl->build = FALSE; - sp_canvas_item_request_update(item); - } - break; - - case ARG_SIZE: { - ctrl->span = (gint)((g_value_get_double(value) - 1.0) / 2.0 + 0.5); - ctrl->defined = (ctrl->span > 0); - ctrl->build = FALSE; - sp_canvas_item_request_update(item); - } - break; - - case ARG_FILLED: { - ctrl->filled = g_value_get_boolean(value); - ctrl->build = FALSE; - sp_canvas_item_request_update(item); - } - break; - - case ARG_FILL_COLOR: { - guint32 fill = g_value_get_int(value); - ctrl->fill_color = fill; - ctrl->build = FALSE; - sp_canvas_item_request_update(item); - } - break; - - case ARG_STROKED: { - ctrl->stroked = g_value_get_boolean(value); - ctrl->build = FALSE; - sp_canvas_item_request_update(item); - } - break; - - case ARG_STROKE_COLOR: { - guint32 stroke = g_value_get_int(value); - ctrl->stroke_color = stroke; - ctrl->build = FALSE; - sp_canvas_item_request_update(item); - } - break; - - case ARG_PIXBUF: { - pixbuf = (GdkPixbuf*) g_value_get_pointer(value); - if (gdk_pixbuf_get_has_alpha(pixbuf)) { - ctrl->pixbuf = pixbuf; - } else { - ctrl->pixbuf = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0); - g_object_unref(pixbuf); - } - ctrl->build = FALSE; - } - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; + case ARG_SHAPE: + ctrl->shape = (SPCtrlShapeType) g_value_get_int(value); + break; + case ARG_MODE: + ctrl->mode = (SPCtrlModeType) g_value_get_int(value); + break; + case ARG_ANCHOR: + ctrl->anchor = (SPAnchorType) g_value_get_int(value); + break; + case ARG_SIZE: + ctrl->width = (gint)(g_value_get_double(value) / 2.0); + ctrl->height = ctrl->width; + ctrl->defined = (ctrl->width > 0); + break; + case ARG_FILLED: + ctrl->filled = g_value_get_boolean(value); + break; + case ARG_FILL_COLOR: + ctrl->fill_color = (guint32)g_value_get_int(value); + break; + case ARG_STROKED: + ctrl->stroked = g_value_get_boolean(value); + break; + case ARG_STROKE_COLOR: + ctrl->stroke_color = (guint32)g_value_get_int(value); + break; + case ARG_PIXBUF: + pixbuf = (GdkPixbuf*) g_value_get_pointer(value); + // A pixbuf defines it's own size, don't mess about with size. + ctrl->width = gdk_pixbuf_get_width(pixbuf) / 2.0; + ctrl->height = gdk_pixbuf_get_height(pixbuf) / 2.0; + if (gdk_pixbuf_get_has_alpha(pixbuf)) { + ctrl->pixbuf = pixbuf; + } else { + ctrl->pixbuf = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0); + g_object_unref(pixbuf); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + return; // Do not do an update } + ctrl->build = FALSE; + sp_canvas_item_request_update(item); } static void @@ -206,7 +175,7 @@ sp_ctrl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec break; case ARG_SIZE: - g_value_set_double(value, ctrl->span); + g_value_set_double(value, ctrl->width); break; case ARG_FILLED: @@ -241,7 +210,8 @@ sp_ctrl_init (SPCtrl *ctrl) ctrl->shape = SP_CTRL_SHAPE_SQUARE; ctrl->mode = SP_CTRL_MODE_COLOR; ctrl->anchor = SP_ANCHOR_CENTER; - ctrl->span = 3; + ctrl->width = 3; + ctrl->height = 3; ctrl->defined = TRUE; ctrl->shown = FALSE; ctrl->build = FALSE; @@ -250,12 +220,6 @@ sp_ctrl_init (SPCtrl *ctrl) ctrl->fill_color = 0x000000ff; ctrl->stroke_color = 0x000000ff; - // This way we make sure that the first sp_ctrl_update() call finishes properly; - // in subsequent calls it will not update anything it the control hasn't moved - // Consider for example the case in which a snap indicator is drawn at (0, 0); - // If moveto() is called then it will not set _moved to true because we're initially already at (0, 0) - ctrl->_moved = true; // Is this flag ever going to be set back to false? I can't find where that is supposed to happen - new (&ctrl->box) Geom::IntRect(0,0,0,0); ctrl->cache = NULL; ctrl->pixbuf = NULL; @@ -292,16 +256,14 @@ sp_ctrl_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int fla sp_canvas_item_reset_bounds (item); - if (!ctrl->_moved) return; - if (ctrl->shown) { item->canvas->requestRedraw(ctrl->box.left(), ctrl->box.top(), ctrl->box.right() + 1, ctrl->box.bottom() + 1); } if (!ctrl->defined) return; - x = (gint) ((affine[4] > 0) ? (affine[4] + 0.5) : (affine[4] - 0.5)) - ctrl->span; - y = (gint) ((affine[5] > 0) ? (affine[5] + 0.5) : (affine[5] - 0.5)) - ctrl->span; + x = (gint) ((affine[4] > 0) ? (affine[4] + 0.5) : (affine[4] - 0.5)) - ctrl->width; + y = (gint) ((affine[5] > 0) ? (affine[5] + 0.5) : (affine[5] - 0.5)) - ctrl->height; switch (ctrl->anchor) { case SP_ANCHOR_N: @@ -312,13 +274,13 @@ sp_ctrl_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int fla case SP_ANCHOR_NW: case SP_ANCHOR_W: case SP_ANCHOR_SW: - x += ctrl->span; + x += ctrl->width; break; case SP_ANCHOR_NE: case SP_ANCHOR_E: case SP_ANCHOR_SE: - x -= (ctrl->span + 1); + x -= (ctrl->width + 1); break; } @@ -331,17 +293,17 @@ sp_ctrl_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int fla case SP_ANCHOR_NW: case SP_ANCHOR_N: case SP_ANCHOR_NE: - y += ctrl->span; + y += ctrl->height; break; case SP_ANCHOR_SW: case SP_ANCHOR_S: case SP_ANCHOR_SE: - y -= (ctrl->span + 1); + y -= (ctrl->height + 1); break; } - ctrl->box = Geom::IntRect::from_xywh(x, y, 2*ctrl->span, 2*ctrl->span); + ctrl->box = Geom::IntRect::from_xywh(x, y, 2*ctrl->width, 2*ctrl->height); sp_canvas_update_bbox (item, ctrl->box.left(), ctrl->box.top(), ctrl->box.right() + 1, ctrl->box.bottom() + 1); } @@ -360,7 +322,7 @@ static void sp_ctrl_build_cache (SPCtrl *ctrl) { guint32 *p, *q; - gint size, x, y, z, s, a, side, c; + gint size, x, y, z, s, a, width, height, c; guint32 stroke_color, fill_color; if (ctrl->filled) { @@ -382,11 +344,11 @@ sp_ctrl_build_cache (SPCtrl *ctrl) stroke_color = fill_color; } - - side = (ctrl->span * 2 +1); - c = ctrl->span; - size = side * side; - if (side < 2) return; + width = (ctrl->width * 2 +1); + height = (ctrl->height * 2 +1); + c = ctrl->width; // Only used for pre-set square drawing + size = width * height; + if (width < 2) return; if (ctrl->cache) delete[] ctrl->cache; ctrl->cache = new guint32[size]; @@ -395,19 +357,19 @@ sp_ctrl_build_cache (SPCtrl *ctrl) case SP_CTRL_SHAPE_SQUARE: p = ctrl->cache; // top edge - for (x=0; x < side; x++) { + for (x=0; x < width; x++) { *p++ = stroke_color; } // middle - for (y = 2; y < side; y++) { + for (y = 2; y < height; y++) { *p++ = stroke_color; // stroke at first and last pixel - for (x=2; x < side; x++) { + for (x=2; x < width; x++) { *p++ = fill_color; // fill in the middle } *p++ = stroke_color; } // bottom edge - for (x=0; x < side; x++) { + for (x=0; x < width; x++) { *p++ = stroke_color; } ctrl->build = TRUE; @@ -415,19 +377,19 @@ sp_ctrl_build_cache (SPCtrl *ctrl) case SP_CTRL_SHAPE_DIAMOND: p = ctrl->cache; - for (y = 0; y < side; y++) { + for (y = 0; y < height; y++) { z = abs (c - y); for (x = 0; x < z; x++) { *p++ = 0; } *p++ = stroke_color; x++; - for (; x < side - z -1; x++) { + for (; x < width - z -1; x++) { *p++ = fill_color; } if (z != c) { *p++ = stroke_color; x++; } - for (; x < side; x++) { + for (; x < width; x++) { *p++ = 0; } } @@ -462,7 +424,7 @@ sp_ctrl_build_cache (SPCtrl *ctrl) *q-- = stroke_color; x++; } while (x <= c+z); - while (x < side) { + while (x < width) { *p++ = 0; *q-- = 0; x++; @@ -474,7 +436,7 @@ sp_ctrl_build_cache (SPCtrl *ctrl) case SP_CTRL_SHAPE_CROSS: p = ctrl->cache; - for (y = 0; y < side; y++) { + for (y = 0; y < height; y++) { z = abs (c - y); for (x = 0; x < c-z; x++) { *p++ = 0; @@ -486,7 +448,7 @@ sp_ctrl_build_cache (SPCtrl *ctrl) if (z != 0) { *p++ = stroke_color; x++; } - for (; x < side; x++) { + for (; x < width; x++) { *p++ = 0; } } @@ -499,12 +461,12 @@ sp_ctrl_build_cache (SPCtrl *ctrl) unsigned int rs; px = gdk_pixbuf_get_pixels (ctrl->pixbuf); rs = gdk_pixbuf_get_rowstride (ctrl->pixbuf); - for (y = 0; y < side; y++){ + for (y = 0; y < height; y++){ guint32 *d; unsigned char *s; s = px + y * rs; - d = ctrl->cache + side * y; - for (x = 0; x < side; x++) { + d = ctrl->cache + height * y; + for (x = 0; x < width; x++) { if (s[3] < 0x80) { *d++ = 0; } else if (s[0] < 0x80) { @@ -527,9 +489,9 @@ sp_ctrl_build_cache (SPCtrl *ctrl) guint32 *px; guchar *data = gdk_pixbuf_get_pixels (ctrl->pixbuf); p = ctrl->cache; - for (y = 0; y < side; y++){ + for (y = 0; y < height; y++){ px = reinterpret_cast(data + y * r); - for (x = 0; x < side; x++) { + for (x = 0; x < width; x++) { *p++ = *px++; } } @@ -566,8 +528,8 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) sp_ctrl_build_cache (ctrl); } - int w, h; - w = h = (ctrl->span * 2 +1); + int w = (ctrl->width * 2 + 1); + int h = (ctrl->height * 2 + 1); // The code below works even when the target is not an image surface if (ctrl->mode == SP_CTRL_MODE_XOR) { @@ -627,7 +589,6 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) void SPCtrl::moveto (Geom::Point const p) { if (p != _point) { sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (this), Geom::Affine(Geom::Translate (p))); - _moved = true; } _point = p; } diff --git a/src/display/sodipodi-ctrl.h b/src/display/sodipodi-ctrl.h index cd0fcadf1..ecdb896a7 100644 --- a/src/display/sodipodi-ctrl.h +++ b/src/display/sodipodi-ctrl.h @@ -37,7 +37,8 @@ struct SPCtrl : public SPCanvasItem { SPCtrlShapeType shape; SPCtrlModeType mode; SPAnchorType anchor; - gint span; + gint width; + gint height; guint defined : 1; guint shown : 1; guint build : 1; @@ -45,7 +46,6 @@ struct SPCtrl : public SPCanvasItem { guint stroked : 1; guint32 fill_color; guint32 stroke_color; - bool _moved; Geom::IntRect box; /* NB! x1 & y1 are included */ guint32 *cache; -- cgit v1.2.3 From bf4e68d81307463eea90914566f6d6611688bb04 Mon Sep 17 00:00:00 2001 From: buliabyak <> Date: Sat, 28 Sep 2013 20:58:11 -0300 Subject: clear paints on delete to release reffed paintservers, fixes leaking of gradients (bzr r12623) --- src/display/nr-style.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/display') diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index cd7e9575f..317f38635 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -77,6 +77,8 @@ NRStyle::~NRStyle() if (dash){ delete [] dash; } + fill.clear(); + stroke.clear(); } void NRStyle::set(SPStyle *style) -- cgit v1.2.3 From 1e82781408cc335ca29946a4de10349d868d65be Mon Sep 17 00:00:00 2001 From: buliabyak <> Date: Sat, 28 Sep 2013 20:58:48 -0300 Subject: fix leaking of transforms (bzr r12624) --- src/display/drawing-group.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/display') diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp index 6d52b89fc..b5ce18891 100644 --- a/src/display/drawing-group.cpp +++ b/src/display/drawing-group.cpp @@ -28,6 +28,7 @@ DrawingGroup::~DrawingGroup() { if (_style) sp_style_unref(_style); + delete _child_transform; // delete NULL; is safe } /** -- cgit v1.2.3 From 799f473597d4eb61d843c37b2e294824c919db73 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 30 Sep 2013 21:59:36 +0200 Subject: fix memleak (bzr r12633) --- src/display/guideline.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/display') diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp index f71bc82ef..55c1ee495 100644 --- a/src/display/guideline.cpp +++ b/src/display/guideline.cpp @@ -94,14 +94,20 @@ static void sp_guideline_destroy(SPCanvasItem *object) g_return_if_fail (SP_IS_GUIDELINE (object)); //g_return_if_fail (SP_GUIDELINE(object)->origin != NULL); //g_return_if_fail (SP_IS_CTRLPOINT(SP_GUIDELINE(object)->origin)); - - if (SP_GUIDELINE(object)->origin != NULL && SP_IS_CTRLPOINT(SP_GUIDELINE(object)->origin)) { - sp_canvas_item_destroy(SP_GUIDELINE(object)->origin); + + SPGuideLine *gl = SP_GUIDELINE(object); + + if (gl->origin != NULL && SP_IS_CTRLPOINT(gl->origin)) { + sp_canvas_item_destroy(gl->origin); } else { // FIXME: This branch shouldn't be reached (although it seems to be harmless). //g_error("Why can it be that gl->origin is not a valid SPCtrlPoint?\n"); } + if (gl->label) { + g_free(gl->label); + } + SP_CANVAS_ITEM_CLASS(parent_class)->destroy(object); } -- cgit v1.2.3 From 5cf6f3cac4b8dce6a3059c2547cf376fd382e741 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 1 Oct 2013 02:55:12 +0200 Subject: Minor improvements to DrawingItem code and documentation (bzr r12645) --- src/display/drawing-item.cpp | 45 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 1af07cb44..526fc3000 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -141,7 +141,11 @@ DrawingItem::appendChild(DrawingItem *item) assert(item->_child_type == CHILD_ORPHAN); item->_child_type = CHILD_NORMAL; _children.push_back(*item); - _markForUpdate(STATE_ALL, false); + // Because _markForUpdate recurses through ancestors, we can simply call it + // on the just-added child. This has the additional benefit that we do not + // rely on the appended child being in the default non-updated state. + // We set propagate to true, because the child might have descendants of its own. + item->_markForUpdate(STATE_ALL, true); } void @@ -151,7 +155,8 @@ DrawingItem::prependChild(DrawingItem *item) assert(item->_child_type == CHILD_ORPHAN); item->_child_type = CHILD_NORMAL; _children.push_front(*item); - _markForUpdate(STATE_ALL, false); + // See appendChild for explanation + item->_markForUpdate(STATE_ALL, true); } /// Delete all regular children of this item (not mask or clip). @@ -714,8 +719,11 @@ DrawingItem::pick(Geom::Point const &p, double delta, unsigned flags) { // Sometimes there's no BBOX in state, reason unknown (bug 992817) // I made this not an assert to remove the warning - if (!(_state & STATE_BBOX) || !(_state & STATE_PICK)) + if (!(_state & STATE_BBOX) || !(_state & STATE_PICK)) { + g_warning("Invalid state when picking: STATE_BBOX = %d, STATE_PICK = %d", + _state & STATE_BBOX, _state & STATE_PICK); return NULL; + } // ignore invisible and insensitive items unless sticky if (!(flags & PICK_STICKY) && !(_visible && _sensitive)) return NULL; @@ -736,7 +744,10 @@ DrawingItem::pick(Geom::Point const &p, double delta, unsigned flags) } Geom::OptIntRect box = (outline || (flags & PICK_AS_CLIP)) ? _bbox : _drawbox; - if (!box) return NULL; + if (!box) { + g_warning("bbox unset when picking"); + return NULL; + } Geom::Rect expanded = *box; expanded.expandBy(delta); @@ -756,6 +767,9 @@ DrawingItem::pick(Geom::Point const &p, double delta, unsigned flags) void DrawingItem::_markForRendering() { + // TODO: this function does too much work when a large subtree + // is invalidated - fix + bool outline = _drawing.outline(); Geom::OptIntRect dirty = outline ? _bbox : _drawbox; if (!dirty) return; @@ -807,8 +821,8 @@ DrawingItem::_invalidateFilterBackground(Geom::IntRect const &area) * all children should also have the corresponding flags unset before checking * whether they need to be traversed. This way there is one less traversal * of the tree. Without this we would need to unset state bits in all children. - * With _propagate we do this during the update call, when we have to traverse - * the tree anyway. + * With _propagate we do this during the update call, when we have to recurse + * into children anyway. */ void DrawingItem::_markForUpdate(unsigned flags, bool propagate) @@ -818,15 +832,31 @@ DrawingItem::_markForUpdate(unsigned flags, bool propagate) } if (_state & flags) { + unsigned oldstate = _state; _state &= ~flags; - if (_parent) { + if (oldstate != _state && _parent) { + // If we actually reset anything in state, recurse on the parent. _parent->_markForUpdate(flags, false); } else { + // If nothing changed, it means our ancestors are already invalidated + // up to the root. Do not bother recursing, because it won't change anything. + // Also do this if we are the root item, because we have no more ancestors + // to invalidate. _drawing.signal_request_update.emit(this); } } } +/** + * Process information related to the new style. + * + * This function is something of a hack to avoid creating an extra class in the hierarchy + * which would differ from DrawingItem only by having a _style member. + * This is mainly to the benefit of DrawingGlyphs, which use the style of their parent. + * This should probably be refactored some day, possibly by creating the relevant class + * or creating a more complex data model in DrawingText and removing DrawingGlyphs, + * which would cause every item to have a style. + */ void DrawingItem::_setStyleCommon(SPStyle *&_style, SPStyle *style) { @@ -834,7 +864,6 @@ DrawingItem::_setStyleCommon(SPStyle *&_style, SPStyle *style) if (_style) sp_style_unref(_style); _style = style; - // if group has a filter if (style->filter.set && style->getFilter()) { if (!_filter) { int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter())); -- cgit v1.2.3 From 1595a83d610f4e328d84eb1fc2764041ea9335db Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Tue, 1 Oct 2013 07:55:55 -0400 Subject: Revert render svg:patern segment for fill and stroke (bzr r12646) --- src/display/drawing-shape.cpp | 4 ++-- src/display/nr-filter.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index e689d0755..9ad18243e 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -179,8 +179,8 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne // update fill and stroke paints. // this cannot be done during nr_arena_shape_update, because we need a Cairo context // to render svg:pattern - has_fill = _nrstyle.prepareFill(ct, _bbox); - has_stroke = _nrstyle.prepareStroke(ct, _bbox); + has_fill = _nrstyle.prepareFill(ct, _filter_bbox); + has_stroke = _nrstyle.prepareStroke(ct, _filter_bbox); has_stroke &= (_nrstyle.stroke_width != 0); if (has_fill || has_stroke) { diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index c0044c5d8..1289362aa 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -114,7 +114,7 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D Geom::Affine trans = item->ctm(); - // Get filter are, the filter_effect_area is already done in visualBounds + // Get filter area, the filter_effect_area is already done in visualBounds Geom::OptRect filter_area = item->filterBounds(); // Use the geometricBounds as a backup solution if (!filter_area) return 1; -- cgit v1.2.3 From 56791e9c202001bf29b089f1f52ad128e548f198 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 1 Oct 2013 14:31:34 +0200 Subject: Fix possible bug in DrawingItem code (bzr r12647) --- src/display/drawing-item.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/display') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 526fc3000..b2b3e68a2 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -141,6 +141,9 @@ DrawingItem::appendChild(DrawingItem *item) assert(item->_child_type == CHILD_ORPHAN); item->_child_type = CHILD_NORMAL; _children.push_back(*item); + + // This ensures that _markForUpdate() called on the child will recurse to this item + item->_state = STATE_ALL; // Because _markForUpdate recurses through ancestors, we can simply call it // on the just-added child. This has the additional benefit that we do not // rely on the appended child being in the default non-updated state. @@ -156,6 +159,7 @@ DrawingItem::prependChild(DrawingItem *item) item->_child_type = CHILD_NORMAL; _children.push_front(*item); // See appendChild for explanation + item->_state = STATE_ALL; item->_markForUpdate(STATE_ALL, true); } -- cgit v1.2.3 From 87d93e27330577c2fd632dbaccbd3103884aa590 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 1 Oct 2013 15:25:44 +0200 Subject: Comprehensive fix for the issues with disappearing filtered objects. Fixes #304407 and possibly a few other bugs. Revert incorrect _item_bbox changes from r12528. Fixed bugs: - https://launchpad.net/bugs/304407 (bzr r12648) --- src/display/drawing-item.cpp | 25 +++++++++++-------------- src/display/drawing-item.h | 6 ++++-- src/display/drawing-shape.cpp | 4 ++-- src/display/drawing-text.cpp | 4 ++-- src/display/nr-filter.cpp | 8 +++----- 5 files changed, 22 insertions(+), 25 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index b2b3e68a2..71a7f8906 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -290,17 +290,10 @@ DrawingItem::setZOrder(unsigned z) _markForRendering(); } -void DrawingItem::setItemBounds(Geom::OptRect const &bounds) -{ - if (!bounds) return; - Geom::IntRect copy = bounds->roundOutwards(); - if (_filter) _filter->area_enlarge(copy, this); - this->setFilterBounds(copy); -} - -void DrawingItem::setFilterBounds(Geom::OptRect const &bounds) +void +DrawingItem::setItemBounds(Geom::OptRect const &bounds) { - if (bounds) _filter_bbox = bounds; + _item_bbox = bounds; } /** @@ -368,10 +361,14 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne if (to_update & STATE_BBOX) { // compute drawbox - if (_filter && render_filters && _filter_bbox) { - Geom::OptRect enlarged = _filter_bbox; - *enlarged *= ctm(); - _drawbox = enlarged->roundOutwards(); + if (_filter && render_filters) { + Geom::OptRect enlarged = _filter->filter_effect_area(_item_bbox); + if (enlarged) { + *enlarged *= ctm(); + _drawbox = enlarged->roundOutwards(); + } else { + _drawbox = Geom::OptIntRect(); + } } else { _drawbox = _bbox; } diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h index c69b996b4..e03bbd0f7 100644 --- a/src/display/drawing-item.h +++ b/src/display/drawing-item.h @@ -89,7 +89,7 @@ public: Geom::OptIntRect geometricBounds() const { return _bbox; } Geom::OptIntRect visualBounds() const { return _drawbox; } - Geom::OptRect filterBounds() const { return _filter_bbox; } + Geom::OptRect itemBounds() const { return _item_bbox; } Geom::Affine ctm() const { return _ctm; } Geom::Affine transform() const { return _transform ? *_transform : Geom::identity(); } Drawing &drawing() const { return _drawing; } @@ -176,7 +176,9 @@ protected: Geom::Affine _ctm; ///< Total transform from item coords to display coords Geom::OptIntRect _bbox; ///< Bounding box in display (pixel) coords including stroke Geom::OptIntRect _drawbox; ///< Full visual bounding box - enlarged by filters, shrunk by clips and masks - Geom::OptRect _filter_bbox; ///< Used by filters when settings bounds + Geom::OptRect _item_bbox; ///< Geometric bounding box in item's user space. + /// This is used to compute the filter effect region and render in + /// objectBoundingBox units. DrawingItem *_clip; DrawingItem *_mask; diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp index 9ad18243e..e80f12486 100644 --- a/src/display/drawing-shape.cpp +++ b/src/display/drawing-shape.cpp @@ -179,8 +179,8 @@ DrawingShape::_renderItem(DrawingContext &ct, Geom::IntRect const &area, unsigne // update fill and stroke paints. // this cannot be done during nr_arena_shape_update, because we need a Cairo context // to render svg:pattern - has_fill = _nrstyle.prepareFill(ct, _filter_bbox); - has_stroke = _nrstyle.prepareStroke(ct, _filter_bbox); + has_fill = _nrstyle.prepareFill(ct, _item_bbox); + has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); has_stroke &= (_nrstyle.stroke_width != 0); if (has_fill || has_stroke) { diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index fa9ce4ff8..55d54b770 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -398,8 +398,8 @@ unsigned DrawingText::_renderItem(DrawingContext &ct, Geom::IntRect const &/*are using Geom::X; using Geom::Y; - has_fill = _nrstyle.prepareFill( ct, _bbox); - has_stroke = _nrstyle.prepareStroke(ct, _bbox); + has_fill = _nrstyle.prepareFill( ct, _item_bbox); + has_stroke = _nrstyle.prepareStroke(ct, _item_bbox); if (has_fill || has_stroke) { Geom::Affine rotinv; diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 1289362aa..af9c15cd8 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -114,14 +114,12 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D Geom::Affine trans = item->ctm(); - // Get filter area, the filter_effect_area is already done in visualBounds - Geom::OptRect filter_area = item->filterBounds(); - // Use the geometricBounds as a backup solution + Geom::OptRect filter_area = filter_effect_area(item->itemBounds()); if (!filter_area) return 1; FilterUnits units(_filter_units, _primitive_units); units.set_ctm(trans); - units.set_item_bbox(filter_area); + units.set_item_bbox(item->itemBounds()); units.set_filter_area(*filter_area); std::pair resolution @@ -201,7 +199,7 @@ void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item } Geom::Rect item_bbox; - Geom::OptRect maybe_bbox = item->geometricBounds(); + Geom::OptRect maybe_bbox = item->itemBounds(); if (maybe_bbox.isEmpty()) { // Code below needs a bounding box return; -- cgit v1.2.3 From b50ef0ab822a44a8e6d430305fccc2fc723ca3f5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 4 Oct 2013 05:32:27 +0200 Subject: Remove unnecessary warning (bzr r12654) --- src/display/drawing-item.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/display') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 71a7f8906..69adcb441 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -746,7 +746,6 @@ DrawingItem::pick(Geom::Point const &p, double delta, unsigned flags) Geom::OptIntRect box = (outline || (flags & PICK_AS_CLIP)) ? _bbox : _drawbox; if (!box) { - g_warning("bbox unset when picking"); return NULL; } -- cgit v1.2.3 From 706294ff1fa82c86089221d8ee4a0d5bd032925a Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 5 Oct 2013 05:54:43 +0200 Subject: Rewrite the internals of the unit code for somewhat better performance (bzr r12661) --- src/display/canvas-axonomgrid.cpp | 10 +++++----- src/display/canvas-grid.cpp | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index f7a7cb39a..654144122 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -214,18 +214,18 @@ CanvasAxonomGrid::readRepr() { gchar const *value; if ( (value = repr->attribute("originx")) ) { - Inkscape::Util::Quantity q = unit_table.getQuantity(value); + Inkscape::Util::Quantity q = unit_table.parseQuantity(value); gridunit = q.unit; - origin[Geom::X] = unit_table.getQuantity(value).value("px"); + origin[Geom::X] = q.value("px"); } if ( (value = repr->attribute("originy")) ) { - Inkscape::Util::Quantity q = unit_table.getQuantity(value); + Inkscape::Util::Quantity q = unit_table.parseQuantity(value); gridunit = q.unit; - origin[Geom::Y] = unit_table.getQuantity(value).value("px"); + origin[Geom::Y] = q.value("px"); } if ( (value = repr->attribute("spacingy")) ) { - Inkscape::Util::Quantity q = unit_table.getQuantity(value); + Inkscape::Util::Quantity q = unit_table.parseQuantity(value); gridunit = q.unit; lengthy = q.value("px"); if (lengthy < 0.0500) lengthy = 0.0500; diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index ef32c113b..5701b91a1 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -588,20 +588,20 @@ CanvasXYGrid::readRepr() { gchar const *value; if ( (value = repr->attribute("originx")) ) { - Inkscape::Util::Quantity q = unit_table.getQuantity(value); + Inkscape::Util::Quantity q = unit_table.parseQuantity(value); gridunit = q.unit; - origin[Geom::X] = unit_table.getQuantity(value).value("px"); + origin[Geom::X] = q.value("px"); } if ( (value = repr->attribute("originy")) ) { - Inkscape::Util::Quantity q = unit_table.getQuantity(value); + Inkscape::Util::Quantity q = unit_table.parseQuantity(value); gridunit = q.unit; - origin[Geom::Y] = unit_table.getQuantity(value).value("px"); + origin[Geom::Y] = q.value("px"); } if ( (value = repr->attribute("spacingx")) ) { double oldVal = spacing[Geom::X]; - Inkscape::Util::Quantity q = unit_table.getQuantity(value); + Inkscape::Util::Quantity q = unit_table.parseQuantity(value); gridunit = q.unit; spacing[Geom::X] = q.quantity; validateScalar(oldVal, &spacing[Geom::X]); @@ -609,7 +609,7 @@ CanvasXYGrid::readRepr() } if ( (value = repr->attribute("spacingy")) ) { double oldVal = spacing[Geom::Y]; - Inkscape::Util::Quantity q = unit_table.getQuantity(value); + Inkscape::Util::Quantity q = unit_table.parseQuantity(value); gridunit = q.unit; spacing[Geom::Y] = q.quantity; validateScalar(oldVal, &spacing[Geom::Y]); -- cgit v1.2.3 From 30422af227381c9aa900690586d25adec4fa262f Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Wed, 9 Oct 2013 21:09:49 +0200 Subject: Documentation/Translation. Fix for Bug #1236382 (Typos in comments and message, localization context needed) by Yuri Chornoivan. Fixed bugs: - https://launchpad.net/bugs/1236382 (bzr r12673) --- src/display/drawing-item.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/display') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 69adcb441..a8257e6e5 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -459,7 +459,7 @@ struct MaskLuminanceToAlpha { /** * Rasterize items. * This method submits the drawing opeartions required to draw this item - * to the supplied DrawingContext, restricting drawing the the specified area. + * to the supplied DrawingContext, restricting drawing the specified area. * * This method does some common tasks and calls the item-specific rendering * function, _renderItem(), to render e.g. paths or bitmaps. -- cgit v1.2.3 From a970dc423d59ea844bdb1af48d5d9419a5e2a287 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 13 Oct 2013 00:24:05 +0200 Subject: Units: stop newing Unit objects. pass around pointers to "undeletable" Unit objects in the UnitTable. I think we should move to using indexed units, and pass around the index of the unit in the unittable, or smth like that... ? (bzr r12679) --- src/display/canvas-axonomgrid.cpp | 19 ++++++++++--------- src/display/canvas-grid.cpp | 28 ++++++++++++++-------------- src/display/canvas-grid.h | 2 +- 3 files changed, 25 insertions(+), 24 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index 654144122..d66b97bbc 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -161,15 +161,16 @@ CanvasAxonomGrid::CanvasAxonomGrid (SPNamedView * nv, Inkscape::XML::Node * in_r : CanvasGrid(nv, in_repr, in_doc, GRID_AXONOMETRIC) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gridunit = new Inkscape::Util::Unit(unit_table.getUnit(prefs->getString("/options/grids/axonom/units"))); - if (!gridunit) - gridunit = new Inkscape::Util::Unit(unit_table.getUnit("px")); - origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_x", 0.0), *gridunit, "px"); - origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_y", 0.0), *gridunit, "px"); + gridunit = unit_table.getUnit(prefs->getString("/options/grids/axonom/units")); + if (!gridunit) { + gridunit = unit_table.getUnit("px"); + } + origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_x", 0.0), gridunit, "px"); + origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/origin_y", 0.0), gridunit, "px"); color = prefs->getInt("/options/grids/axonom/color", 0x0000ff20); empcolor = prefs->getInt("/options/grids/axonom/empcolor", 0x0000ff40); empspacing = prefs->getInt("/options/grids/axonom/empspacing", 5); - lengthy = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/spacing_y", 1.0), *gridunit, "px"); + lengthy = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/axonom/spacing_y", 1.0), gridunit, "px"); angle_deg[X] = prefs->getDouble("/options/grids/axonom/angle_x", 30.0); angle_deg[Z] = prefs->getDouble("/options/grids/axonom/angle_z", 30.0); angle_deg[Y] = 0; @@ -370,13 +371,13 @@ _wr.setUpdating (false); gdouble val; val = origin[Geom::X]; - val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", gridunit); _rsu_ox->setValue (val); val = origin[Geom::Y]; - val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", gridunit); _rsu_oy->setValue (val); val = lengthy; - double gridy = Inkscape::Util::Quantity::convert(val, "px", *gridunit); + double gridy = Inkscape::Util::Quantity::convert(val, "px", gridunit); _rsu_sy->setValue (gridy); _rsu_ax->setValue(angle_deg[X]); diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 5701b91a1..192cc4cba 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -399,10 +399,10 @@ void CanvasGrid::setOrigin(Geom::Point const &origin_px) gdouble val; val = origin_px[Geom::X]; - val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", gridunit); os_x << val << gridunit->abbr; val = origin_px[Geom::Y]; - val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", gridunit); os_y << val << gridunit->abbr; repr->setAttribute("originx", os_x.str().c_str()); repr->setAttribute("originy", os_y.str().c_str()); @@ -489,17 +489,17 @@ CanvasXYGrid::CanvasXYGrid (SPNamedView * nv, Inkscape::XML::Node * in_repr, SPD : CanvasGrid(nv, in_repr, in_doc, GRID_RECTANGULAR) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gridunit = new Inkscape::Util::Unit(unit_table.getUnit(prefs->getString("/options/grids/xy/units"))); + gridunit = unit_table.getUnit(prefs->getString("/options/grids/xy/units")); if (!gridunit) { - gridunit = new Inkscape::Util::Unit(unit_table.getUnit("px")); + gridunit = unit_table.getUnit("px"); } - origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_x", 0.0), *gridunit, "px"); - origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_y", 0.0), *gridunit, "px"); + origin[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_x", 0.0), gridunit, "px"); + origin[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/origin_y", 0.0), gridunit, "px"); color = prefs->getInt("/options/grids/xy/color", 0x0000ff20); empcolor = prefs->getInt("/options/grids/xy/empcolor", 0x0000ff40); empspacing = prefs->getInt("/options/grids/xy/empspacing", 5); - spacing[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_x", 0.0), *gridunit, "px"); - spacing[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_y", 0.0), *gridunit, "px"); + spacing[Geom::X] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_x", 0.0), gridunit, "px"); + spacing[Geom::Y] = Inkscape::Util::Quantity::convert(prefs->getDouble("/options/grids/xy/spacing_y", 0.0), gridunit, "px"); render_dotted = prefs->getBool("/options/grids/xy/dotted", false); snapper = new CanvasXYGridSnapper(this, &namedview->snap_manager, 0); @@ -605,7 +605,7 @@ CanvasXYGrid::readRepr() gridunit = q.unit; spacing[Geom::X] = q.quantity; validateScalar(oldVal, &spacing[Geom::X]); - spacing[Geom::X] = Inkscape::Util::Quantity::convert(spacing[Geom::X], *gridunit, "px"); + spacing[Geom::X] = Inkscape::Util::Quantity::convert(spacing[Geom::X], gridunit, "px"); } if ( (value = repr->attribute("spacingy")) ) { double oldVal = spacing[Geom::Y]; @@ -613,7 +613,7 @@ CanvasXYGrid::readRepr() gridunit = q.unit; spacing[Geom::Y] = q.quantity; validateScalar(oldVal, &spacing[Geom::Y]); - spacing[Geom::Y] = Inkscape::Util::Quantity::convert(spacing[Geom::Y], *gridunit, "px"); + spacing[Geom::Y] = Inkscape::Util::Quantity::convert(spacing[Geom::Y], gridunit, "px"); } if ( (value = repr->attribute("color")) ) { @@ -753,16 +753,16 @@ CanvasXYGrid::newSpecificWidget() gdouble val; val = origin[Geom::X]; - val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", gridunit); _rsu_ox->setValue (val); val = origin[Geom::Y]; - val = Inkscape::Util::Quantity::convert(val, "px", *gridunit); + val = Inkscape::Util::Quantity::convert(val, "px", gridunit); _rsu_oy->setValue (val); val = spacing[Geom::X]; - double gridx = Inkscape::Util::Quantity::convert(val, "px", *gridunit); + double gridx = Inkscape::Util::Quantity::convert(val, "px", gridunit); _rsu_sx->setValue (gridx); val = spacing[Geom::Y]; - double gridy = Inkscape::Util::Quantity::convert(val, "px", *gridunit); + double gridy = Inkscape::Util::Quantity::convert(val, "px", gridunit); _rsu_sy->setValue (gridy); _rcp_gcol->setRgba32 (color); diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h index 56ed86e94..078670da7 100644 --- a/src/display/canvas-grid.h +++ b/src/display/canvas-grid.h @@ -92,7 +92,7 @@ public: guint32 empcolor; /**< Color for emphasis lines */ gint empspacing; /**< Spacing between emphasis lines */ - Inkscape::Util::Unit const* gridunit; + Inkscape::Util::Unit const* gridunit; /**< points to Unit object in UnitTable (so don't delete it) */ Inkscape::XML::Node * repr; SPDocument *doc; -- cgit v1.2.3 From d3f86d34d0d92505a798f8c9b83ca12dfcbf50ab Mon Sep 17 00:00:00 2001 From: Kris De Gussem Date: Sun, 13 Oct 2013 17:24:57 +0200 Subject: cppcheck (bzr r12680) --- src/display/cairo-utils.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/display') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 451f0b509..5b358ade7 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -254,7 +254,6 @@ Pixbuf *Pixbuf::create_from_data_uri(gchar const *uri_data) } if ((*data) && data_is_image && data_is_base64) { - GdkPixbuf *buf = NULL; GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); if (!loader) return NULL; @@ -264,7 +263,7 @@ Pixbuf *Pixbuf::create_from_data_uri(gchar const *uri_data) if (gdk_pixbuf_loader_write(loader, decoded, decoded_len, NULL)) { gdk_pixbuf_loader_close(loader, NULL); - buf = gdk_pixbuf_loader_get_pixbuf(loader); + GdkPixbuf *buf = gdk_pixbuf_loader_get_pixbuf(loader); if (buf) { g_object_ref(buf); pixbuf = new Pixbuf(buf); -- cgit v1.2.3 From a07da31cfa400f23f2c048340164700e3103d185 Mon Sep 17 00:00:00 2001 From: Alex Valavanis Date: Tue, 15 Oct 2013 10:17:55 +0100 Subject: Replace deprecated thread protection macros (bzr r12690) --- src/display/sp-canvas.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 9adb96642..455f628bc 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -2301,8 +2301,6 @@ int SPCanvasImpl::do_update(SPCanvas *canvas) gint SPCanvasImpl::idle_handler(gpointer data) { - GDK_THREADS_ENTER (); - SPCanvas *canvas = SP_CANVAS (data); int const ret = do_update (canvas); @@ -2312,15 +2310,13 @@ gint SPCanvasImpl::idle_handler(gpointer data) canvas->idle_id = 0; } - GDK_THREADS_LEAVE (); - return !ret; } void SPCanvasImpl::add_idle(SPCanvas *canvas) { if (canvas->idle_id == 0) { - canvas->idle_id = g_idle_add_full(UPDATE_PRIORITY, idle_handler, canvas, NULL); + canvas->idle_id = gdk_threads_add_idle_full(UPDATE_PRIORITY, idle_handler, canvas, NULL); } } -- cgit v1.2.3