From ede382b3928afae9e59e8da0f475a4e59decf30e Mon Sep 17 00:00:00 2001 From: Armin Le Grand Date: Fri, 1 Jul 2016 15:50:00 +0200 Subject: tdf#82214 optimize PatternFillPrimitive and SVG Use buffering in the drawinglayer, and don't do slow stuff in the windows gdi renderer. Conflicts: svgio/source/svgreader/svgstyleattributes.cxx Change-Id: Id955ee6a3b03e568c2678f02d77af35d2e5ba1d4 --- .../source/primitive2d/patternfillprimitive2d.cxx | 73 ++++++++-------- svgio/source/svgreader/svgstyleattributes.cxx | 99 +++++++++++++--------- vcl/win/gdi/gdiimpl.cxx | 56 ++++-------- 3 files changed, 112 insertions(+), 116 deletions(-) diff --git a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx index 39b695c4be7a..5d1eec1ca93b 100644 --- a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx @@ -31,8 +31,8 @@ using namespace com::sun::star; -#define MAXIMUM_SQUARE_LENGTH (164.0) -#define MINIMUM_SQUARE_LENGTH (32.0) +#define MAXIMUM_SQUARE_LENGTH (186.0) +#define MINIMUM_SQUARE_LENGTH (16.0) #define MINIMUM_TILES_LENGTH (3) namespace drawinglayer @@ -257,57 +257,58 @@ namespace drawinglayer Primitive2DContainer PatternFillPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const { - if(0 == mnDiscreteWidth || 0 == mnDiscreteHeight) + // The existing bufferd decomposition uses a buffer in the remembered + // size or none if sizes are zero. Get new needed sizes which depend on + // the given ViewInformation + bool bResetBuffering = false; + sal_uInt32 nW(0); + sal_uInt32 nH(0); + calculateNeededDiscreteBufferSize(nW, nH, rViewInformation); + const bool bBufferingCurrentlyUsed(0 != mnDiscreteWidth && 0 != mnDiscreteHeight); + const bool bBufferingNextUsed(0 != nW && 0 != nH); + + if(bBufferingNextUsed) { - // Currently no buffering is used. Check if the resulting discrete sizes - // in the current situation would be good for buffering from now on - PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this); - - calculateNeededDiscreteBufferSize(pThat->mnDiscreteWidth, pThat->mnDiscreteHeight, rViewInformation); - } - else - { - // The existing bufferd decomposition uses a buffer in the remembered - // size. Get new needed sizes which depend on the given ViewInformation - sal_uInt32 nW(0); - sal_uInt32 nH(0); - calculateNeededDiscreteBufferSize(nW, nH, rViewInformation); - - if(0 != nW && 0 != nH) + // buffering is now possible + if(bBufferingCurrentlyUsed) { - // buffering is possible - check if reset is needed - bool bResetBuffering = false; - if(nW > mnDiscreteWidth || nH > mnDiscreteHeight) { // Higher resolution is needed than used in the existing buffered - // decomposition + // decomposition - create new one bResetBuffering = true; } else if(double(nW * nH) / double(mnDiscreteWidth * mnDiscreteHeight) <= 0.5) { // Size has shrunk for 50% or more - it's worth to refresh the buffering + // to spare some ressources bResetBuffering = true; } - - if(bResetBuffering) - { - PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this); - pThat->mnDiscreteWidth = nW; - pThat->mnDiscreteHeight = nH; - pThat->setBuffered2DDecomposition(Primitive2DContainer()); - } } else { - // no buffering wanted or possible - clear decomposition to create a - // new, unbuffered one - PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this); - pThat->mnDiscreteWidth = 0; - pThat->mnDiscreteHeight = 0; - pThat->setBuffered2DDecomposition(Primitive2DContainer()); + // currently no buffering used - reset evtl. unbuffered + // decomposition to start buffering + bResetBuffering = true; } } + else + { + // buffering is no longer possible + if(bBufferingCurrentlyUsed) + { + // reset decomposition to allow creation of unbuffered one + bResetBuffering = true; + } + } + + if(bResetBuffering) + { + PatternFillPrimitive2D* pThat = const_cast< PatternFillPrimitive2D* >(this); + pThat->mnDiscreteWidth = nW; + pThat->mnDiscreteHeight = nH; + pThat->setBuffered2DDecomposition(Primitive2DContainer()); + } // call parent return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation); diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx index dcde298b72be..993521c39922 100644 --- a/svgio/source/svgreader/svgstyleattributes.cxx +++ b/svgio/source/svgreader/svgstyleattributes.cxx @@ -664,54 +664,75 @@ namespace svgio if(basegfx::fTools::more(fStrokeWidth, 0.0)) { - // get LineJoin, LineCap and stroke array - const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin())); - const css::drawing::LineCap aLineCap(StrokeLinecapToDrawingLineCap(getStrokeLinecap())); - ::std::vector< double > aDashArray; + drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive; - if(!getStrokeDasharray().empty()) + // if we have a line with two identical points it is not really a line, + // but used by SVG sometimes to paint a single dot.In that case, create + // the geometry for a single dot + if(1 == rPath.count()) { - aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner); - } + const basegfx::B2DPolygon aSingle(rPath.getB2DPolygon(0)); - // todo: Handle getStrokeDashOffset() - - // convert svg:stroke-miterlimit to LineAttrute:mfMiterMinimumAngle - // The default needs to be set explicitly, because svg default <> Draw default - double fMiterMinimumAngle; - if (getStrokeMiterLimit().isSet()) - { - fMiterMinimumAngle = 2.0 * asin(1.0/getStrokeMiterLimit().getNumber()); + if(2 == aSingle.count() && aSingle.getB2DPoint(0).equal(aSingle.getB2DPoint(1))) + { + aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon( + basegfx::tools::createPolygonFromCircle( + aSingle.getB2DPoint(0), + fStrokeWidth * (1.44 * 0.5))), + pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0)); + } } - else + + if(!aNewLinePrimitive.is()) { - fMiterMinimumAngle = 2.0 * asin(0.25); // 1.0/default 4.0 - } + // get LineJoin, LineCap and stroke array + const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin())); + const css::drawing::LineCap aLineCap(StrokeLinecapToDrawingLineCap(getStrokeLinecap())); + ::std::vector< double > aDashArray; - // prepare line attribute - drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive; + if(!getStrokeDasharray().empty()) + { + aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner); + } + + // convert svg:stroke-miterlimit to LineAttrute:mfMiterMinimumAngle + // The default needs to be set explicitely, because svg default <> Draw default + double fMiterMinimumAngle; + if (getStrokeMiterLimit().isSet()) + { + fMiterMinimumAngle = 2.0 * asin(1.0/getStrokeMiterLimit().getNumber()); + } + else + { + fMiterMinimumAngle = 2.0 * asin(0.25); // 1.0/default 4.0 + } - const drawinglayer::attribute::LineAttribute aLineAttribute( - pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0), - fStrokeWidth, - aB2DLineJoin, - aLineCap, - fMiterMinimumAngle); + // todo: Handle getStrokeDashOffset() - if(aDashArray.empty()) - { - aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - rPath, - aLineAttribute); - } - else - { - const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray); + // prepare line attribute + const drawinglayer::attribute::LineAttribute aLineAttribute( + pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0), + fStrokeWidth, + aB2DLineJoin, + aLineCap, + fMiterMinimumAngle); - aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - rPath, - aLineAttribute, - aStrokeAttribute); + if(aDashArray.empty()) + { + aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + rPath, + aLineAttribute); + } + else + { + const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray); + + aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + rPath, + aLineAttribute, + aStrokeAttribute); + } } if(pStrokeGradient || pStrokePattern) diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx index 3728755cb756..09c63f554799 100644 --- a/vcl/win/gdi/gdiimpl.cxx +++ b/vcl/win/gdi/gdiimpl.cxx @@ -1896,10 +1896,9 @@ bool WinSalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt } void impAddB2DPolygonToGDIPlusGraphicsPathReal( - Gdiplus::GpPath *pPath, + Gdiplus::GraphicsPath& rGraphicsPath, const basegfx::B2DPolygon& rPolygon, - bool bNoLineJoin, - const basegfx::B2DVector* pLineWidths) + bool bNoLineJoin) { sal_uInt32 nCount(rPolygon.count()); @@ -1941,43 +1940,17 @@ void impAddB2DPolygonToGDIPlusGraphicsPathReal( aCb = aNext + ((aCa - aNext) * 0.3); } - Gdiplus::DllExports::GdipAddPathBezier( - pPath, - aCurr.getX(), aCurr.getY(), - aCa.getX(), aCa.getY(), - aCb.getX(), aCb.getY(), - aNext.getX(), aNext.getY()); + rGraphicsPath.AddBezier( + static_cast< Gdiplus::REAL >(aCurr.getX()), static_cast< Gdiplus::REAL >(aCurr.getY()), + static_cast< Gdiplus::REAL >(aCa.getX()), static_cast< Gdiplus::REAL >(aCa.getY()), + static_cast< Gdiplus::REAL >(aCb.getX()), static_cast< Gdiplus::REAL >(aCb.getY()), + static_cast< Gdiplus::REAL >(aNext.getX()), static_cast< Gdiplus::REAL >(aNext.getY())); } else { - if(pLineWidths && aCurr.equal(aNext)) - { - // For lines with no length Gdiplus unfortunately paints nothing, - // independent of LineCaps being set. This differs from e.g. SVG - // and other systems. To get geometry created, add some offset, - // based on line width to have something relative to current metrics - if(!basegfx::fTools::equalZero(pLineWidths->getX())) - { - Gdiplus::DllExports::GdipAddPathLine( - pPath, - aCurr.getX(), aCurr.getY(), - aNext.getX() + (pLineWidths->getX() * 0.1), aNext.getY()); - } - else - { - Gdiplus::DllExports::GdipAddPathLine( - pPath, - aCurr.getX(), aCurr.getY(), - aNext.getX(), aNext.getY() + (pLineWidths->getY() * 0.1)); - } - } - else - { - Gdiplus::DllExports::GdipAddPathLine( - pPath, - aCurr.getX(), aCurr.getY(), - aNext.getX(), aNext.getY()); - } + rGraphicsPath.AddLine( + static_cast< Gdiplus::REAL >(aCurr.getX()), static_cast< Gdiplus::REAL >(aCurr.getY()), + static_cast< Gdiplus::REAL >(aNext.getX()), static_cast< Gdiplus::REAL >(aNext.getY())); } if(a + 1 < nEdgeCount) @@ -1986,7 +1959,7 @@ void impAddB2DPolygonToGDIPlusGraphicsPathReal( if(bNoLineJoin) { - Gdiplus::DllExports::GdipStartPathFigure(pPath); + rGraphicsPath.StartFigure(); } } } @@ -2014,8 +1987,9 @@ bool WinSalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPo aGraphicsPath.StartFigure(); } - impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolyPolygon.getB2DPolygon(a), false, 0); - Gdiplus::DllExports::GdipClosePathFigure(pPath); + impAddB2DPolygonToGDIPlusGraphicsPathReal(aGraphicsPath, rPolyPolygon.getB2DPolygon(a), false); + + aGraphicsPath.CloseFigure(); } if(mrParent.getAntiAliasB2DDraw()) @@ -2127,7 +2101,7 @@ bool WinSalGraphicsImpl::drawPolyLine( } } - impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolygon, bNoLineJoin, &rLineWidths); + impAddB2DPolygonToGDIPlusGraphicsPathReal(aGraphicsPath, rPolygon, bNoLineJoin); if(rPolygon.isClosed() && !bNoLineJoin) { -- cgit v1.2.3