Gradient shaders: make fPtsToUnit const, pre-cache getType().

This prevents races when calling fPtsToUnit.getType() from multiple threads.

This introduces a small amount of redundant code in SkTwoPointRadialGradient,
but it's probably optimized together into no extra run-time work.

BUG=437511

Review URL: https://codereview.chromium.org/793763003
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index dce079e..0c14794 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -67,9 +67,11 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////
 
-SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc)
+SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit)
     : INHERITED(desc.fLocalMatrix)
+    , fPtsToUnit(ptsToUnit)
 {
+    fPtsToUnit.getType();  // Precache so reads are threadsafe.
     SkASSERT(desc.fCount > 1);
 
     fGradFlags = SkToU8(desc.fGradFlags);
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 72014d3..125c7b0 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -121,7 +121,7 @@
     };
 
 public:
-    SkGradientShaderBase(const Descriptor& desc);
+    SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
     virtual ~SkGradientShaderBase();
 
     // The cache is initialized on-demand when getCache16/32 is called.
@@ -223,7 +223,7 @@
     virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
     SK_TO_STRING_OVERRIDE()
 
-    SkMatrix    fPtsToUnit;     // set by subclass
+    const SkMatrix fPtsToUnit;
     TileMode    fTileMode;
     TileProc    fTileProc;
     int         fColorCount;
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 958862f..6bd5d83 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -39,25 +39,25 @@
 #pragma optimize("", on)
 #endif
 
-static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
+static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) {
     SkVector    vec = pts[1] - pts[0];
     SkScalar    mag = vec.length();
     SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
 
     vec.scale(inv);
-    matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
-    matrix->postTranslate(-pts[0].fX, -pts[0].fY);
-    matrix->postScale(inv, inv);
+    SkMatrix matrix;
+    matrix.setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
+    matrix.postTranslate(-pts[0].fX, -pts[0].fY);
+    matrix.postScale(inv, inv);
+    return matrix;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, pts_to_unit_matrix(pts))
     , fStart(pts[0])
-    , fEnd(pts[1])
-{
-    pts_to_unit_matrix(pts, &fPtsToUnit);
+    , fEnd(pts[1]) {
 }
 
 SkFlattenable* SkLinearGradient::CreateProc(SkReadBuffer& buffer) {
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index e880df2..c10c555 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -12,6 +12,8 @@
 #define kSQRT_TABLE_BITS    11
 #define kSQRT_TABLE_SIZE    (1 << kSQRT_TABLE_BITS)
 
+SK_COMPILE_ASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE, SqrtTableSizesMatch);
+
 #if 0
 
 #include <stdio.h>
@@ -55,12 +57,13 @@
     return repeat_tileproc(x);
 }
 
-void rad_to_unit_matrix(const SkPoint& center, SkScalar radius,
-                               SkMatrix* matrix) {
+SkMatrix rad_to_unit_matrix(const SkPoint& center, SkScalar radius) {
     SkScalar    inv = SkScalarInvert(radius);
 
-    matrix->setTranslate(-center.fX, -center.fY);
-    matrix->postScale(inv, inv);
+    SkMatrix matrix;
+    matrix.setTranslate(-center.fX, -center.fY);
+    matrix.postScale(inv, inv);
+    return matrix;
 }
 
 typedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx,
@@ -146,14 +149,9 @@
 /////////////////////////////////////////////////////////////////////
 
 SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, rad_to_unit_matrix(center, radius))
     , fCenter(center)
-    , fRadius(radius)
-{
-    // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
-    SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
-
-    rad_to_unit_matrix(center, radius, &fPtsToUnit);
+    , fRadius(radius) {
 }
 
 size_t SkRadialGradient::contextSize() const {
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 2493060..6e91e2b 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -8,12 +8,16 @@
 
 #include "SkSweepGradient.h"
 
+static SkMatrix translate(SkScalar dx, SkScalar dy) {
+    SkMatrix matrix;
+    matrix.setTranslate(dx, dy);
+    return matrix;
+}
+
 SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, translate(-cx, -cy))
     , fCenter(SkPoint::Make(cx, cy))
 {
-    fPtsToUnit.setTranslate(-cx, -cy);
-
     // overwrite the tilemode to a canonical value (since sweep ignores it)
     fTileMode = SkShader::kClamp_TileMode;
 }
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index 2fc848e..94751a8 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -186,18 +186,13 @@
     }
 }
 
