* @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.
<p />
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,
}
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;
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 {
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;
}
///////////////////////////////////////////////////////////////////////////////
-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;
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&);
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
#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.
}
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;
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..
*/
SkScalar fError;
#endif
SkScalar fWidth, fMiterLimit;
+ SkScalar fResScale;
uint8_t fCap, fJoin;
SkBool8 fDoFill;
#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;
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;
stroker.setMiterLimit(fMiterLimit);
stroker.setWidth(fWidth);
stroker.setDoFill(fStrokeAndFill);
+ stroker.setResScale(fResScale);
#if QUAD_STROKE_APPROXIMATION
stroker.setError(1);
#endif