From 05d9044de4f1c6e791df66a425638752daac4c6b Mon Sep 17 00:00:00 2001 From: reed Date: Thu, 12 Feb 2015 13:35:52 -0800 Subject: [PATCH] optional res-scale parameter to getFillPath BUG=skia: NOTREECHECKS=True TBR= Review URL: https://codereview.chromium.org/911053005 --- include/core/SkPaint.h | 10 ++++++++-- include/core/SkStrokeRec.h | 8 ++++---- src/core/SkDraw.cpp | 14 +++++++++++++- src/core/SkPaint.cpp | 6 +++--- src/core/SkStroke.cpp | 24 +++++++++++++----------- src/core/SkStroke.h | 15 +++++++++++++++ src/core/SkStrokeRec.cpp | 14 +++++++++----- 7 files changed, 65 insertions(+), 26 deletions(-) diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index fef4319477..50fe1f4c1d 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -512,11 +512,17 @@ public: * @param src input path * @param dst output path (may be the same as src) * @param cullRect If not null, the dst path may be culled to this rect. + * @param resScale If > 1, increase precision, else if (0 < res < 1) reduce precision + * in favor of speed/size. * @return true if the path should be filled, or false if it should be * drawn with a hairline (width == 0) */ - bool getFillPath(const SkPath& src, SkPath* dst, - const SkRect* cullRect = NULL) const; + bool getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect, + SkScalar resScale = 1) const; + + bool getFillPath(const SkPath& src, SkPath* dst) const { + return this->getFillPath(src, dst, NULL, 1); + } /** Get the paint's shader object.