-void SkTwoPointConicalGradient::init() {
-    fRec.init(fCenter1, fRadius1, fCenter2, fRadius2, fFlippedGrad);
-    fPtsToUnit.reset();
-}
-
 /////////////////////////////////////////////////////////////////////
 
 SkTwoPointConicalGradient::SkTwoPointConicalGradient(
         const SkPoint& start, SkScalar startRadius,
         const SkPoint& end, SkScalar endRadius,
         bool flippedGrad, const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, SkMatrix::I())
     , fCenter1(start)
     , fCenter2(end)
     , fRadius1(startRadius)
@@ -206,7 +201,7 @@
 {
     // this is degenerate, and should be caught by our caller
     SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
-    this->init();
+    fRec.init(fCenter1, fRadius1, fCenter2, fRadius2, fFlippedGrad);
 }
 
 bool SkTwoPointConicalGradient::isOpaque() const {
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.h b/src/effects/gradients/SkTwoPointConicalGradient.h
index c43f682..941d12b 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.h
+++ b/src/effects/gradients/SkTwoPointConicalGradient.h
@@ -39,8 +39,6 @@
 
 class SkTwoPointConicalGradient : public SkGradientShaderBase {
     TwoPtRadial fRec;
-    void init();
-
 public:
     SkTwoPointConicalGradient(const SkPoint& start, SkScalar startRadius,
                               const SkPoint& end, SkScalar endRadius,
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index 4fb29962..3a3921d 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -167,16 +167,33 @@
 
 /////////////////////////////////////////////////////////////////////
 
+static SkMatrix pts_to_unit(const SkPoint& start, SkScalar diffRadius) {
+    SkScalar inv = diffRadius ? SkScalarInvert(diffRadius) : 0;
+    SkMatrix matrix;
+    matrix.setTranslate(-start.fX, -start.fY);
+    matrix.postScale(inv, inv);
+    return matrix;
+}
+
 SkTwoPointRadialGradient::SkTwoPointRadialGradient(const SkPoint& start, SkScalar startRadius,
                                                    const SkPoint& end, SkScalar endRadius,
                                                    const Descriptor& desc)
-    : SkGradientShaderBase(desc)
+    : SkGradientShaderBase(desc, pts_to_unit(start, endRadius - startRadius))
     , fCenter1(start)
     , fCenter2(end)
     , fRadius1(startRadius)
     , fRadius2(endRadius)
 {
-    init();
+    fDiff = fCenter1 - fCenter2;
+    fDiffRadius = fRadius2 - fRadius1;
+    // hack to avoid zero-divide for now
+    SkScalar inv = fDiffRadius ? SkScalarInvert(fDiffRadius) : 0;
+    fDiff.fX = SkScalarMul(fDiff.fX, inv);
+    fDiff.fY = SkScalarMul(fDiff.fY, inv);
+    fStartRadius = SkScalarMul(fRadius1, inv);
+    fSr2D2 = SkScalarSquare(fStartRadius);
+    fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
+    fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
 }
 
 SkShader::BitmapType SkTwoPointRadialGradient::asABitmap(
@@ -366,22 +383,6 @@
     buffer.writeScalar(fRadius2);
 }
 
-void SkTwoPointRadialGradient::init() {
-    fDiff = fCenter1 - fCenter2;
-    fDiffRadius = fRadius2 - fRadius1;
-    // hack to avoid zero-divide for now
-    SkScalar inv = fDiffRadius ? SkScalarInvert(fDiffRadius) : 0;
-    fDiff.fX = SkScalarMul(fDiff.fX, inv);
-    fDiff.fY = SkScalarMul(fDiff.fY, inv);
-    fStartRadius = SkScalarMul(fRadius1, inv);
-    fSr2D2 = SkScalarSquare(fStartRadius);
-    fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
-    fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
-
-    fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
-    fPtsToUnit.postScale(inv, inv);
-}
-
 /////////////////////////////////////////////////////////////////////
 
 #if SK_SUPPORT_GPU
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.h b/src/effects/gradients/SkTwoPointRadialGradient.h
index da9c5fc..dff2479 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.h
+++ b/src/effects/gradients/SkTwoPointRadialGradient.h
@@ -56,8 +56,6 @@
     SkPoint fDiff;
     SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
 
-    void init();
-
     friend class SkGradientShader;
     typedef SkGradientShaderBase INHERITED;
 };