diff options
author | Ethan Nicholas <ethannicholas@google.com> | 2017-07-14 13:11:38 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-07-14 19:45:14 +0000 |
commit | 420f1565e9783b25d6ceb7ada21ca7c7c57d9e4c (patch) | |
tree | 52cf55c23a97001f48a3fcb94bc66763f9ea4d5f /src/gpu/effects | |
parent | f2c901474c240637c590ebfdf37db6e7d8316ec1 (diff) |
converted EllipseEffect to sksl
Bug: skia:
Change-Id: Id089b9ead7a21e903b001006dffff2381efd4ba3
Reviewed-on: https://skia-review.googlesource.com/23582
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Diffstat (limited to 'src/gpu/effects')
-rw-r--r-- | src/gpu/effects/GrEllipseEffect.cpp | 110 | ||||
-rw-r--r-- | src/gpu/effects/GrEllipseEffect.fp | 105 | ||||
-rw-r--r-- | src/gpu/effects/GrEllipseEffect.h | 46 | ||||
-rw-r--r-- | src/gpu/effects/GrOvalEffect.cpp | 218 |
4 files changed, 264 insertions, 215 deletions
diff --git a/src/gpu/effects/GrEllipseEffect.cpp b/src/gpu/effects/GrEllipseEffect.cpp new file mode 100644 index 0000000000..2b9675fd94 --- /dev/null +++ b/src/gpu/effects/GrEllipseEffect.cpp @@ -0,0 +1,110 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * This file was autogenerated from GrEllipseEffect.fp; do not modify. + */ +#include "GrEllipseEffect.h" +#if SK_SUPPORT_GPU +#include "glsl/GrGLSLColorSpaceXformHelper.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLProgramBuilder.h" +#include "SkSLCPP.h" +#include "SkSLUtil.h" +class GrGLSLEllipseEffect : public GrGLSLFragmentProcessor { +public: + GrGLSLEllipseEffect() {} + void emitCode(EmitArgs& args) override { + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + const GrEllipseEffect& _outer = args.fFp.cast<GrEllipseEffect>(); + (void) _outer; +prevRadii = vec2(-1.0); +useScale = sk_Caps.floatPrecisionVaries; + fEllipseVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, kHigh_GrSLPrecision, "ellipse"); + if (useScale) { + fScaleVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "scale"); + } + fragBuilder->codeAppendf("vec2 prevCenter;\nvec2 prevRadii = vec2(%f, %f);\nbool useScale = %s;\nvec2 d = sk_FragCoord.xy - %s.xy;\n@if (useScale) {\n d *= %s.y;\n}\nvec2 Z = d * %s.zw;\nfloat implicit = dot(Z, d) - 1.0;\nfloat grad_dot = 4.0 * dot(Z, Z);\ngrad_dot = max(grad_dot, 0.0001);\nfloat approx_dist = implicit * inversesqrt(grad_dot);\n@if (useScale) {\n approx_dist *= %s.x;\n}\nfloat alpha;\n@switch (%d) {\n case 0:\n alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n break;\n case 1:\n alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n break;\n case 2:\n alpha = approx_dist > 0.0 ? 1.0 : 0.0;\n break;\n case 3:\n alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n break;\n default:\n discard;\n}\n%s = %s * alpha;\n", prevRadii.fX, prevRadii.fY, (useScale ? "true" : "false"), args.fUniformHandler->getUniformCStr(fEllipseVar), fScaleVar.isValid() ? args.fUniformHandler->getUniformCStr(fScaleVar) : "vec2(0.0)", args.fUniformHandler->getUniformCStr(fEllipseVar), fScaleVar.isValid() ? args.fUniformHandler->getUniformCStr(fScaleVar) : "vec2(0.0)", _outer.edgeType(), args.fOutputColor, args.fInputColor ? args.fInputColor : "vec4(1)"); + } +private: + void onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& _proc) override { + const GrEllipseEffect& _outer = _proc.cast<GrEllipseEffect>(); + auto edgeType = _outer.edgeType(); + (void) edgeType; + auto center = _outer.center(); + (void) center; + auto radii = _outer.radii(); + (void) radii; + UniformHandle& ellipse = fEllipseVar; + (void) ellipse; + UniformHandle& scale = fScaleVar; + (void) scale; + + if (radii != prevRadii || center != prevCenter) { + float invRXSqd; + float invRYSqd; + + + if (scale.isValid()) { + if (radii.fX > radii.fY) { + invRXSqd = 1.f; + invRYSqd = (radii.fX * radii.fX) / + (radii.fY * radii.fY); + pdman.set2f(scale, radii.fX, 1.f / radii.fX); + } else { + invRXSqd = (radii.fY * radii.fY) / + (radii.fX * radii.fX); + invRYSqd = 1.f; + pdman.set2f(scale, radii.fY, 1.f / radii.fY); + } + } else { + invRXSqd = 1.f / (radii.fX * radii.fX); + invRYSqd = 1.f / (radii.fY * radii.fY); + } + pdman.set4f(ellipse, center.fX, center.fY, invRXSqd, invRYSqd); + prevCenter = center; + prevRadii = radii; + } + } +SkPoint prevCenter; +SkPoint prevRadii; +bool useScale; + UniformHandle fEllipseVar; + UniformHandle fScaleVar; +}; +GrGLSLFragmentProcessor* GrEllipseEffect::onCreateGLSLInstance() const { + return new GrGLSLEllipseEffect(); +} +void GrEllipseEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { + b->add32(fEdgeType); +} +bool GrEllipseEffect::onIsEqual(const GrFragmentProcessor& other) const { + const GrEllipseEffect& that = other.cast<GrEllipseEffect>(); + (void) that; + if (fEdgeType != that.fEdgeType) return false; + if (fCenter != that.fCenter) return false; + if (fRadii != that.fRadii) return false; + return true; +} +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrEllipseEffect); +#if GR_TEST_UTILS +sk_sp<GrFragmentProcessor> GrEllipseEffect::TestCreate(GrProcessorTestData* testData) { + + SkPoint center; + center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f); + center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f); + SkScalar rx = testData->fRandom->nextRangeF(0.f, 1000.f); + SkScalar ry = testData->fRandom->nextRangeF(0.f, 1000.f); + GrPrimitiveEdgeType et; + do { + et = (GrPrimitiveEdgeType) testData->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt); + } while (kHairlineAA_GrProcessorEdgeType == et); + return GrEllipseEffect::Make(et, center, SkPoint::Make(rx, ry)); +} +#endif +#endif diff --git a/src/gpu/effects/GrEllipseEffect.fp b/src/gpu/effects/GrEllipseEffect.fp new file mode 100644 index 0000000000..7bf32206fb --- /dev/null +++ b/src/gpu/effects/GrEllipseEffect.fp @@ -0,0 +1,105 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +layout(key) in int edgeType; +in vec2 center; +in vec2 radii; + +vec2 prevCenter; +vec2 prevRadii = vec2(-1); +// The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2) +// The last two terms can underflow on mediump, so we use highp. +uniform highp vec4 ellipse; + +bool useScale = sk_Caps.floatPrecisionVaries; +layout(when=useScale) uniform vec2 scale; + +@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag } + +@setData(pdman) { + if (radii != prevRadii || center != prevCenter) { + float invRXSqd; + float invRYSqd; + // If we're using a scale factor to work around precision issues, choose the larger radius + // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. + if (scale.isValid()) { + if (radii.fX > radii.fY) { + invRXSqd = 1.f; + invRYSqd = (radii.fX * radii.fX) / + (radii.fY * radii.fY); + pdman.set2f(scale, radii.fX, 1.f / radii.fX); + } else { + invRXSqd = (radii.fY * radii.fY) / + (radii.fX * radii.fX); + invRYSqd = 1.f; + pdman.set2f(scale, radii.fY, 1.f / radii.fY); + } + } else { + invRXSqd = 1.f / (radii.fX * radii.fX); + invRYSqd = 1.f / (radii.fY * radii.fY); + } + pdman.set4f(ellipse, center.fX, center.fY, invRXSqd, invRYSqd); + prevCenter = center; + prevRadii = radii; + } +} + +void main() { + // d is the offset to the ellipse center + vec2 d = sk_FragCoord.xy - ellipse.xy; + // If we're on a device with a "real" mediump then we'll do the distance computation in a space + // that is normalized by the larger radius. The scale uniform will be scale, 1/scale. The + // inverse squared radii uniform values are already in this normalized space. The center is + // not. + @if (useScale) { + d *= scale.y; + } + vec2 Z = d * ellipse.zw; + // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1. + float implicit = dot(Z, d) - 1; + // grad_dot is the squared length of the gradient of the implicit. + float grad_dot = 4 * dot(Z, Z); + // Avoid calling inversesqrt on zero. + grad_dot = max(grad_dot, 1e-4); + float approx_dist = implicit * inversesqrt(grad_dot); + @if (useScale) { + approx_dist *= scale.x; + } + + float alpha; + @switch (edgeType) { + case 0 /* kFillBW_GrProcessorEdgeType */: + alpha = approx_dist > 0.0 ? 0.0 : 1.0; + break; + case 1 /* kFillAA_GrProcessorEdgeType */: + alpha = clamp(0.5 - approx_dist, 0.0, 1.0); + break; + case 2 /* kInverseFillBW_GrProcessorEdgeType */: + alpha = approx_dist > 0.0 ? 1.0 : 0.0; + break; + case 3 /* kInverseFillAA_GrProcessorEdgeType */: + alpha = clamp(0.5 + approx_dist, 0.0, 1.0); + break; + default: + // hairline not supported + discard; + } + sk_OutColor = sk_InColor * alpha; +} + +@test(testData) { + SkPoint center; + center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f); + center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f); + SkScalar rx = testData->fRandom->nextRangeF(0.f, 1000.f); + SkScalar ry = testData->fRandom->nextRangeF(0.f, 1000.f); + GrPrimitiveEdgeType et; + do { + et = (GrPrimitiveEdgeType) testData->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt); + } while (kHairlineAA_GrProcessorEdgeType == et); + return GrEllipseEffect::Make(et, center, SkPoint::Make(rx, ry)); +}
\ No newline at end of file diff --git a/src/gpu/effects/GrEllipseEffect.h b/src/gpu/effects/GrEllipseEffect.h new file mode 100644 index 0000000000..f4a92c0bc4 --- /dev/null +++ b/src/gpu/effects/GrEllipseEffect.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * This file was autogenerated from GrEllipseEffect.fp; do not modify. + */ +#ifndef GrEllipseEffect_DEFINED +#define GrEllipseEffect_DEFINED +#include "SkTypes.h" +#if SK_SUPPORT_GPU +#include "GrFragmentProcessor.h" +#include "GrCoordTransform.h" +#include "GrColorSpaceXform.h" +#include "effects/GrProxyMove.h" +class GrEllipseEffect : public GrFragmentProcessor { +public: + int edgeType() const { return fEdgeType; } + SkPoint center() const { return fCenter; } + SkPoint radii() const { return fRadii; } + static sk_sp<GrFragmentProcessor> Make(int edgeType, SkPoint center, SkPoint radii) { + return sk_sp<GrFragmentProcessor>(new GrEllipseEffect(edgeType, center, radii)); + } + const char* name() const override { return "EllipseEffect"; } +private: + GrEllipseEffect(int edgeType, SkPoint center, SkPoint radii) + : INHERITED((OptimizationFlags) kCompatibleWithCoverageAsAlpha_OptimizationFlag ) + , fEdgeType(edgeType) + , fCenter(center) + , fRadii(radii) { + this->initClassID<GrEllipseEffect>(); + } + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + void onGetGLSLProcessorKey(const GrShaderCaps&,GrProcessorKeyBuilder*) const override; + bool onIsEqual(const GrFragmentProcessor&) const override; + GR_DECLARE_FRAGMENT_PROCESSOR_TEST + int fEdgeType; + SkPoint fCenter; + SkPoint fRadii; + typedef GrFragmentProcessor INHERITED; +}; +#endif +#endif diff --git a/src/gpu/effects/GrOvalEffect.cpp b/src/gpu/effects/GrOvalEffect.cpp index ccfc72e610..3180533146 100644 --- a/src/gpu/effects/GrOvalEffect.cpp +++ b/src/gpu/effects/GrOvalEffect.cpp @@ -8,221 +8,8 @@ #include "GrOvalEffect.h" #include "GrCircleEffect.h" -#include "GrFragmentProcessor.h" +#include "GrEllipseEffect.h" #include "SkRect.h" -#include "GrShaderCaps.h" -#include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLUniformHandler.h" -#include "../private/GrGLSL.h" - -////////////////////////////////////////////////////////////////////////////// - -class EllipseEffect : public GrFragmentProcessor { -public: - static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, const SkPoint& center, - SkScalar rx, SkScalar ry); - - ~EllipseEffect() override {} - - const char* name() const override { return "Ellipse"; } - - const SkPoint& getCenter() const { return fCenter; } - SkVector getRadii() const { return fRadii; } - - GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } - -private: - EllipseEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry); - - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - - void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; - - bool onIsEqual(const GrFragmentProcessor&) const override; - - SkPoint fCenter; - SkVector fRadii; - GrPrimitiveEdgeType fEdgeType; - - GR_DECLARE_FRAGMENT_PROCESSOR_TEST - - typedef GrFragmentProcessor INHERITED; -}; - -sk_sp<GrFragmentProcessor> EllipseEffect::Make(GrPrimitiveEdgeType edgeType, - const SkPoint& center, - SkScalar rx, - SkScalar ry) { - SkASSERT(rx >= 0 && ry >= 0); - return sk_sp<GrFragmentProcessor>(new EllipseEffect(edgeType, center, rx, ry)); -} - -EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx, - SkScalar ry) - : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag) - , fCenter(c) - , fRadii(SkVector::Make(rx, ry)) - , fEdgeType(edgeType) { - this->initClassID<EllipseEffect>(); -} - -bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const { - const EllipseEffect& ee = other.cast<EllipseEffect>(); - return fEdgeType == ee.fEdgeType && fCenter == ee.fCenter && fRadii == ee.fRadii; -} - -////////////////////////////////////////////////////////////////////////////// - -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect); - -#if GR_TEST_UTILS -sk_sp<GrFragmentProcessor> EllipseEffect::TestCreate(GrProcessorTestData* d) { - SkPoint center; - center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f); - center.fY = d->fRandom->nextRangeScalar(0.f, 1000.f); - SkScalar rx = d->fRandom->nextRangeF(0.f, 1000.f); - SkScalar ry = d->fRandom->nextRangeF(0.f, 1000.f); - GrPrimitiveEdgeType et; - do { - et = (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt); - } while (kHairlineAA_GrProcessorEdgeType == et); - return EllipseEffect::Make(et, center, rx, ry); -} -#endif - -////////////////////////////////////////////////////////////////////////////// - -class GLEllipseEffect : public GrGLSLFragmentProcessor { -public: - GLEllipseEffect() { - fPrevRadii.fX = -1.0f; - } - - void emitCode(EmitArgs&) override; - - static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); - -protected: - void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; - -private: - GrGLSLProgramDataManager::UniformHandle fEllipseUniform; - GrGLSLProgramDataManager::UniformHandle fScaleUniform; - SkPoint fPrevCenter; - SkVector fPrevRadii; - - typedef GrGLSLFragmentProcessor INHERITED; -}; - -void GLEllipseEffect::emitCode(EmitArgs& args) { - const EllipseEffect& ee = args.fFp.cast<EllipseEffect>(); - const char *ellipseName; - // The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2) - // The last two terms can underflow on mediump, so we use highp. - fEllipseUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, - kVec4f_GrSLType, kHigh_GrSLPrecision, - "ellipse", - &ellipseName); - // If we're on a device with a "real" mediump then we'll do the distance computation in a space - // that is normalized by the larger radius. The scale uniform will be scale, 1/scale. The - // inverse squared radii uniform values are already in this normalized space. The center is - // not. - const char* scaleName = nullptr; - if (args.fShaderCaps->floatPrecisionVaries()) { - fScaleUniform = args.fUniformHandler->addUniform( - kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, - "scale", &scaleName); - } - - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - - // d is the offset to the ellipse center - fragBuilder->codeAppendf("vec2 d = sk_FragCoord.xy - %s.xy;", ellipseName); - if (scaleName) { - fragBuilder->codeAppendf("d *= %s.y;", scaleName); - } - fragBuilder->codeAppendf("vec2 Z = d * %s.zw;", ellipseName); - // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1. - fragBuilder->codeAppend("float implicit = dot(Z, d) - 1.0;"); - // grad_dot is the squared length of the gradient of the implicit. - fragBuilder->codeAppendf("float grad_dot = 4.0 * dot(Z, Z);"); - // Avoid calling inversesqrt on zero. - fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);"); - fragBuilder->codeAppendf("float approx_dist = implicit * inversesqrt(grad_dot);"); - if (scaleName) { - fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName); - } - - switch (ee.getEdgeType()) { - case kFillAA_GrProcessorEdgeType: - fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);"); - break; - case kInverseFillAA_GrProcessorEdgeType: - fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); - break; - case kFillBW_GrProcessorEdgeType: - fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 0.0 : 1.0;"); - break; - case kInverseFillBW_GrProcessorEdgeType: - fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 1.0 : 0.0;"); - break; - case kHairlineAA_GrProcessorEdgeType: - SkFAIL("Hairline not expected here."); - } - - fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); -} - -void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&, - GrProcessorKeyBuilder* b) { - const EllipseEffect& ee = effect.cast<EllipseEffect>(); - b->add32(ee.getEdgeType()); -} - -void GLEllipseEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& effect) { - const EllipseEffect& ee = effect.cast<EllipseEffect>(); - if (ee.getRadii() != fPrevRadii || ee.getCenter() != fPrevCenter) { - float invRXSqd; - float invRYSqd; - // If we're using a scale factor to work around precision issues, choose the larger radius - // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. - if (fScaleUniform.isValid()) { - if (ee.getRadii().fX > ee.getRadii().fY) { - invRXSqd = 1.f; - invRYSqd = (ee.getRadii().fX * ee.getRadii().fX) / - (ee.getRadii().fY * ee.getRadii().fY); - pdman.set2f(fScaleUniform, ee.getRadii().fX, 1.f / ee.getRadii().fX); - } else { - invRXSqd = (ee.getRadii().fY * ee.getRadii().fY) / - (ee.getRadii().fX * ee.getRadii().fX); - invRYSqd = 1.f; - pdman.set2f(fScaleUniform, ee.getRadii().fY, 1.f / ee.getRadii().fY); - } - } else { - invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX); - invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY); - } - pdman.set4f(fEllipseUniform, ee.getCenter().fX, ee.getCenter().fY, invRXSqd, invRYSqd); - fPrevCenter = ee.getCenter(); - fPrevRadii = ee.getRadii(); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -void EllipseEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const { - GLEllipseEffect::GenKey(*this, caps, b); -} - -GrGLSLFragmentProcessor* EllipseEffect::onCreateGLSLInstance() const { - return new GLEllipseEffect; -} - -////////////////////////////////////////////////////////////////////////////// sk_sp<GrFragmentProcessor> GrOvalEffect::Make(GrPrimitiveEdgeType edgeType, const SkRect& oval) { if (kHairlineAA_GrProcessorEdgeType == edgeType) { @@ -236,7 +23,8 @@ sk_sp<GrFragmentProcessor> GrOvalEffect::Make(GrPrimitiveEdgeType edgeType, cons } else { w /= 2; h /= 2; - return EllipseEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), w, h); + return GrEllipseEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), + SkPoint::Make(w, h)); } return nullptr; |