Skip to content

Commit f548a02

Browse files
tdennistonSkia Commit-Bot
authored andcommitted
[svg] Implement gradientUnits="objectBoundingBox"
Currently only works properly when filling rects, since that is the only node that implements bounds computation with this CL. Summary of changes: - Scale gradient coords by object bounds when units are kObjectBoundingBox. - Make fGradientUnits protected instead of private. - Change default value of fGradientUnits to kObjectBoundingBox, which is the default according to the spec. - Change SkSVGNode::onObjectBoundingBox to take a full render context instead of length context. - Implement bounds computation for SkSVGRect, SkSVGContainer and SkSVGUse. Bug: skia:10842 Change-Id: I2e999985e67644e50da7f681fde190bcf4823eec Reviewed-on: https://skia-review.googlesource.com/c/skia/+/329223 Reviewed-by: Florin Malita <[email protected]> Commit-Queue: Tyler Denniston <[email protected]>
1 parent 532c749 commit f548a02

14 files changed

Lines changed: 68 additions & 8 deletions

modules/svg/include/SkSVGContainer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class SkSVGContainer : public SkSVGTransformableNode {
2424

2525
SkPath onAsPath(const SkSVGRenderContext&) const override;
2626

27+
SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override;
28+
2729
bool hasChildren() const final;
2830

2931
// TODO: add some sort of child iterator, and hide the container.

modules/svg/include/SkSVGGradient.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class SkSVGGradient : public SkSVGHiddenContainer {
3636
const SkColor*, const SkScalar*, int count,
3737
SkTileMode, const SkMatrix& localMatrix) const = 0;
3838

39+
SkSVGGradientUnits fGradientUnits = SkSVGGradientUnits(SkSVGGradientUnits::Type::kObjectBoundingBox);
40+
3941
private:
4042
using StopPositionArray = SkSTArray<2, SkScalar, true>;
4143
using StopColorArray = SkSTArray<2, SkColor, true>;
@@ -45,7 +47,6 @@ class SkSVGGradient : public SkSVGHiddenContainer {
4547
SkSVGStringType fHref;
4648
SkSVGTransformType fGradientTransform = SkSVGTransformType(SkMatrix::I());
4749
SkSVGSpreadMethod fSpreadMethod = SkSVGSpreadMethod(SkSVGSpreadMethod::Type::kPad);
48-
SkSVGGradientUnits fGradientUnits = SkSVGGradientUnits(SkSVGGradientUnits::Type::kUserSpaceOnUse);
4950

5051
using INHERITED = SkSVGHiddenContainer;
5152
};

modules/svg/include/SkSVGNode.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class SkSVGNode : public SkRefCnt {
7373
void render(const SkSVGRenderContext&) const;
7474
bool asPaint(const SkSVGRenderContext&, SkPaint*) const;
7575
SkPath asPath(const SkSVGRenderContext&) const;
76-
SkRect objectBoundingBox(const SkSVGLengthContext&) const;
76+
SkRect objectBoundingBox(const SkSVGRenderContext&) const;
7777

7878
void setAttribute(SkSVGAttribute, const SkSVGValue&);
7979
bool setAttribute(const char* attributeName, const char* attributeValue);
@@ -121,7 +121,7 @@ class SkSVGNode : public SkRefCnt {
121121

122122
virtual bool hasChildren() const { return false; }
123123

124-
virtual SkRect onObjectBoundingBox(const SkSVGLengthContext&) const {
124+
virtual SkRect onObjectBoundingBox(const SkSVGRenderContext&) const {
125125
return SkRect::MakeEmpty();
126126
}
127127

modules/svg/include/SkSVGRect.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class SkSVGRect final : public SkSVGShape {
3333

3434
SkPath onAsPath(const SkSVGRenderContext&) const override;
3535

36+
SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override;
37+
3638
private:
3739
SkSVGRect();
3840

modules/svg/include/SkSVGTransformableNode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class SkSVGTransformableNode : public SkSVGNode {
2626

2727
void mapToParent(SkPath*) const;
2828

29+
void mapToParent(SkRect*) const;
30+
2931
private:
3032
// FIXME: should be sparse
3133
SkSVGTransformType fTransform;

modules/svg/include/SkSVGUse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class SkSVGUse final : public SkSVGTransformableNode {
3333
bool onPrepareToRender(SkSVGRenderContext*) const override;
3434
void onRender(const SkSVGRenderContext&) const override;
3535
SkPath onAsPath(const SkSVGRenderContext&) const override;
36+
SkRect onObjectBoundingBox(const SkSVGRenderContext&) const override;
3637

3738
private:
3839
SkSVGUse();

modules/svg/src/SkSVGContainer.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,15 @@ SkPath SkSVGContainer::onAsPath(const SkSVGRenderContext& ctx) const {
3939
this->mapToParent(&path);
4040
return path;
4141
}
42+
43+
SkRect SkSVGContainer::onObjectBoundingBox(const SkSVGRenderContext& ctx) const {
44+
SkRect bounds = SkRect::MakeEmpty();
45+
46+
for (int i = 0; i < fChildren.count(); ++i) {
47+
const SkRect childBounds = fChildren[i]->objectBoundingBox(ctx);
48+
bounds.join(childBounds);
49+
}
50+
51+
this->mapToParent(&bounds);
52+
return bounds;
53+
}

modules/svg/src/SkSVGGradient.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,16 @@ bool SkSVGGradient::onAsPaint(const SkSVGRenderContext& ctx, SkPaint* paint) con
126126
SkTileMode::kMirror, "SkSVGSpreadMethod::Type is out of sync");
127127
const auto tileMode = static_cast<SkTileMode>(fSpreadMethod.type());
128128

129+
SkMatrix localMatrix = SkMatrix::I();
130+
if (fGradientUnits.type() == SkSVGGradientUnits::Type::kObjectBoundingBox) {
131+
SkASSERT(ctx.node());
132+
const SkRect objBounds = ctx.node()->objectBoundingBox(ctx);
133+
localMatrix.preTranslate(objBounds.fLeft, objBounds.fTop);
134+
localMatrix.preScale(objBounds.width(), objBounds.height());
135+
}
136+
localMatrix.preConcat(fGradientTransform);
137+
129138
paint->setShader(this->onMakeShader(ctx, colors.begin(), pos.begin(), colors.count(), tileMode,
130-
fGradientTransform));
139+
localMatrix));
131140
return true;
132141
}

modules/svg/src/SkSVGLinearGradient.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,11 @@ sk_sp<SkShader> SkSVGLinearGradient::onMakeShader(const SkSVGRenderContext& ctx,
5959
const SkColor* colors, const SkScalar* pos,
6060
int count, SkTileMode tm,
6161
const SkMatrix& localMatrix) const {
62-
const auto& lctx = ctx.lengthContext();
62+
const SkSVGLengthContext lctx =
63+
fGradientUnits.type() == SkSVGGradientUnits::Type::kObjectBoundingBox
64+
? SkSVGLengthContext({1, 1})
65+
: ctx.lengthContext();
66+
6367
const auto x1 = lctx.resolve(fX1, SkSVGLengthContext::LengthType::kHorizontal);
6468
const auto y1 = lctx.resolve(fY1, SkSVGLengthContext::LengthType::kVertical);
6569
const auto x2 = lctx.resolve(fX2, SkSVGLengthContext::LengthType::kHorizontal);

modules/svg/src/SkSVGNode.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ SkPath SkSVGNode::asPath(const SkSVGRenderContext& ctx) const {
4848
return path;
4949
}
5050

51-
SkRect SkSVGNode::objectBoundingBox(const SkSVGLengthContext& lctx) const {
52-
return this->onObjectBoundingBox(lctx);
51+
SkRect SkSVGNode::objectBoundingBox(const SkSVGRenderContext& ctx) const {
52+
return this->onObjectBoundingBox(ctx);
5353
}
5454

5555
bool SkSVGNode::onPrepareToRender(SkSVGRenderContext* ctx) const {

0 commit comments

Comments
 (0)