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

tdf#82214 optimize performance for primitives

See svg bug doc, which is processed quite slowly. Beyond needing faster
renderers, there is also demand to improve the handling of primitives
created by SVG import.

Conflicts:
	drawinglayer/source/primitive2d/patternfillprimitive2d.cxx
	vcl/win/gdi/gdiimpl.cxx

Change-Id: I10992a5746b8b2d6b50e3ee3fe415a035685c9ba
üst c1f476d9
......@@ -955,6 +955,14 @@ namespace basegfx
}
}
}
else
{
// point count, but no edge count -> single point
aRetval.append(
createPolygonFromCircle(
aCandidate.getB2DPoint(0),
fHalfLineWidth));
}
return aRetval;
}
......
......@@ -40,8 +40,24 @@ namespace drawinglayer
}
default :
{
// process recursively
process(rCandidate.get2DDecomposition(getViewInformation2D()));
// we look for an encapsulated primitive, so do not decompose primitives
// based on GroupPrimitive2D, just visit their children. It may be that more
// group-like primitives need to be added here, but all primitives with
// grouping functionality should be implemented based on the GroupPrimitive2D
// class and have their main content accessible as children
const primitive2d::GroupPrimitive2D* pGroupPrimitive2D = dynamic_cast< const primitive2d::GroupPrimitive2D* >(&rCandidate);
if(pGroupPrimitive2D)
{
// process group children recursively
process(pGroupPrimitive2D->getChildren());
}
else
{
// do not process recursively, we *only* want to find existing
// ObjectInfoPrimitive2D entries
}
break;
}
}
......
......@@ -182,17 +182,19 @@ namespace drawinglayer
bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency)
{
basegfx::B2DPolygon aLocalPolygon(rSource.getB2DPolygon());
if(!aLocalPolygon.count())
if(!rSource.getB2DPolygon().count())
{
// no geometry, done
return true;
}
aLocalPolygon = basegfx::tools::simplifyCurveSegments(aLocalPolygon);
// get geometry data, prepare hairline data
basegfx::B2DPolygon aLocalPolygon(rSource.getB2DPolygon());
basegfx::B2DPolyPolygon aHairLinePolyPolygon;
// simplify curve segments
aLocalPolygon = basegfx::tools::simplifyCurveSegments(aLocalPolygon);
if(rSource.getStrokeAttribute().isDefault() || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen())
{
// no line dashing, just copy
......
......@@ -720,9 +720,20 @@ namespace drawinglayer
&& mfOffsetY == pCompare->mfOffsetY);
}
void GeoTexSvxTiled::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices)
sal_uInt32 GeoTexSvxTiled::getNumberOfTiles() const
{
return iterateTiles(nullptr);
}
void GeoTexSvxTiled::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) const
{
iterateTiles(&rMatrices);
}
sal_Int32 GeoTexSvxTiled::iterateTiles(::std::vector< basegfx::B2DHomMatrix >* pMatrices) const
{
const double fWidth(maRange.getWidth());
sal_Int32 nTiles = 0;
if(!basegfx::fTools::equalZero(fWidth))
{
......@@ -774,12 +785,19 @@ namespace drawinglayer
for(double fPosY((nPosX % 2) ? fStartY - fHeight + (mfOffsetY * fHeight) : fStartY);
basegfx::fTools::less(fPosY, 1.0); fPosY += fHeight)
{
rMatrices.push_back(
basegfx::tools::createScaleTranslateB2DHomMatrix(
fWidth,
fHeight,
fPosX,
fPosY));
if(pMatrices)
{
pMatrices->push_back(
basegfx::tools::createScaleTranslateB2DHomMatrix(
fWidth,
fHeight,
fPosX,
fPosY));
}
else
{
nTiles++;
}
}
}
}
......@@ -790,17 +808,26 @@ namespace drawinglayer
for(double fPosX((nPosY % 2) ? fStartX - fWidth + (mfOffsetX * fWidth) : fStartX);
basegfx::fTools::less(fPosX, 1.0); fPosX += fWidth)
{
rMatrices.push_back(
basegfx::tools::createScaleTranslateB2DHomMatrix(
fWidth,
fHeight,
fPosX,
fPosY));
if(pMatrices)
{
pMatrices->push_back(
basegfx::tools::createScaleTranslateB2DHomMatrix(
fWidth,
fHeight,
fPosX,
fPosY));
}
else
{
nTiles++;
}
}
}
}
}
}
return nTiles;
}
} // end of namespace texture
} // end of namespace drawinglayer
......
......@@ -42,9 +42,24 @@ namespace drawinglayer
{
private:
const basegfx::B2DPolyPolygon maMask;
const Primitive2DContainer maChildren;
const Primitive2DContainer maChildren;
const basegfx::B2DRange maReferenceRange;
/// values holding the discrete buffer size
sal_uInt32 mnDiscreteWidth;
sal_uInt32 mnDiscreteHeight;
/// helper that is capable to calculate the needed discrete buffer size for
/// eventually buffered content
void calculateNeededDiscreteBufferSize(
sal_uInt32& rWidth,
sal_uInt32& rHeight,
const geometry::ViewInformation2D& rViewInformation) const;
/// helper which creates the content - checks if clipping is needed and eventually
/// creates buffered content to speed up rendering
Primitive2DContainer createContent(const geometry::ViewInformation2D& rViewInformation) const;
protected:
/// create local decomposition
virtual Primitive2DContainer create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override;
......@@ -67,6 +82,9 @@ namespace drawinglayer
/// get range
virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
/// overload to react on evtl. buffered content
virtual Primitive2DContainer get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override;
/// provide unique ID
DeclPrimitive2DIDBlock()
};
......
......@@ -324,6 +324,9 @@ namespace drawinglayer
double mfOffsetX;
double mfOffsetY;
private:
sal_Int32 iterateTiles(::std::vector< basegfx::B2DHomMatrix >* pMatrices) const;
public:
GeoTexSvxTiled(
const basegfx::B2DRange& rRange,
......@@ -334,7 +337,8 @@ namespace drawinglayer
// compare operator
virtual bool operator==(const GeoTexSvx& rGeoTexSvx) const override;
void appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices);
void appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) const;
sal_uInt32 getNumberOfTiles() const;
};
} // end of namespace texture
} // end of namespace drawinglayer
......
......@@ -1896,9 +1896,10 @@ bool WinSalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt
}
void impAddB2DPolygonToGDIPlusGraphicsPathReal(
Gdiplus::GraphicsPath& rGraphicsPath,
Gdiplus::GpPath *pPath,
const basegfx::B2DPolygon& rPolygon,
bool bNoLineJoin)
bool bNoLineJoin,
const basegfx::B2DVector* pLineWidths)
{
sal_uInt32 nCount(rPolygon.count());
......@@ -1908,56 +1909,85 @@ void impAddB2DPolygonToGDIPlusGraphicsPathReal(
const bool bControls(rPolygon.areControlPointsUsed());
basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0));
for(sal_uInt32 a(0); a < nEdgeCount; a++)
if(nEdgeCount)
{
const sal_uInt32 nNextIndex((a + 1) % nCount);
const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
const bool b1stControlPointUsed(bControls && rPolygon.isNextControlPointUsed(a));
const bool b2ndControlPointUsed(bControls && rPolygon.isPrevControlPointUsed(nNextIndex));
if(b1stControlPointUsed || b2ndControlPointUsed)
for(sal_uInt32 a(0); a < nEdgeCount; a++)
{
basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
// tdf#99165 MS Gdiplus cannot handle creating correct extra geometry for fat lines
// with LineCap or LineJoin when a bezier segment starts or ends trivial, e.g. has
// no 1st or 2nd control point, despite that these are mathematicaly correct definitions
// (basegfx can handle that). To solve, create replacement vectors to thre resp. next
// control point with 1/3rd of length (the default control vector for these cases).
// Only one of this can happen here, else the is(Next|Prev)ControlPointUsed wopuld have
// both been false.
// Caution: This error (and it's correction) might be necessary for other graphical
// sub-systems in a similar way
if(!b1stControlPointUsed)
const sal_uInt32 nNextIndex((a + 1) % nCount);
const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
const bool b1stControlPointUsed(bControls && rPolygon.isNextControlPointUsed(a));
const bool b2ndControlPointUsed(bControls && rPolygon.isPrevControlPointUsed(nNextIndex));
if(b1stControlPointUsed || b2ndControlPointUsed)
{
aCa = aCurr + ((aCb - aCurr) * 0.3);
basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
// tdf#99165 MS Gdiplus cannot handle creating correct extra geometry for fat lines
// with LineCap or LineJoin when a bezier segment starts or ends trivial, e.g. has
// no 1st or 2nd control point, despite that these are mathematicaly correct definitions
// (basegfx can handle that). To solve, create replacement vectors to thre resp. next
// control point with 1/3rd of length (the default control vector for these cases).
// Only one of this can happen here, else the is(Next|Prev)ControlPointUsed wopuld have
// both been false.
// Caution: This error (and it's correction) might be necessary for other graphical
// sub-systems in a similar way
if(!b1stControlPointUsed)
{
aCa = aCurr + ((aCb - aCurr) * 0.3);
}
else if(!b2ndControlPointUsed)
{
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());
}
else if(!b2ndControlPointUsed)
else
{
aCb = aNext + ((aCa - aNext) * 0.3);
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.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
{
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)
{
aCurr = aNext;
if(bNoLineJoin)
if(a + 1 < nEdgeCount)
{
rGraphicsPath.StartFigure();
aCurr = aNext;
if(bNoLineJoin)
{
Gdiplus::DllExports::GdipStartPathFigure(pPath);
}
}
}
}
......@@ -1984,9 +2014,8 @@ bool WinSalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPo
aGraphicsPath.StartFigure();
}
impAddB2DPolygonToGDIPlusGraphicsPathReal(aGraphicsPath, rPolyPolygon.getB2DPolygon(a), false);
aGraphicsPath.CloseFigure();
impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolyPolygon.getB2DPolygon(a), false, 0);
Gdiplus::DllExports::GdipClosePathFigure(pPath);
}
if(mrParent.getAntiAliasB2DDraw())
......@@ -2098,7 +2127,7 @@ bool WinSalGraphicsImpl::drawPolyLine(
}
}
impAddB2DPolygonToGDIPlusGraphicsPathReal(aGraphicsPath, rPolygon, bNoLineJoin);
impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolygon, bNoLineJoin, &rLineWidths);
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