Fast path translate() in SkCanvas and SkLiteDL.

This adds didTranslate() so that SkLiteDL (and other canvas recorders)
can record the translate rather than the full concat.

It also adds a case to SkMatrix::preTranslate() to fast path
translate x translate -> translate (i.e. +=).

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2255283002

Committed: https://skia.googlesource.com/skia/+/5fa47f4fd13b3158de4599414c86d17649c2dd1c

Misc bots failing in pictureimagefilter replay modes.
https://luci-milo.appspot.com/swarming/task/30b8e53f3a1f4f10/steps/dm/0/stdout

Problem is FMA vs. not.

CQ_INCLUDE_TRYBOTS=master.client.skia:
Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-Fast-Trybot

Review-Url: https://codereview.chromium.org/2255283002
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index e5ad3b8..e039c60 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1444,9 +1444,14 @@
 /////////////////////////////////////////////////////////////////////////////
 
 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
-    SkMatrix m;
-    m.setTranslate(dx, dy);
-    this->concat(m);
+    this->checkForDeferredSave();
+    fDeviceCMDirty = true;
+    fMCRec->fMatrix.preTranslate(dx,dy);
+
+    // Translate shouldn't affect the is-scale-translateness of the matrix.
+    SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
+
+    this->didTranslate(dx,dy);
 }
 
 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp
index c634d48..c3bf976 100644
--- a/src/core/SkLiteDL.cpp
+++ b/src/core/SkLiteDL.cpp
@@ -52,7 +52,7 @@
 namespace {
 #define TYPES(M)                                                                \
     M(Save) M(Restore) M(SaveLayer)                                             \
-    M(Concat) M(SetMatrix) M(TranslateZ)                                        \
+    M(Concat) M(SetMatrix) M(Translate) M(TranslateZ)                           \
     M(ClipPath) M(ClipRect) M(ClipRRect) M(ClipRegion)                          \
     M(DrawPaint) M(DrawPath) M(DrawRect) M(DrawOval) M(DrawRRect) M(DrawDRRect) \
     M(DrawAnnotation) M(DrawDrawable) M(DrawPicture) M(DrawShadowedPicture)     \
@@ -115,6 +115,14 @@
         }
         void makeThreadsafe() { make_threadsafe(nullptr, &matrix); }
     };
+    struct Translate final : Op {
+        static const auto kType = Type::Translate;
+        Translate(SkScalar dx, SkScalar dy) : dx(dx), dy(dy) {}
+        SkScalar dx,dy;
+        void draw(SkCanvas* c, const SkMatrix&) {
+            c->translate(dx, dy);
+        }
+    };
     struct TranslateZ final : Op {
         static const auto kType = Type::TranslateZ;
         TranslateZ(SkScalar dz) : dz(dz) {}
@@ -539,8 +547,9 @@
     this->push<SaveLayer>(0, bounds, paint, backdrop, flags);
 }
 
-void SkLiteDL::   concat(const SkMatrix& matrix) { this->push   <Concat>(0, matrix); }
-void SkLiteDL::setMatrix(const SkMatrix& matrix) { this->push<SetMatrix>(0, matrix); }
+void SkLiteDL::   concat(const SkMatrix& matrix)   { this->push   <Concat>(0, matrix); }
+void SkLiteDL::setMatrix(const SkMatrix& matrix)   { this->push<SetMatrix>(0, matrix); }
+void SkLiteDL::translate(SkScalar dx, SkScalar dy) { this->push<Translate>(0, dx, dy); }
 void SkLiteDL::translateZ(SkScalar dz) { this->push<TranslateZ>(0, dz); }
 
 void SkLiteDL::clipPath(const SkPath& path, SkRegion::Op op, bool aa) {
diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h
index 38a0812..e80548c 100644
--- a/src/core/SkLiteDL.h
+++ b/src/core/SkLiteDL.h
@@ -29,6 +29,7 @@
 
     void    concat (const SkMatrix&);
     void setMatrix (const SkMatrix&);
+    void translate(SkScalar, SkScalar);
     void translateZ(SkScalar);
 
     void clipPath  (const   SkPath&, SkRegion::Op, bool aa);
diff --git a/src/core/SkLiteRecorder.cpp b/src/core/SkLiteRecorder.cpp
index b61dd8f..049ccd1 100644
--- a/src/core/SkLiteRecorder.cpp
+++ b/src/core/SkLiteRecorder.cpp
@@ -29,8 +29,9 @@
 }
 void SkLiteRecorder::willRestore() { fDL->restore(); }
 
