diff options
author | Ben Murdoch <benm@google.com> | 2014-11-22 01:28:46 +0000 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2014-11-22 01:28:46 +0000 |
commit | 95f06ba6a33dd0b2e3d099bd692bef749afcaef5 (patch) | |
tree | fda0d92d68bd82a3c76bdc3ddaf39efd75d12aa5 | |
parent | a13fcec27143ac84f98ef27d2a743b23098bf3bd (diff) | |
parent | 275ac4234af201b1c56ed893cd39a6d396a4ca6a (diff) | |
download | skia-95f06ba6a33dd0b2e3d099bd692bef749afcaef5.tar.gz |
Merge from Chromium at DEPS revision 39.0.2171.90
This commit was generated by merge_to_master.py.
Change-Id: Ic822d0dcb3576bf60590b10a7e242af23094897d
-rw-r--r-- | expectations/gm/ignored-tests.txt | 3 | ||||
-rw-r--r-- | gm/dashing.cpp | 107 | ||||
-rw-r--r-- | include/core/SkMatrix.h | 4 | ||||
-rw-r--r-- | src/core/SkBitmapProcState.cpp | 33 | ||||
-rw-r--r-- | src/core/SkDraw.cpp | 2 | ||||
-rw-r--r-- | src/effects/SkDashPathEffect.cpp | 123 | ||||
-rw-r--r-- | src/utils/SkDashPath.cpp | 9 |
7 files changed, 233 insertions, 48 deletions
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt index 377575eda..989e1f320 100644 --- a/expectations/gm/ignored-tests.txt +++ b/expectations/gm/ignored-tests.txt @@ -41,3 +41,6 @@ multipicturedraw_pathclip_tiled # rileya - https://codereview.chromium.org/516463005/ will rebaseline after bots cycle yuv_to_rgb_effect + +#edgdaniel https://codereview.chromium.org/703783002/ +dashing diff --git a/gm/dashing.cpp b/gm/dashing.cpp index 55addc8a6..7e32bfaf9 100644 --- a/gm/dashing.cpp +++ b/gm/dashing.cpp @@ -12,7 +12,8 @@ static void drawline(SkCanvas* canvas, int on, int off, const SkPaint& paint, SkScalar finalX = SkIntToScalar(600), SkScalar finalY = SkIntToScalar(0), - SkScalar phase = SkIntToScalar(0)) { + SkScalar phase = SkIntToScalar(0), + SkScalar startX = SkIntToScalar(0), SkScalar startY = SkIntToScalar(0)) { SkPaint p(paint); const SkScalar intervals[] = { @@ -21,7 +22,7 @@ static void drawline(SkCanvas* canvas, int on, int off, const SkPaint& paint, }; p.setPathEffect(SkDashPathEffect::Create(intervals, 2, phase))->unref(); - canvas->drawLine(0, 0, finalX, finalY, p); + canvas->drawLine(startX, startY, finalX, finalY, p); } // earlier bug stopped us from drawing very long single-segment dashes, because @@ -33,6 +34,16 @@ static void show_giant_dash(SkCanvas* canvas) { drawline(canvas, 1, 1, paint, SkIntToScalar(20 * 1000)); } +static void show_zero_len_dash(SkCanvas* canvas) { + SkPaint paint; + + drawline(canvas, 2, 2, paint, SkIntToScalar(0)); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(SkIntToScalar(2)); + canvas->translate(0, SkIntToScalar(20)); + drawline(canvas, 4, 4, paint, SkIntToScalar(0)); +} + class DashingGM : public skiagm::GM { public: DashingGM() {} @@ -80,6 +91,8 @@ protected: } show_giant_dash(canvas); + canvas->translate(0, SkIntToScalar(20)); + show_zero_len_dash(canvas); } }; @@ -396,12 +409,86 @@ protected: ////////////////////////////////////////////////////////////////////////////// -static skiagm::GM* F0(void*) { return new DashingGM; } -static skiagm::GM* F1(void*) { return new Dashing2GM; } -static skiagm::GM* F2(void*) { return new Dashing3GM; } -static skiagm::GM* F3(void*) { return new Dashing4GM; } +class Dashing5GM : public skiagm::GM { +public: + Dashing5GM(bool doAA) : fDoAA(doAA) {} + +protected: + virtual uint32_t onGetFlags() const SK_OVERRIDE { return kAsBench_Flag | kSkipTiled_Flag; } + + virtual SkString onShortName() SK_OVERRIDE { + if (fDoAA) { + return SkString("dashing5_aa"); + } else { + return SkString("dashing5_bw"); + } + } + + virtual SkISize onISize() SK_OVERRIDE { return SkISize::Make(400, 200); } + + virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { + static const int kOn = 4; + static const int kOff = 4; + static const int kIntervalLength = kOn + kOff; + + static const SkColor gColors[kIntervalLength] = { + SK_ColorRED, + SK_ColorGREEN, + SK_ColorBLUE, + SK_ColorCYAN, + SK_ColorMAGENTA, + SK_ColorYELLOW, + SK_ColorGRAY, + SK_ColorDKGRAY + }; + + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + + paint.setAntiAlias(fDoAA); + + SkMatrix rot; + rot.setRotate(90); + SkASSERT(rot.rectStaysRect()); + + canvas->concat(rot); + + int sign; // used to toggle the direction of the lines + int phase = 0; + + for (int x = 0; x < 200; x += 10) { + paint.setStrokeWidth(SkIntToScalar(phase+1)); + paint.setColor(gColors[phase]); + sign = (x % 20) ? 1 : -1; + drawline(canvas, kOn, kOff, paint, + SkIntToScalar(x), -sign * SkIntToScalar(10003), + SkIntToScalar(phase), + SkIntToScalar(x), sign * SkIntToScalar(10003)); + phase = (phase + 1) % kIntervalLength; + } + + for (int y = -400; y < 0; y += 10) { + paint.setStrokeWidth(SkIntToScalar(phase+1)); + paint.setColor(gColors[phase]); + sign = (y % 20) ? 1 : -1; + drawline(canvas, kOn, kOff, paint, + -sign * SkIntToScalar(10003), SkIntToScalar(y), + SkIntToScalar(phase), + sign * SkIntToScalar(10003), SkIntToScalar(y)); + phase = (phase + 1) % kIntervalLength; + } + } + +private: + bool fDoAA; +}; + +////////////////////////////////////////////////////////////////////////////// + +DEF_GM(return SkNEW(DashingGM);) +DEF_GM(return SkNEW(Dashing2GM);) +DEF_GM(return SkNEW(Dashing3GM);) +DEF_GM(return SkNEW(Dashing4GM);) +DEF_GM(return SkNEW_ARGS(Dashing5GM, (true));) +DEF_GM(return SkNEW_ARGS(Dashing5GM, (false));) -static skiagm::GMRegistry gR0(F0); -static skiagm::GMRegistry gR1(F1); -static skiagm::GMRegistry gR2(F2); -static skiagm::GMRegistry gR3(F3); diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h index 9f44bed9c..a65cd19f2 100644 --- a/include/core/SkMatrix.h +++ b/include/core/SkMatrix.h @@ -60,6 +60,10 @@ public: return this->getType() == 0; } + bool isScaleTranslate() const { + return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); + } + /** Returns true if will map a rectangle to another rectangle. This can be true if the matrix is identity, scale-only, or rotates a multiple of 90 degrees. diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index 6c1dc3044..c3801e440 100644 --- a/src/core/SkBitmapProcState.cpp +++ b/src/core/SkBitmapProcState.cpp @@ -252,36 +252,9 @@ bool SkBitmapProcState::possiblyScaleImage() { SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel); - /** - * Medium quality means use a mipmap for down-scaling, and just bilper - * for upscaling. Since we're examining the inverse matrix, we look for - * a scale > 1 to indicate down scaling by the CTM. - */ - if (scaleSqd > SK_Scalar1) { - fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap)); - if (NULL == fCurrMip.get()) { - fCurrMip.reset(SkMipMap::Build(fOrigBitmap)); - if (NULL == fCurrMip.get()) { - return false; - } - SkMipMapCache::Add(fOrigBitmap, fCurrMip); - } - - SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd)); - SkMipMap::Level level; - if (fCurrMip->extractLevel(levelScale, &level)) { - SkScalar invScaleFixup = level.fScale; - fInvMatrix.postScale(invScaleFixup, invScaleFixup); - - const SkImageInfo info = fOrigBitmap.info().makeWH(level.fWidth, level.fHeight); - // todo: if we could wrap the fCurrMip in a pixelref, then we could just install - // that here, and not need to explicitly track it ourselves. - fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes); - fBitmap = &fScaledBitmap; - fFilterLevel = SkPaint::kLow_FilterLevel; - return true; - } - } + // HACK: Disable use of mipmaps in M39 since they do not use discardable + // memory in the cache. + fFilterLevel = SkPaint::kLow_FilterLevel; return false; } diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index e905f4b9f..4deefdc64 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -460,7 +460,7 @@ bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint, return true; } if (paint.getStrokeCap() != SkPaint::kRound_Cap && - matrix->rectStaysRect() && SkCanvas::kPoints_PointMode == mode) { + matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) { SkScalar sx = matrix->get(SkMatrix::kMScaleX); SkScalar sy = matrix->get(SkMatrix::kMScaleY); if (SkScalarNearlyZero(sx - sy)) { diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp index f9a56d0ff..412965e88 100644 --- a/src/effects/SkDashPathEffect.cpp +++ b/src/effects/SkDashPathEffect.cpp @@ -41,6 +41,116 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, fInitialDashLength, fInitialDashIndex, fIntervalLength); } +static void outset_for_stroke(SkRect* rect, const SkStrokeRec& rec) { + SkScalar radius = SkScalarHalf(rec.getWidth()); + if (0 == radius) { + radius = SK_Scalar1; // hairlines + } + if (SkPaint::kMiter_Join == rec.getJoin()) { + radius = SkScalarMul(radius, rec.getMiter()); + } + rect->outset(radius, radius); +} + +// Attempt to trim the line to minimally cover the cull rect (currently +// only works for horizontal and vertical lines). +// Return true if processing should continue; false otherwise. +static bool cull_line(SkPoint* pts, const SkStrokeRec& rec, + const SkMatrix& ctm, const SkRect* cullRect, + const SkScalar intervalLength) { + if (NULL == cullRect) { + SkASSERT(false); // Shouldn't ever occur in practice + return false; + } + + SkScalar dx = pts[1].x() - pts[0].x(); + SkScalar dy = pts[1].y() - pts[0].y(); + + if ((dx && dy) || (!dx && !dy)) { + return false; + } + + SkRect bounds = *cullRect; + outset_for_stroke(&bounds, rec); + + // cullRect is in device space while pts are in the local coordinate system + // defined by the ctm. We want our answer in the local coordinate system. + + SkASSERT(ctm.rectStaysRect()); + SkMatrix inv; + if (!ctm.invert(&inv)) { + return false; + } + + inv.mapRect(&bounds); + + if (dx) { + SkASSERT(dx && !dy); + SkScalar minX = pts[0].fX; + SkScalar maxX = pts[1].fX; + + if (dx < 0) { + SkTSwap(minX, maxX); + } + + SkASSERT(minX < maxX); + if (maxX < bounds.fLeft || minX > bounds.fRight) { + return false; + } + + // Now we actually perform the chop, removing the excess to the left and + // right of the bounds (keeping our new line "in phase" with the dash, + // hence the (mod intervalLength). + + if (minX < bounds.fLeft) { + minX = bounds.fLeft - SkScalarMod(bounds.fLeft - minX, intervalLength); + } + if (maxX > bounds.fRight) { + maxX = bounds.fRight + SkScalarMod(maxX - bounds.fRight, intervalLength); + } + + SkASSERT(maxX > minX); + if (dx < 0) { + SkTSwap(minX, maxX); + } + pts[0].fX = minX; + pts[1].fX = maxX; + } else { + SkASSERT(dy && !dx); + SkScalar minY = pts[0].fY; + SkScalar maxY = pts[1].fY; + + if (dy < 0) { + SkTSwap(minY, maxY); + } + + SkASSERT(minY < maxY); + if (maxY < bounds.fTop || minY > bounds.fBottom) { + return false; + } + + // Now we actually perform the chop, removing the excess to the top and + // bottom of the bounds (keeping our new line "in phase" with the dash, + // hence the (mod intervalLength). + + if (minY < bounds.fTop) { + minY = bounds.fTop - SkScalarMod(bounds.fTop - minY, intervalLength); + } + if (maxY > bounds.fBottom) { + maxY = bounds.fBottom + SkScalarMod(maxY - bounds.fBottom, intervalLength); + } + + SkASSERT(maxY > minY); + if (dy < 0) { + SkTSwap(minY, maxY); + } + pts[0].fY = minY; + pts[1].fY = maxY; + } + + return true; +} + // Currently asPoints is more restrictive then it needs to be. In the future // we need to: // allow kRound_Cap capping (could allow rotations in the matrix with this) @@ -83,7 +193,12 @@ bool SkDashPathEffect::asPoints(PointData* results, return false; } - SkScalar length = SkPoint::Distance(pts[1], pts[0]); + // See if the line can be limited to something plausible. + if (!cull_line(pts, rec, matrix, cullRect, fIntervalLength)) { + return false; + } + + SkScalar length = SkPoint::Distance(pts[1], pts[0]); SkVector tangent = pts[1] - pts[0]; if (tangent.isZero()) { @@ -94,9 +209,11 @@ bool SkDashPathEffect::asPoints(PointData* results, // TODO: make this test for horizontal & vertical lines more robust bool isXAxis = true; - if (SK_Scalar1 == tangent.fX || -SK_Scalar1 == tangent.fX) { + if (SkScalarNearlyEqual(SK_Scalar1, tangent.fX) || + SkScalarNearlyEqual(-SK_Scalar1, tangent.fX)) { results->fSize.set(SkScalarHalf(fIntervals[0]), SkScalarHalf(rec.getWidth())); - } else if (SK_Scalar1 == tangent.fY || -SK_Scalar1 == tangent.fY) { + } else if (SkScalarNearlyEqual(SK_Scalar1, tangent.fY) || + SkScalarNearlyEqual(-SK_Scalar1, tangent.fY)) { results->fSize.set(SkScalarHalf(rec.getWidth()), SkScalarHalf(fIntervals[0])); isXAxis = false; } else if (SkPaint::kRound_Cap != rec.getCap()) { diff --git a/src/utils/SkDashPath.cpp b/src/utils/SkDashPath.cpp index 3c4aef343..4b2b33d2c 100644 --- a/src/utils/SkDashPath.cpp +++ b/src/utils/SkDashPath.cpp @@ -115,14 +115,15 @@ static bool cull_path(const SkPath& srcPath, const SkStrokeRec& rec, SkScalar minX = pts[0].fX; SkScalar maxX = pts[1].fX; - if (maxX < bounds.fLeft || minX > bounds.fRight) { - return false; - } - if (dx < 0) { SkTSwap(minX, maxX); } + SkASSERT(minX <= maxX); + if (maxX < bounds.fLeft || minX > bounds.fRight) { + return false; + } + // Now we actually perform the chop, removing the excess to the left and // right of the bounds (keeping our new line "in phase" with the dash, // hence the (mod intervalLength). |