aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2014-11-22 01:28:46 +0000
committerBen Murdoch <benm@google.com>2014-11-22 01:28:46 +0000
commit95f06ba6a33dd0b2e3d099bd692bef749afcaef5 (patch)
treefda0d92d68bd82a3c76bdc3ddaf39efd75d12aa5
parenta13fcec27143ac84f98ef27d2a743b23098bf3bd (diff)
parent275ac4234af201b1c56ed893cd39a6d396a4ca6a (diff)
downloadskia-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.txt3
-rw-r--r--gm/dashing.cpp107
-rw-r--r--include/core/SkMatrix.h4
-rw-r--r--src/core/SkBitmapProcState.cpp33
-rw-r--r--src/core/SkDraw.cpp2
-rw-r--r--src/effects/SkDashPathEffect.cpp123
-rw-r--r--src/utils/SkDashPath.cpp9
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).