Merge from Chromium at DEPS revision 39.0.2171.90

This commit was generated by merge_to_master.py.

Change-Id: Ic822d0dcb3576bf60590b10a7e242af23094897d
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 377575e..989e1f3 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -41,3 +41,6 @@
 
 # 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 55addc8..7e32bfa 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 @@
     };
 
     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 @@
     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 @@
         }
 
         show_giant_dash(canvas);
+        canvas->translate(0, SkIntToScalar(20));
+        show_zero_len_dash(canvas);
     }
 };
 
@@ -396,12 +409,86 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-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) {}
 
-static skiagm::GMRegistry gR0(F0);
-static skiagm::GMRegistry gR1(F1);
-static skiagm::GMRegistry gR2(F2);
-static skiagm::GMRegistry gR3(F3);
+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));)
+
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index 9f44bed..a65cd19 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -60,6 +60,10 @@
         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 6c1dc30..c3801e4 100644
--- a/src/core/SkBitmapProcState.cpp
+++ b/src/core/SkBitmapProcState.cpp
@@ -252,36 +252,9 @@
 
     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 e905f4b..4deefdc 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -460,7 +460,7 @@
         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 f9a56d0..412965e 100644
--- a/src/effects/SkDashPathEffect.cpp
+++ b/src/effects/SkDashPathEffect.cpp
@@ -41,6 +41,116 @@
                                       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 @@
         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 @@
 
     // 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 3c4aef3..4b2b33d 100644
--- a/src/utils/SkDashPath.cpp
+++ b/src/utils/SkDashPath.cpp
@@ -115,14 +115,15 @@
     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).