-void SkLiteRecorder::didConcat   (const SkMatrix& matrix) { fDL->   concat(matrix); }
-void SkLiteRecorder::didSetMatrix(const SkMatrix& matrix) { fDL->setMatrix(matrix); }
+void SkLiteRecorder::didConcat   (const SkMatrix& matrix)   { fDL->   concat(matrix); }
+void SkLiteRecorder::didSetMatrix(const SkMatrix& matrix)   { fDL->setMatrix(matrix); }
+void SkLiteRecorder::didTranslate(SkScalar dx, SkScalar dy) { fDL->translate(dx, dy); }
 
 void SkLiteRecorder::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle style) {
     fDL->clipRect(rect, op, style==kSoft_ClipEdgeStyle);
diff --git a/src/core/SkLiteRecorder.h b/src/core/SkLiteRecorder.h
index a924378..6ca03cd 100644
--- a/src/core/SkLiteRecorder.h
+++ b/src/core/SkLiteRecorder.h
@@ -25,6 +25,7 @@
 
     void didConcat(const SkMatrix&) override;
     void didSetMatrix(const SkMatrix&) override;
+    void didTranslate(SkScalar, SkScalar) override;
 
     void onClipRect  (const   SkRect&, SkRegion::Op, ClipEdgeStyle) override;
     void onClipRRect (const  SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index 0fd8020..fb0c69d 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -290,7 +290,12 @@
         return;
     }
 
-    if (this->hasPerspective()) {
+    if (fTypeMask <= kTranslate_Mask) {
+        fMat[kMTransX] += dx;
+        fMat[kMTransY] += dy;
+        this->setTypeMask((fMat[kMTransX] != 0 || fMat[kMTransY] != 0) ? kTranslate_Mask
+                                                                       : kIdentity_Mask);
+    } else if (this->hasPerspective()) {
         SkMatrix    m;
         m.setTranslate(dx, dy);
         this->preConcat(m);
@@ -1100,7 +1105,7 @@
 void SkMatrix::mapRectScaleTranslate(SkRect* dst, const SkRect& src) const {
     SkASSERT(dst);
     SkASSERT(this->isScaleTranslate());
-    
+
     SkScalar sx = fMat[kMScaleX];
     SkScalar sy = fMat[kMScaleY];
     SkScalar tx = fMat[kMTransX];
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index dcfc0fb..4d27fb6 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -83,6 +83,7 @@
                                                  r.saveLayerFlags)));
 DRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix)));
 DRAW(Concat, concat(r.matrix));
+DRAW(Translate, translate(r.dx, r.dy));
 
 DRAW(ClipPath, clipPath(r.path, r.opAA.op, r.opAA.aa));
 DRAW(ClipRRect, clipRRect(r.rrect, r.opAA.op, r.opAA.aa));
@@ -241,11 +242,12 @@
         SkMatrix ctm;
     };
 
-    // Only Restore, SetMatrix, and Concat change the CTM.
+    // Only Restore, SetMatrix, Concat, and Translate change the CTM.
     template <typename T> void updateCTM(const T&) {}
     void updateCTM(const Restore& op)   { fCTM = op.matrix; }
     void updateCTM(const SetMatrix& op) { fCTM = op.matrix; }
     void updateCTM(const Concat& op)    { fCTM.preConcat(op.matrix); }
+    void updateCTM(const Translate& op) { fCTM.preTranslate(op.dx, op.dy); }
 
     // Most ops don't change the clip.
     template <typename T> void updateClipBounds(const T&) {}
@@ -299,12 +301,13 @@
 
     void trackBounds(const SetMatrix&)         { this->pushControl(); }
     void trackBounds(const Concat&)            { this->pushControl(); }
+    void trackBounds(const Translate&)         { this->pushControl(); }
+    void trackBounds(const TranslateZ&)        { this->pushControl(); }
     void trackBounds(const ClipRect&)          { this->pushControl(); }
     void trackBounds(const ClipRRect&)         { this->pushControl(); }
     void trackBounds(const ClipPath&)          { this->pushControl(); }
     void trackBounds(const ClipRegion&)        { this->pushControl(); }
 
-    void trackBounds(const TranslateZ&)              { this->pushControl(); }
 
     // For all other ops, we can calculate and store the bounds directly now.
     template <typename T> void trackBounds(const T& op) {
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index b961c7d..92bb6ae 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -380,6 +380,10 @@
     APPEND(SetMatrix, matrix);
 }
 
+void SkRecorder::didTranslate(SkScalar dx, SkScalar dy) {
+    APPEND(Translate, dx, dy);
+}
+
 void SkRecorder::didTranslateZ(SkScalar z) {
 #ifdef SK_EXPERIMENTAL_SHADOWING
     APPEND(TranslateZ, z);
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index ba171a1..d039e20 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -60,6 +60,7 @@
 
     void didConcat(const SkMatrix&) override;
     void didSetMatrix(const SkMatrix&) override;
+    void didTranslate(SkScalar, SkScalar) override;
 
 #ifdef SK_EXPERIMENTAL_SHADOWING
     void didTranslateZ(SkScalar) override;