Kaydet (Commit) 5046ebd8 authored tarafından Armin Le Grand's avatar Armin Le Grand Kaydeden (comit) Thorsten Behrens

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
üst 4609380b
......@@ -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);
......
......@@ -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)
......
......@@ -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)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment