mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1074161 - Avoid creating a Moz2D Path object to draw SVG <rect>, <image> and <line> elements. r=mattwoodrow
This commit is contained in:
parent
f7a1b85cdf
commit
2a309ca31b
@ -106,6 +106,14 @@ SVGLineElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks) {
|
||||
aMarks->AppendElement(nsSVGMark(x2, y2, angle, nsSVGMark::eEnd));
|
||||
}
|
||||
|
||||
void
|
||||
SVGLineElement::GetAsSimplePath(SimplePath* aSimplePath)
|
||||
{
|
||||
float x1, y1, x2, y2;
|
||||
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
|
||||
aSimplePath->SetLine(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGLineElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
|
@ -32,6 +32,7 @@ public:
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
|
||||
virtual void GetAsSimplePath(SimplePath* aSimplePath) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
|
@ -108,6 +108,28 @@ SVGRectElement::GetLengthInfo()
|
||||
//----------------------------------------------------------------------
|
||||
// nsSVGPathGeometryElement methods
|
||||
|
||||
void
|
||||
SVGRectElement::GetAsSimplePath(SimplePath* aSimplePath)
|
||||
{
|
||||
float x, y, width, height, rx, ry;
|
||||
GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
aSimplePath->Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
rx = std::max(rx, 0.0f);
|
||||
ry = std::max(ry, 0.0f);
|
||||
|
||||
if (rx != 0 || ry != 0) {
|
||||
aSimplePath->Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
aSimplePath->SetRect(x, y, width, height);
|
||||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGRectElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
|
@ -30,6 +30,7 @@ public:
|
||||
virtual bool HasValidDimensions() const MOZ_OVERRIDE;
|
||||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual void GetAsSimplePath(SimplePath* aSimplePath) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
|
||||
|
@ -35,7 +35,9 @@ protected:
|
||||
typedef mozilla::gfx::FillRule FillRule;
|
||||
typedef mozilla::gfx::Float Float;
|
||||
typedef mozilla::gfx::Path Path;
|
||||
typedef mozilla::gfx::Point Point;
|
||||
typedef mozilla::gfx::PathBuilder PathBuilder;
|
||||
typedef mozilla::gfx::Rect Rect;
|
||||
|
||||
public:
|
||||
explicit nsSVGPathGeometryElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
@ -67,6 +69,65 @@ public:
|
||||
virtual bool IsMarkable();
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
|
||||
|
||||
/**
|
||||
* For use with GetAsSimplePath.
|
||||
*/
|
||||
class SimplePath
|
||||
{
|
||||
public:
|
||||
SimplePath()
|
||||
: mType(NONE)
|
||||
{}
|
||||
bool IsPath() const {
|
||||
return mType != NONE;
|
||||
}
|
||||
void SetRect(Float x, Float y, Float width, Float height) {
|
||||
mX = x; mY = y, mWidthOrX2 = width, mHeightOrY2 = height;
|
||||
mType = RECT;
|
||||
}
|
||||
Rect AsRect() const {
|
||||
MOZ_ASSERT(mType == RECT);
|
||||
return Rect(mX, mY, mWidthOrX2, mHeightOrY2);
|
||||
}
|
||||
bool IsRect() const {
|
||||
return mType == RECT;
|
||||
}
|
||||
void SetLine(Float x1, Float y1, Float x2, Float y2) {
|
||||
mX = x1, mY = y1, mWidthOrX2 = x2, mHeightOrY2 = y2;
|
||||
mType = LINE;
|
||||
}
|
||||
Point Point1() const {
|
||||
MOZ_ASSERT(mType == LINE);
|
||||
return Point(mX, mY);
|
||||
}
|
||||
Point Point2() const {
|
||||
MOZ_ASSERT(mType == LINE);
|
||||
return Point(mWidthOrX2, mHeightOrY2);
|
||||
}
|
||||
bool IsLine() const {
|
||||
return mType == LINE;
|
||||
}
|
||||
void Reset() {
|
||||
mType = NONE;
|
||||
}
|
||||
private:
|
||||
enum Type {
|
||||
NONE, RECT, LINE
|
||||
};
|
||||
Float mX, mY, mWidthOrX2, mHeightOrY2;
|
||||
Type mType;
|
||||
};
|
||||
|
||||
/**
|
||||
* For some platforms there is significant overhead to creating and painting
|
||||
* a Moz2D Path object. For Rects and lines it is better to get the path data
|
||||
* using this method and then use the optimized DrawTarget methods for
|
||||
* filling/stroking rects and lines.
|
||||
*/
|
||||
virtual void GetAsSimplePath(SimplePath* aSimplePath) {
|
||||
aSimplePath->Reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Path that can be used to paint, hit-test or calculate bounds for
|
||||
* this element. May return nullptr if there is no [valid] path. The path
|
||||
|
@ -685,11 +685,6 @@ nsSVGPathGeometryFrame::Render(gfxContext* aContext,
|
||||
nsSVGPathGeometryElement* element =
|
||||
static_cast<nsSVGPathGeometryElement*>(mContent);
|
||||
|
||||
RefPtr<Path> path = element->GetOrBuildPath(*drawTarget, fillRule);
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
|
||||
AntialiasMode aaMode =
|
||||
(StyleSVG()->mShapeRendering == NS_STYLE_SHAPE_RENDERING_OPTIMIZESPEED ||
|
||||
StyleSVG()->mShapeRendering == NS_STYLE_SHAPE_RENDERING_CRISPEDGES) ?
|
||||
@ -702,12 +697,28 @@ nsSVGPathGeometryFrame::Render(gfxContext* aContext,
|
||||
aContext->SetMatrix(aNewTransform);
|
||||
|
||||
if (GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) {
|
||||
ColorPattern white(ToDeviceColor(Color(1.0f, 1.0f, 1.0f, 1.0f)));
|
||||
drawTarget->Fill(path, white,
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER, aaMode));
|
||||
// We don't complicate this code with GetAsSimplePath since the cost of
|
||||
// masking will dwarf Path creation overhead anyway.
|
||||
RefPtr<Path> path = element->GetOrBuildPath(*drawTarget, fillRule);
|
||||
if (path) {
|
||||
ColorPattern white(ToDeviceColor(Color(1.0f, 1.0f, 1.0f, 1.0f)));
|
||||
drawTarget->Fill(path, white,
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER, aaMode));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nsSVGPathGeometryElement::SimplePath simplePath;
|
||||
RefPtr<Path> path;
|
||||
|
||||
element->GetAsSimplePath(&simplePath);
|
||||
if (!simplePath.IsPath()) {
|
||||
path = element->GetOrBuildPath(*drawTarget, fillRule);
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gfxTextContextPaint *contextPaint =
|
||||
(gfxTextContextPaint*)drawTarget->
|
||||
GetUserData(&gfxTextContextPaint::sUserDataKey);
|
||||
@ -716,8 +727,12 @@ nsSVGPathGeometryFrame::Render(gfxContext* aContext,
|
||||
GeneralPattern fillPattern;
|
||||
nsSVGUtils::MakeFillPatternFor(this, aContext, &fillPattern, contextPaint);
|
||||
if (fillPattern.GetPattern()) {
|
||||
drawTarget->Fill(path, fillPattern,
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER, aaMode));
|
||||
DrawOptions drawOptions(1.0f, CompositionOp::OP_OVER, aaMode);
|
||||
if (simplePath.IsRect()) {
|
||||
drawTarget->FillRect(simplePath.AsRect(), fillPattern, drawOptions);
|
||||
} else if (path) {
|
||||
drawTarget->Fill(path, fillPattern, drawOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -726,6 +741,15 @@ nsSVGPathGeometryFrame::Render(gfxContext* aContext,
|
||||
// Account for vector-effect:non-scaling-stroke:
|
||||
gfxMatrix userToOuterSVG;
|
||||
if (nsSVGUtils::GetNonScalingStrokeTransform(this, &userToOuterSVG)) {
|
||||
// A simple Rect can't be transformed with rotate/skew, so let's switch
|
||||
// to using a real path:
|
||||
if (!path) {
|
||||
path = element->GetOrBuildPath(*drawTarget, fillRule);
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
simplePath.Reset();
|
||||
}
|
||||
// We need to transform the path back into the appropriate ancestor
|
||||
// coordinate system, and paint it it that coordinate system, in order
|
||||
// for non-scaled stroke to paint correctly.
|
||||
@ -747,8 +771,16 @@ nsSVGPathGeometryFrame::Render(gfxContext* aContext,
|
||||
if (strokeOptions.mLineWidth <= 0) {
|
||||
return;
|
||||
}
|
||||
drawTarget->Stroke(path, strokePattern, strokeOptions,
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER, aaMode));
|
||||
DrawOptions drawOptions(1.0f, CompositionOp::OP_OVER, aaMode);
|
||||
if (simplePath.IsRect()) {
|
||||
drawTarget->StrokeRect(simplePath.AsRect(), strokePattern,
|
||||
strokeOptions, drawOptions);
|
||||
} else if (simplePath.IsLine()) {
|
||||
drawTarget->StrokeLine(simplePath.Point1(), simplePath.Point2(),
|
||||
strokePattern, strokeOptions, drawOptions);
|
||||
} else {
|
||||
drawTarget->Stroke(path, strokePattern, strokeOptions, drawOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user