diff --git a/include/core/SkStrokeRec.h b/include/core/SkStrokeRec.h index 68fa14581d..4858fce28e 100644 --- a/include/core/SkStrokeRec.h +++ b/include/core/SkStrokeRec.h @@ -21,8 +21,8 @@ public: SkStrokeRec(InitStyle style); SkStrokeRec(const SkStrokeRec&); - SkStrokeRec(const SkPaint&, SkPaint::Style); - explicit SkStrokeRec(const SkPaint&); + SkStrokeRec(const SkPaint&, SkPaint::Style, SkScalar resScale = 1); + explicit SkStrokeRec(const SkPaint&, SkScalar resScale = 1); enum Style { kHairline_Style, @@ -99,9 +99,9 @@ public: } private: - void init(const SkPaint& paint, SkPaint::Style style); - + void init(const SkPaint&, SkPaint::Style, SkScalar resScale); + SkScalar fResScale; SkScalar fWidth; SkScalar fMiterLimit; SkPaint::Cap fCap; diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index c42d3ef9ed..03b331108d 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1004,6 +1004,17 @@ DRAW_PATH: this->drawPath(path, paint, NULL, true); } +static SkScalar compute_res_scale_for_stroking(const SkMatrix& matrix) { + if (!matrix.hasPerspective()) { + SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]); + SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]); + if (SkScalarsAreFinite(sx, sy)) { + return SkTMax(sx, sy); + } + } + return 1; +} + void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, const SkMatrix* prePathMatrix, bool pathIsMutable, bool drawCoverage, SkBlitter* customBlitter) const { @@ -1072,7 +1083,8 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, if (this->computeConservativeLocalClipBounds(&cullRect)) { cullRectPtr = &cullRect; } - doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr); + doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr, + compute_res_scale_for_stroking(*fMatrix)); pathPtr = &tmpPath; } diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 7c6c8e0109..5774839ed8 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -2003,9 +2003,9 @@ SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) { /////////////////////////////////////////////////////////////////////////////// -bool SkPaint::getFillPath(const SkPath& src, SkPath* dst, - const SkRect* cullRect) const { - SkStrokeRec rec(*this); +bool SkPaint::getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect, + SkScalar resScale) const { + SkStrokeRec rec(*this, resScale); const SkPath* srcPtr = &src; SkPath tmpPath; diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp index f8173c0555..db76cafe35 100644 --- a/src/core/SkStroke.cpp +++ b/src/core/SkStroke.cpp @@ -158,12 +158,12 @@ class SkPathStroker { public: #if QUAD_STROKE_APPROXIMATION SkPathStroker(const SkPath& src, - SkScalar radius, SkScalar miterLimit, SkScalar error, SkPaint::Cap cap, - SkPaint::Join join); + SkScalar radius, SkScalar miterLimit, SkScalar error, SkPaint::Cap, + SkPaint::Join, SkScalar resScale); #else SkPathStroker(const SkPath& src, - SkScalar radius, SkScalar miterLimit, SkPaint::Cap cap, - SkPaint::Join join); + SkScalar radius, SkScalar miterLimit, SkPaint::Cap, + SkPaint::Join, SkScalar resScale); #endif void moveTo(const SkPoint&); @@ -178,12 +178,15 @@ public: dst->swap(fOuter); } + SkScalar getResScale() const { return fResScale; } + private: #if QUAD_STROKE_APPROXIMATION SkScalar fError; #endif SkScalar fRadius; SkScalar fInvMiterLimit; + SkScalar fResScale; SkVector fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal; SkPoint fFirstPt, fPrevPt; // on original path @@ -348,13 +351,13 @@ void SkPathStroker::finishContour(bool close, bool currIsLine) { #if QUAD_STROKE_APPROXIMATION SkPathStroker::SkPathStroker(const SkPath& src, SkScalar radius, SkScalar miterLimit, SkScalar error, - SkPaint::Cap cap, SkPaint::Join join) + SkPaint::Cap cap, SkPaint::Join join, SkScalar resScale) #else SkPathStroker::SkPathStroker(const SkPath& src, SkScalar radius, SkScalar miterLimit, - SkPaint::Cap cap, SkPaint::Join join) + SkPaint::Cap cap, SkPaint::Join join, SkScalar resScale) #endif - : fRadius(radius) { + : fRadius(radius), fResScale(resScale) { /* This is only used when join is miter_join, but we initialize it here so that it is always defined, to fis valgrind warnings. @@ -1429,14 +1432,13 @@ void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { } SkAutoConicToQuads converter; - const SkScalar conicTol = SK_Scalar1 / 4; + const SkScalar conicTol = SK_Scalar1 / 4 / fResScale; #if QUAD_STROKE_APPROXIMATION SkPathStroker stroker(src, radius, fMiterLimit, fError, this->getCap(), - this->getJoin()); + this->getJoin(), fResScale); #else - SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), - this->getJoin()); + SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJoin(), fResScale); #endif SkPath::Iter iter(src, false); SkPath::Verb lastSegment = SkPath::kMove_Verb; diff --git a/src/core/SkStroke.h b/src/core/SkStroke.h index cb329399a9..a5446a4178 100644 --- a/src/core/SkStroke.h +++ b/src/core/SkStroke.h @@ -52,6 +52,20 @@ public: bool getDoFill() const { return SkToBool(fDoFill); } void setDoFill(bool doFill) { fDoFill = SkToU8(doFill); } + /** + * ResScale is the "intended" resolution for the output. + * Default is 1.0. + * Larger values (res > 1) indicate that the result should be more precise, since it will + * be zoomed up, and small errors will be magnified. + * Smaller values (0 < res < 1) indicate that the result can be less precise, since it will + * be zoomed down, and small errors may be invisible. + */ + SkScalar getResScale() const { return fResScale; } + void setResScale(SkScalar rs) { + SkASSERT(rs > 0 && SkScalarIsFinite(rs)); + fResScale = rs; + } + /** * Stroke the specified rect, winding it in the specified direction.. */ @@ -66,6 +80,7 @@ private: SkScalar fError; #endif SkScalar fWidth, fMiterLimit; + SkScalar fResScale; uint8_t fCap, fJoin; SkBool8 fDoFill; diff --git a/src/core/SkStrokeRec.cpp b/src/core/SkStrokeRec.cpp index 95f56b76a6..c25a652a88 100644 --- a/src/core/SkStrokeRec.cpp +++ b/src/core/SkStrokeRec.cpp @@ -12,6 +12,7 @@ #define kStrokeRec_FillStyleWidth (-SK_Scalar1) SkStrokeRec::SkStrokeRec(InitStyle s) { + fResScale = 1; fWidth = (kFill_InitStyle == s) ? kStrokeRec_FillStyleWidth : 0; fMiterLimit = SkPaintDefaults_MiterLimit; fCap = SkPaint::kDefault_Cap; @@ -23,15 +24,17 @@ SkStrokeRec::SkStrokeRec(const SkStrokeRec& src) { memcpy(this, &src, sizeof(src)); } -SkStrokeRec::SkStrokeRec(const SkPaint& paint) { - this->init(paint, paint.getStyle()); +SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkScalar resScale) { + this->init(paint, paint.getStyle(), resScale); } -SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkPaint::Style styleOverride) { - this->init(paint, styleOverride); +SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkPaint::Style styleOverride, SkScalar resScale) { + this->init(paint, styleOverride, resScale); } -void SkStrokeRec::init(const SkPaint& paint, SkPaint::Style style) { +void SkStrokeRec::init(const SkPaint& paint, SkPaint::Style style, SkScalar resScale) { + fResScale = resScale; + switch (style) { case SkPaint::kFill_Style: fWidth = kStrokeRec_FillStyleWidth; @@ -108,6 +111,7 @@ bool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const { stroker.setMiterLimit(fMiterLimit); stroker.setWidth(fWidth); stroker.setDoFill(fStrokeAndFill); + stroker.setResScale(fResScale); #if QUAD_STROKE_APPROXIMATION stroker.setError(1); #endif