Revert of Remove unused (by clients) SkUnitMapper (https://codereview.chromium.org/283273002/) (https://codereview.chromium.org/288343009/)

Reason for revert:
required blink change failed to land

Original issue's description:
> Remove unused (by clients) SkUnitMapper (https://codereview.chromium.org/283273002/)
>
> This reverts commit dd50c83b5b34dab3a077741861b50ed1f2bc6b8f.
>
> BUG=skia:
>
> Committed: http://code.google.com/p/skia/source/detail?r=14830

R=scroggo@google.com, reed@google.com
TBR=reed@google.com, scroggo@google.com
NOTREECHECKS=true
NOTRY=true
BUG=skia:

Author: reed@chromium.org

Review URL: https://codereview.chromium.org/296823008

git-svn-id: http://skia.googlecode.com/svn/trunk@14838 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/GradientBench.cpp b/bench/GradientBench.cpp
index fa07bce..55e777d 100644
--- a/bench/GradientBench.cpp
+++ b/bench/GradientBench.cpp
@@ -13,6 +13,7 @@
 #include "SkPaint.h"
 #include "SkShader.h"
 #include "SkString.h"
+#include "SkUnitMapper.h"
 
 struct GradData {
     int             fCount;
@@ -44,33 +45,38 @@
 
 /// Ignores scale
 static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
-                            SkShader::TileMode tm, float scale) {
-    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
+                            SkShader::TileMode tm, SkUnitMapper* mapper,
+                            float scale) {
+    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+                                          data.fCount, tm, mapper);
 }
 
 static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
-                            SkShader::TileMode tm, float scale) {
+                            SkShader::TileMode tm, SkUnitMapper* mapper,
+                            float scale) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateRadial(center, center.fX * scale,
                                           data.fColors,
-                                          data.fPos, data.fCount, tm);
+                                          data.fPos, data.fCount, tm, mapper);
 }
 
 /// Ignores scale
 static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
-                           SkShader::TileMode tm, float scale) {
+                           SkShader::TileMode tm, SkUnitMapper* mapper,
+                           float scale) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
-                                         data.fPos, data.fCount);
+                                         data.fPos, data.fCount, mapper);
 }
 
 /// Ignores scale
 static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, float scale) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             float scale) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -79,12 +85,13 @@
     return SkGradientShader::CreateTwoPointRadial(
                                                   center1, (pts[1].fX - pts[0].fX) / 7,
                                                   center0, (pts[1].fX - pts[0].fX) / 2,
-                                                  data.fColors, data.fPos, data.fCount, tm);
+                                                  data.fColors, data.fPos, data.fCount, tm, mapper);
 }
 
 /// Ignores scale
 static SkShader* MakeConical(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, float scale) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             float scale) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -92,12 +99,13 @@
                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
                                                    center0, (pts[1].fX - pts[0].fX) / 2,
-                                                   data.fColors, data.fPos, data.fCount, tm);
+                                                   data.fColors, data.fPos, data.fCount, tm, mapper);
 }
 
 /// Ignores scale
 static SkShader* MakeConicalZeroRad(const SkPoint pts[2], const GradData& data,
-                                    SkShader::TileMode tm, float scale) {
+                                    SkShader::TileMode tm, SkUnitMapper* mapper,
+                                    float scale) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -105,12 +113,13 @@
                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     return SkGradientShader::CreateTwoPointConical(center1, 0.0,
                                                    center0, (pts[1].fX - pts[0].fX) / 2,
-                                                   data.fColors, data.fPos, data.fCount, tm);
+                                                   data.fColors, data.fPos, data.fCount, tm, mapper);
 }
 
 /// Ignores scale
 static SkShader* MakeConicalOutside(const SkPoint pts[2], const GradData& data,
-                                    SkShader::TileMode tm, float scale) {
+                                    SkShader::TileMode tm, SkUnitMapper* mapper,
+                                    float scale) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -119,12 +128,13 @@
     return SkGradientShader::CreateTwoPointConical(center0, radius0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm);
+                                                   data.fCount, tm, mapper);
 }
 
 /// Ignores scale
 static SkShader* MakeConicalOutsideZeroRad(const SkPoint pts[2], const GradData& data,
-                                           SkShader::TileMode tm, float scale) {
+                                           SkShader::TileMode tm, SkUnitMapper* mapper,
+                                           float scale) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -133,11 +143,12 @@
     return SkGradientShader::CreateTwoPointConical(center0, 0.0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm);
+                                                   data.fCount, tm, mapper);
 }
 
 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
-                               SkShader::TileMode tm, float scale);
+                               SkShader::TileMode tm, SkUnitMapper* mapper,
+                               float scale);
 
 static const struct {
     GradMaker   fMaker;
@@ -229,7 +240,7 @@
             { SkIntToScalar(W), SkIntToScalar(H) }
         };
 
-        fShader = gGrads[gradType].fMaker(pts, data, tm, scale);
+        fShader = gGrads[gradType].fMaker(pts, data, tm, NULL, scale);
         fGeomType = geomType;
     }
 
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 81313f1..c134382 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -51,16 +51,4 @@
 downsamplebitmap_checkerboard_high_512_256
 downsamplebitmap_image_high_mandrill_512.png
 filterbitmap_checkerboard_192_192
-downsamplebitmap_text_high_72.00pt
-
-# These are part of picture-version 27 -- removal of SkUnitMapp
-# just need to be rebaselined
-scaled_tilemode_bitmap
-scaled_tilemodes_npot
-scaled_tilemodes
-tilemode_bitmap
-tilemodes_npot
-tilemodes
-shadertext3
-shadertext
-shadertext2
+downsamplebitmap_text_high_72.00pt
\ No newline at end of file
diff --git a/experimental/SkiaExamples/HelloSkiaExample.cpp b/experimental/SkiaExamples/HelloSkiaExample.cpp
index 6fd2624..0b6c790 100644
--- a/experimental/SkiaExamples/HelloSkiaExample.cpp
+++ b/experimental/SkiaExamples/HelloSkiaExample.cpp
@@ -13,6 +13,7 @@
 #include "SkDraw.h"
 #include "SkGradientShader.h"
 #include "SkGraphics.h"
+#include "SkUnitMappers.h"
 
 class HelloSkia : public SkExample {
 public:
@@ -49,9 +50,12 @@
             };
             SkColor linearColors[] = {SK_ColorGREEN, SK_ColorBLACK};
 
+            SkUnitMapper* linearMapper = new SkDiscreteMapper(100);
+            SkAutoUnref lm_deleter(linearMapper);
+
             SkShader* shader = SkGradientShader::CreateLinear(
                     linearPoints, linearColors, NULL, 2,
-                    SkShader::kMirror_TileMode);
+                    SkShader::kMirror_TileMode, linearMapper);
             SkAutoUnref shader_deleter(shader);
 
             paint.setShader(shader);
diff --git a/experimental/webtry/templates/template.cpp b/experimental/webtry/templates/template.cpp
index 67d2c04..5b017f0 100644
--- a/experimental/webtry/templates/template.cpp
+++ b/experimental/webtry/templates/template.cpp
@@ -150,6 +150,7 @@
 #include "SkTSearch.h"
 #include "SkTypeface.h"
 #include "SkTypes.h"
+#include "SkUnitMapper.h"
 #include "SkUnPreMultiply.h"
 #include "SkUtils.h"
 #include "SkWeakRefCnt.h"
diff --git a/gm/alphagradients.cpp b/gm/alphagradients.cpp
index d108288..e63fbc9 100644
--- a/gm/alphagradients.cpp
+++ b/gm/alphagradients.cpp
@@ -29,7 +29,8 @@
         SkPaint paint;
         uint32_t flags = doPreMul ? SkGradientShader::kInterpolateColorsInPremul_Flag : 0;
         SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2,
-                                                     SkShader::kClamp_TileMode, flags, NULL);
+                                                     SkShader::kClamp_TileMode,
+                                                     NULL, flags);
         paint.setShader(s)->unref();
         canvas->drawRect(r, paint);
 
diff --git a/gm/colortype.cpp b/gm/colortype.cpp
index 2774f3a..47bc8a9 100644
--- a/gm/colortype.cpp
+++ b/gm/colortype.cpp
@@ -20,7 +20,7 @@
         SkMatrix local;
         local.setRotate(180);
         SkShader* s = SkGradientShader::CreateSweep(0,0, colors, NULL,
-                                                    SK_ARRAY_COUNT(colors), 0, &local);
+                                                    SK_ARRAY_COUNT(colors), NULL, 0, &local);
 
         SkPaint paint;
         paint.setAntiAlias(true);
diff --git a/gm/convexpolyclip.cpp b/gm/convexpolyclip.cpp
index edafea2..b76335c 100644
--- a/gm/convexpolyclip.cpp
+++ b/gm/convexpolyclip.cpp
@@ -46,7 +46,7 @@
                         colors, pos,
                         SK_ARRAY_COUNT(colors),
                         SkShader::kRepeat_TileMode,
-                        0, &mat))->unref();
+                        NULL, 0, &mat))->unref();
         canvas.drawRect(rect, paint);
         rect.inset(wScalar / 8, hScalar / 8);
         mat.preTranslate(6 * wScalar, 6 * hScalar);
diff --git a/gm/drawbitmaprect.cpp b/gm/drawbitmaprect.cpp
index 33a13f0..d9b1434 100644
--- a/gm/drawbitmaprect.cpp
+++ b/gm/drawbitmaprect.cpp
@@ -63,7 +63,7 @@
                         colors, pos,
                         SK_ARRAY_COUNT(colors),
                         SkShader::kRepeat_TileMode,
-                        0, &mat))->unref();
+                        NULL, 0, &mat))->unref();
         canvas.drawRect(rect, paint);
         rect.inset(wScalar / 8, hScalar / 8);
         mat.postScale(SK_Scalar1 / 4, SK_Scalar1 / 4);
diff --git a/gm/gradientDirtyLaundry.cpp b/gm/gradientDirtyLaundry.cpp
index baa7471..f7797e7 100644
--- a/gm/gradientDirtyLaundry.cpp
+++ b/gm/gradientDirtyLaundry.cpp
@@ -35,28 +35,33 @@
     //  { 2, gCol2, NULL },
 };
 
-static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
-    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
+    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+                                          data.fCount, tm, mapper);
 }
 
-static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
-                                          data.fPos, data.fCount, tm);
+                                          data.fPos, data.fCount, tm, mapper);
 }
 
-static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode) {
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+                           SkShader::TileMode, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
-    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
+    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+                                         data.fPos, data.fCount, mapper);
 }
 
 
-typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
-
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+                               SkShader::TileMode tm, SkUnitMapper* mapper);
 static const GradMaker gGradMakers[] = {
     MakeLinear, MakeRadial, MakeSweep,
 };
@@ -90,7 +95,7 @@
         for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
             canvas->save();
             for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
-                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm);
+                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
                 paint.setShader(shader)->unref();
                 canvas->drawRect(r, paint);
                 canvas->translate(0, SkIntToScalar(120));
diff --git a/gm/gradient_matrix.cpp b/gm/gradient_matrix.cpp
index 275acc8..4f2915a 100644
--- a/gm/gradient_matrix.cpp
+++ b/gm/gradient_matrix.cpp
@@ -63,7 +63,7 @@
 
 static SkShader* make_linear_gradient(const SkPoint pts[2], const SkMatrix& localMatrix) {
     return SkGradientShader::CreateLinear(pts, gColors, NULL, SK_ARRAY_COUNT(gColors),
-                                          SkShader::kClamp_TileMode, 0, &localMatrix);
+                                          SkShader::kClamp_TileMode, NULL, 0, &localMatrix);
 }
 
 static SkShader* make_radial_gradient(const SkPoint pts[2], const SkMatrix& localMatrix) {
@@ -72,7 +72,7 @@
                SkScalarAve(pts[0].fY, pts[1].fY));
     float radius = (center - pts[0]).length();
     return SkGradientShader::CreateRadial(center, radius, gColors, NULL, SK_ARRAY_COUNT(gColors),
-                                          SkShader::kClamp_TileMode, 0, &localMatrix);
+                                          SkShader::kClamp_TileMode, NULL, 0, &localMatrix);
 }
 
 static void draw_gradients(SkCanvas* canvas,
diff --git a/gm/gradients.cpp b/gm/gradients.cpp
index 277033b..f5abb07 100644
--- a/gm/gradients.cpp
+++ b/gm/gradients.cpp
@@ -40,31 +40,35 @@
 };
 
 static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
-                            SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                            SkShader::TileMode tm, SkUnitMapper* mapper,
+                            const SkMatrix& localMatrix) {
     return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
-                                          data.fCount, tm, 0, &localMatrix);
+                                          data.fCount, tm, mapper, 0, &localMatrix);
 }
 
 static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
-                            SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                            SkShader::TileMode tm, SkUnitMapper* mapper,
+                            const SkMatrix& localMatrix) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
-                                          data.fPos, data.fCount, tm, 0, &localMatrix);
+                                          data.fPos, data.fCount, tm, mapper, 0, &localMatrix);
 }
 
 static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
-                           SkShader::TileMode, const SkMatrix& localMatrix) {
+                           SkShader::TileMode, SkUnitMapper* mapper,
+                           const SkMatrix& localMatrix) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
-                                         data.fPos, data.fCount, 0, &localMatrix);
+                                         data.fPos, data.fCount, mapper, 0, &localMatrix);
 }
 
 static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -73,12 +77,13 @@
     return SkGradientShader::CreateTwoPointRadial(
                                                   center1, (pts[1].fX - pts[0].fX) / 7,
                                                   center0, (pts[1].fX - pts[0].fX) / 2,
-                                                  data.fColors, data.fPos, data.fCount, tm,
+                                                  data.fColors, data.fPos, data.fCount, tm, mapper,
                                                   0, &localMatrix);
 }
 
 static SkShader* Make2Conical(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -87,11 +92,13 @@
     return SkGradientShader::CreateTwoPointConical(center1, radius1,
                                                    center0, radius0,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
-                               SkShader::TileMode tm, const SkMatrix& localMatrix);
+                               SkShader::TileMode tm, SkUnitMapper* mapper,
+                               const SkMatrix& localMatrix);
 static const GradMaker gGradMakers[] = {
     MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical
 };
@@ -137,7 +144,7 @@
                     scale.postTranslate(25.f, 25.f);
                 }
 
-                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, scale);
+                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL, scale);
 
                 paint.setShader(shader);
                 canvas->drawRect(r, paint);
@@ -195,7 +202,7 @@
                 perspective.setSkewX(SkScalarDiv(SkIntToScalar((unsigned) i+1),
                                      SkIntToScalar(10)));
 
-                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, perspective);
+                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL, perspective);
 
                 paint.setShader(shader);
                 canvas->drawRect(r, paint);
@@ -320,7 +327,7 @@
         SkShader* shader = SkGradientShader::CreateRadial(
             SkPoint(center),
             SkIntToScalar(200), gColors, NULL, 5,
-            SkShader::kClamp_TileMode);
+            SkShader::kClamp_TileMode, NULL);
         paint.setShader(shader);
         canvas->drawRect(r, paint);
         shader->unref();
@@ -415,17 +422,17 @@
             SkAutoTUnref<SkShader> sweep(
                     SkGradientShader::CreateSweep(cx, cy, sweep_colors,
                                                   NULL, SK_ARRAY_COUNT(sweep_colors),
-                                                  flags[i], NULL));
+                                                  NULL, flags[i]));
             SkAutoTUnref<SkShader> radial1(
                     SkGradientShader::CreateRadial(center, radius, colors1,
                                                    NULL, SK_ARRAY_COUNT(colors1),
                                                    SkShader::kClamp_TileMode,
-                                                   flags[i], NULL));
+                                                   NULL, flags[i]));
             SkAutoTUnref<SkShader> radial2(
                     SkGradientShader::CreateRadial(center, radius, colors2,
                                                    NULL, SK_ARRAY_COUNT(colors2),
                                                    SkShader::kClamp_TileMode,
-                                                   flags[i], NULL));
+                                                   NULL, flags[i]));
             paint1.setShader(sweep);
             paint2.setShader(radial1);
             paint3.setShader(radial2);
diff --git a/gm/gradients_2pt_conical.cpp b/gm/gradients_2pt_conical.cpp
index 27f0da1..dece66e 100644
--- a/gm/gradients_2pt_conical.cpp
+++ b/gm/gradients_2pt_conical.cpp
@@ -1,10 +1,10 @@
+
 /*
  * Copyright 2014 Google Inc.
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-
 #include "gm.h"
 #include "SkGradientShader.h"
 
@@ -38,7 +38,8 @@
 };
 
 static SkShader* Make2ConicalOutside(const SkPoint pts[2], const GradData& data,
-                                     SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -47,11 +48,13 @@
     return SkGradientShader::CreateTwoPointConical(center0, radius0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 static SkShader* Make2ConicalOutsideFlip(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -60,11 +63,13 @@
     return SkGradientShader::CreateTwoPointConical(center1, radius1,
                                                    center0, radius0,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 static SkShader* Make2ConicalInside(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -72,12 +77,13 @@
                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
                                                    center0, (pts[1].fX - pts[0].fX) / 2,
-                                                   data.fColors, data.fPos, data.fCount, tm,
+                                                   data.fColors, data.fPos, data.fCount, tm, mapper,
                                                    0, &localMatrix);
 }
 
 static SkShader* Make2ConicalInsideFlip(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -85,12 +91,13 @@
                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     return SkGradientShader::CreateTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 2,
                                                    center1, (pts[1].fX - pts[0].fX) / 7,
-                                                   data.fColors, data.fPos, data.fCount, tm,
+                                                   data.fColors, data.fPos, data.fCount, tm, mapper,
                                                    0, &localMatrix);
 }
 
 static SkShader* Make2ConicalInsideCenter(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -98,12 +105,13 @@
                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     return SkGradientShader::CreateTwoPointConical(center0, (pts[1].fX - pts[0].fX) / 7,
                                                    center0, (pts[1].fX - pts[0].fX) / 2,
-                                                   data.fColors, data.fPos, data.fCount, tm,
+                                                   data.fColors, data.fPos, data.fCount, tm, mapper,
                                                    0, &localMatrix);
 }
 
 static SkShader* Make2ConicalZeroRad(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -111,12 +119,13 @@
                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     return SkGradientShader::CreateTwoPointConical(center1, 0.f,
                                                    center0, (pts[1].fX - pts[0].fX) / 2,
-                                                   data.fColors, data.fPos, data.fCount, tm,
+                                                   data.fColors, data.fPos, data.fCount, tm, mapper,
                                                    0, &localMatrix);
 }
 
 static SkShader* Make2ConicalZeroRadFlip(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -124,12 +133,13 @@
                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 2,
                                                    center0, 0.f,
-                                                   data.fColors, data.fPos, data.fCount, tm,
+                                                   data.fColors, data.fPos, data.fCount, tm, mapper,
                                                    0, &localMatrix);
 }
 
 static SkShader* Make2ConicalZeroRadCenter(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -137,12 +147,13 @@
                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     return SkGradientShader::CreateTwoPointConical(center0, 0.f,
                                                    center0, (pts[1].fX - pts[0].fX) / 2,
-                                                   data.fColors, data.fPos, data.fCount, tm,
+                                                   data.fColors, data.fPos, data.fCount, tm, mapper,
                                                    0, &localMatrix);
 }
 
 static SkShader* Make2ConicalZeroRadOutside(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = 0.f;
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -151,11 +162,13 @@
     return SkGradientShader::CreateTwoPointConical(center0, radius0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 static SkShader* Make2ConicalZeroRadFlipOutside(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = 0.f;
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -164,11 +177,13 @@
     return SkGradientShader::CreateTwoPointConical(center1, radius1,
                                                    center0, radius0,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 static SkShader* Make2ConicalEdgeX(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 7);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -178,11 +193,13 @@
     return SkGradientShader::CreateTwoPointConical(center0, radius0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 static SkShader* Make2ConicalEdgeY(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 7);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -192,10 +209,12 @@
     return SkGradientShader::CreateTwoPointConical(center0, radius0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 static SkShader* Make2ConicalZeroRadEdgeX(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = 0.f;
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -205,11 +224,13 @@
     return SkGradientShader::CreateTwoPointConical(center0, radius0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 static SkShader* Make2ConicalZeroRadEdgeY(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = 0.f;
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -219,11 +240,13 @@
     return SkGradientShader::CreateTwoPointConical(center0, radius0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 static SkShader* Make2ConicalTouchX(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 7);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -233,11 +256,13 @@
     return SkGradientShader::CreateTwoPointConical(center0, radius0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 static SkShader* Make2ConicalTouchY(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 7);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -247,11 +272,13 @@
     return SkGradientShader::CreateTwoPointConical(center0, radius0,
                                                    center1, radius1,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm, 0, &localMatrix);
+                                                   data.fCount, tm, mapper,
+                                                   0, &localMatrix);
 }
 
 static SkShader* Make2ConicalInsideSmallRad(const SkPoint pts[2], const GradData& data,
-                             SkShader::TileMode tm, const SkMatrix& localMatrix) {
+                             SkShader::TileMode tm, SkUnitMapper* mapper,
+                             const SkMatrix& localMatrix) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -259,12 +286,13 @@
                 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
     return SkGradientShader::CreateTwoPointConical(center0, 0.0000000000000000001f,
                                                    center0, (pts[1].fX - pts[0].fX) / 2,
-                                                   data.fColors, data.fPos, data.fCount, tm,
+                                                   data.fColors, data.fPos, data.fCount, tm, mapper,
                                                    0, &localMatrix);
 }
 
 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
-                               SkShader::TileMode tm, const SkMatrix& localMatrix);
+                               SkShader::TileMode tm, SkUnitMapper* mapper,
+                               const SkMatrix& localMatrix);
 
 static const GradMaker gGradMakersOutside[] = {
     Make2ConicalOutside, Make2ConicalOutsideFlip,
@@ -350,7 +378,7 @@
                     scale.postTranslate(25.f, 25.f);
                 }
 
-                SkShader* shader = gradMaker[j](pts, gGradData[i], tm, scale);
+                SkShader* shader = gradMaker[j](pts, gGradData[i], tm, NULL, scale);
                 paint.setShader(shader);
                 canvas->drawRect(r, paint);
                 shader->unref();
diff --git a/gm/gradients_no_texture.cpp b/gm/gradients_no_texture.cpp
index fcbba45..2e75c9e 100644
--- a/gm/gradients_no_texture.cpp
+++ b/gm/gradients_no_texture.cpp
@@ -26,26 +26,32 @@
     { 4, gColors, NULL },
 };
 
-static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
-    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
+    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+                                          data.fCount, tm, mapper);
 }
 
-static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
-                                          data.fPos, data.fCount, tm);
+                                          data.fPos, data.fCount, tm, mapper);
 }
 
-static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode) {
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+                           SkShader::TileMode, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
-    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
+    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+                                         data.fPos, data.fCount, mapper);
 }
 
-static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
+                             SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -54,10 +60,11 @@
     return SkGradientShader::CreateTwoPointRadial(
         center1, (pts[1].fX - pts[0].fX) / 7,
         center0, (pts[1].fX - pts[0].fX) / 2,
-        data.fColors, data.fPos, data.fCount, tm);
+        data.fColors, data.fPos, data.fCount, tm, mapper);
 }
 
-static SkShader* Make2Conical(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* Make2Conical(const SkPoint pts[2], const GradData& data,
+                              SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center0, center1;
     SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10);
     SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3);
@@ -66,12 +73,12 @@
     return SkGradientShader::CreateTwoPointConical(center1, radius1,
                                                    center0, radius0,
                                                    data.fColors, data.fPos,
-                                                   data.fCount, tm);
+                                                   data.fCount, tm, mapper);
 }
 
 
-typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
-
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+                               SkShader::TileMode tm, SkUnitMapper* mapper);
 static const GradMaker gGradMakers[] = {
     MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical,
 };
@@ -106,7 +113,7 @@
             for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); ++i) {
                 canvas->save();
                 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); ++j) {
-                    SkShader* shader = gGradMakers[j](kPts, gGradData[i], kTM);
+                    SkShader* shader = gGradMakers[j](kPts, gGradData[i], kTM, NULL);
                     paint.setShader(shader)->unref();
                     paint.setAlpha(kAlphas[a]);
                     canvas->drawRect(kRect, paint);
diff --git a/gm/shaderbounds.cpp b/gm/shaderbounds.cpp
index f82985b..f0b8b97 100644
--- a/gm/shaderbounds.cpp
+++ b/gm/shaderbounds.cpp
@@ -19,7 +19,7 @@
     colors[1] = SK_ColorYELLOW;
   }
   return SkGradientShader::CreateLinear(pts, colors, NULL, 2,
-                                        SkShader::kClamp_TileMode, 0, &localMatrix);
+                                        SkShader::kClamp_TileMode, NULL, 0, &localMatrix);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/gm/shadertext.cpp b/gm/shadertext.cpp
index 292acdd..b9e28be 100644
--- a/gm/shadertext.cpp
+++ b/gm/shadertext.cpp
@@ -1,13 +1,14 @@
+
 /*
  * Copyright 2011 Google Inc.
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-
 #include "gm.h"
 #include "SkCanvas.h"
 #include "SkGradientShader.h"
+#include "SkUnitMappers.h"
 
 namespace skiagm {
 
@@ -22,9 +23,15 @@
     SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
     SkPaint     paint;
 
+    SkUnitMapper*   um = NULL;
+
+    um = new SkCosineMapper;
+
+    SkAutoUnref au(um);
+
     paint.setDither(true);
     paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
-                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode))->unref();
+                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
     canvas.drawPaint(paint);
 }
 
@@ -54,26 +61,32 @@
     { 5, gColors, NULL },
 };
 
-static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
-    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
+    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+                                          data.fCount, tm, mapper);
 }
 
-static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
-                                          data.fPos, data.fCount, tm);
+                                          data.fPos, data.fCount, tm, mapper);
 }
 
-static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode) {
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+                           SkShader::TileMode, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
-    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
+    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+                                         data.fPos, data.fCount, mapper);
 }
 
-static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
+                           SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -82,11 +95,11 @@
     return SkGradientShader::CreateTwoPointRadial(
                             center1, (pts[1].fX - pts[0].fX) / 7,
                             center0, (pts[1].fX - pts[0].fX) / 2,
-                            data.fColors, data.fPos, data.fCount, tm);
+                            data.fColors, data.fPos, data.fCount, tm, mapper);
 }
 
-typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
-    
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+                     SkShader::TileMode tm, SkUnitMapper* mapper);
 static const GradMaker gGradMakers[] = {
     MakeLinear, MakeRadial, MakeSweep, Make2Radial
 };
@@ -141,7 +154,8 @@
             for (size_t m = 0; m < SK_ARRAY_COUNT(gGradMakers); ++m) {
                 shaders[shdIdx++] = gGradMakers[m](pts,
                                                    gGradData[d],
-                                                   SkShader::kClamp_TileMode);
+                                                   SkShader::kClamp_TileMode,
+                                                   NULL);
             }
         }
         for (size_t tx = 0; tx < SK_ARRAY_COUNT(tileModes); ++tx) {
diff --git a/gm/shadertext2.cpp b/gm/shadertext2.cpp
index 27b5175..d6a9a72 100644
--- a/gm/shadertext2.cpp
+++ b/gm/shadertext2.cpp
@@ -7,6 +7,7 @@
 #include "gm.h"
 #include "SkCanvas.h"
 #include "SkGradientShader.h"
+#include "SkUnitMappers.h"
 
 namespace skiagm {
 
@@ -25,8 +26,14 @@
 
     SkPaint     paint;
 
+    SkUnitMapper*   um = NULL;
+
+    um = new SkCosineMapper;
+
+    SkAutoUnref au(um);
+
     paint.setShader(SkGradientShader::CreateLinear(kPts0, kColors0, kPos,
-                    SK_ARRAY_COUNT(kColors0), SkShader::kClamp_TileMode))->unref();
+                    SK_ARRAY_COUNT(kColors0), SkShader::kClamp_TileMode, um))->unref();
     canvas.drawPaint(paint);
     paint.setShader(SkGradientShader::CreateLinear(kPts1, kColors1, kPos,
                     SK_ARRAY_COUNT(kColors1), SkShader::kClamp_TileMode))->unref();
diff --git a/gm/shadertext3.cpp b/gm/shadertext3.cpp
index 3c6400d..8aa6e69 100644
--- a/gm/shadertext3.cpp
+++ b/gm/shadertext3.cpp
@@ -4,10 +4,10 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-
 #include "gm.h"
 #include "SkCanvas.h"
 #include "SkGradientShader.h"
+#include "SkUnitMappers.h"
 
 namespace skiagm {
 
@@ -26,8 +26,14 @@
 
     SkPaint     paint;
 
+    SkUnitMapper*   um = NULL;
+
+    um = new SkCosineMapper;
+
+    SkAutoUnref au(um);
+
     paint.setShader(SkGradientShader::CreateLinear(kPts0, kColors0, kPos,
-                    SK_ARRAY_COUNT(kColors0), SkShader::kClamp_TileMode))->unref();
+                    SK_ARRAY_COUNT(kColors0), SkShader::kClamp_TileMode, um))->unref();
     canvas.drawPaint(paint);
     paint.setShader(SkGradientShader::CreateLinear(kPts1, kColors1, kPos,
                     SK_ARRAY_COUNT(kColors1), SkShader::kClamp_TileMode))->unref();
diff --git a/gm/tilemodes.cpp b/gm/tilemodes.cpp
index 99d3a47..e04c52a 100644
--- a/gm/tilemodes.cpp
+++ b/gm/tilemodes.cpp
@@ -16,6 +16,7 @@
 
 // effects
 #include "SkGradientShader.h"
+#include "SkUnitMappers.h"
 #include "SkBlurDrawLooper.h"
 
 static void makebm(SkBitmap* bm, SkColorType ct, int w, int h) {
@@ -28,9 +29,16 @@
     SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
     SkPaint     paint;
 
+    SkUnitMapper*   um = NULL;
+
+    um = new SkCosineMapper;
+//    um = new SkDiscreteMapper(12);
+
+    SkAutoUnref au(um);
+
     paint.setDither(true);
     paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
-                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode))->unref();
+                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
     canvas.drawPaint(paint);
 }
 
diff --git a/gm/tilemodes_scaled.cpp b/gm/tilemodes_scaled.cpp
index 88a070a..a79002b 100644
--- a/gm/tilemodes_scaled.cpp
+++ b/gm/tilemodes_scaled.cpp
@@ -17,6 +17,7 @@
 
 // effects
 #include "SkGradientShader.h"
+#include "SkUnitMappers.h"
 #include "SkBlurDrawLooper.h"
 
 static void makebm(SkBitmap* bm, SkColorType ct, int w, int h) {
@@ -29,9 +30,16 @@
     SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
     SkPaint     paint;
 
+    SkUnitMapper*   um = NULL;
+
+    um = new SkCosineMapper;
+//    um = new SkDiscreteMapper(12);
+
+    SkAutoUnref au(um);
+
     paint.setDither(true);
     paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
-                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode))->unref();
+                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
     canvas.drawPaint(paint);
 }
 
diff --git a/gyp/SampleApp.gyp b/gyp/SampleApp.gyp
index 3eb735f..edcba10 100644
--- a/gyp/SampleApp.gyp
+++ b/gyp/SampleApp.gyp
@@ -106,6 +106,7 @@
         '../samplecode/SampleTextureDomain.cpp',
         '../samplecode/SampleTiling.cpp',
         '../samplecode/SampleTinyBitmap.cpp',
+        '../samplecode/SampleUnitMapper.cpp',
         '../samplecode/SampleUnpremul.cpp',
         '../samplecode/SampleVertices.cpp',
         '../samplecode/SampleXfermodesBlur.cpp',
@@ -272,6 +273,7 @@
         [ 'skia_os == "android"', {
           'sources!': [
             '../samplecode/SampleAnimator.cpp',
+            '../samplecode/SampleUnitMapper.cpp',
           ],
           'dependencies!': [
             'animator.gyp:animator',
diff --git a/gyp/core.gypi b/gyp/core.gypi
index c5d3b00..4676432 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -307,6 +307,7 @@
         '<(skia_include_path)/core/SkTypeface.h',
         '<(skia_include_path)/core/SkTypes.h',
         '<(skia_include_path)/core/SkUnPreMultiply.h',
+        '<(skia_include_path)/core/SkUnitMapper.h',
         '<(skia_include_path)/core/SkUtils.h',
         '<(skia_include_path)/core/SkWeakRefCnt.h',
         '<(skia_include_path)/core/SkWriter32.h',
diff --git a/gyp/public_headers.gypi b/gyp/public_headers.gypi
index 7432d4c..bffcf7d 100644
--- a/gyp/public_headers.gypi
+++ b/gyp/public_headers.gypi
@@ -117,6 +117,7 @@
       'utils/win/SkIStream.h',
       'utils/win/SkTScopedComPtr.h',
       'utils/SkBoundaryPatch.h',
+      'utils/SkUnitMappers.h',
       'utils/SkPictureUtils.h',
       'utils/SkRandom.h',
       'utils/SkMeshUtils.h',
@@ -257,6 +258,7 @@
       'core/SkWriter32.h',
       'core/SkError.h',
       'core/SkPath.h',
+      'core/SkUnitMapper.h',
       'core/SkFlattenable.h',
       'core/SkTSearch.h',
       'core/SkRect.h',
diff --git a/gyp/skia_for_chromium_defines.gypi b/gyp/skia_for_chromium_defines.gypi
index 632c532..f2ed5c3 100644
--- a/gyp/skia_for_chromium_defines.gypi
+++ b/gyp/skia_for_chromium_defines.gypi
@@ -16,6 +16,7 @@
       'SK_SUPPORT_LEGACY_GETTOPDEVICE',
       'SK_SUPPORT_LEGACY_N32_NAME',
       'SK_SUPPORT_LEGACY_BUILDMIPMAP',
+      'SK_SUPPORT_LEGACY_SHADER_LOCALMATRIX',
     ],
   },
 }
diff --git a/gyp/utils.gyp b/gyp/utils.gyp
index 9009ad9..5b3d9ea 100644
--- a/gyp/utils.gyp
+++ b/gyp/utils.gyp
@@ -56,6 +56,7 @@
         '../include/utils/SkRandom.h',
         '../include/utils/SkRTConf.h',
         '../include/utils/SkProxyCanvas.h',
+        '../include/utils/SkUnitMappers.h',
         '../include/utils/SkWGL.h',
 
         '../src/utils/SkBase64.cpp',
@@ -109,6 +110,7 @@
         '../src/utils/SkThreadUtils_win.h',
         '../src/utils/SkTFitsIn.h',
         '../src/utils/SkTLogic.h',
+        '../src/utils/SkUnitMappers.cpp',
 
         #mac
         '../include/utils/mac/SkCGUtils.h',
diff --git a/include/core/SkFlattenable.h b/include/core/SkFlattenable.h
index f6d377a..ee7a433 100644
--- a/include/core/SkFlattenable.h
+++ b/include/core/SkFlattenable.h
@@ -61,7 +61,7 @@
         kSkPixelRef_Type,
         kSkRasterizer_Type,
         kSkShader_Type,
-        kSkUnused_Type,     // used to be SkUnitMapper
+        kSkUnitMapper_Type,
         kSkXfermode_Type,
     };
 
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 58335ac..e17a0d4 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -327,14 +327,13 @@
     // V24: SkTwoPointConicalGradient now has fFlipped flag for gradient flipping
     // V25: SkDashPathEffect now only writes phase and interval array when flattening
     // V26: Removed boolean from SkColorShader for inheriting color from SkPaint.
-    // V27: Remove SkUnitMapper from gradients (and skia).
 
     // Note: If the picture version needs to be increased then please follow the
     // steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw
 
     // Only SKPs within the min/current picture version range (inclusive) can be read.
     static const uint32_t MIN_PICTURE_VERSION = 19;
-    static const uint32_t CURRENT_PICTURE_VERSION = 27;
+    static const uint32_t CURRENT_PICTURE_VERSION = 26;
 
     mutable uint32_t      fUniqueID;
 
diff --git a/include/core/SkReadBuffer.h b/include/core/SkReadBuffer.h
index e962234..4da27d4 100644
--- a/include/core/SkReadBuffer.h
+++ b/include/core/SkReadBuffer.h
@@ -23,6 +23,7 @@
 #include "SkReader32.h"
 #include "SkRefCnt.h"
 #include "SkShader.h"
+#include "SkUnitMapper.h"
 #include "SkWriteBuffer.h"
 #include "SkXfermode.h"
 
@@ -44,7 +45,6 @@
         kGradientFlippedFlag_Version       = 24,
         kDashWritesPhaseIntervals_Version  = 25,
         kColorShaderNoBool_Version         = 26,
-        kNoUnitMappers_Version             = 27,
     };
 
     /**
@@ -121,13 +121,9 @@
     SkPixelRef*    readPixelRef()    { return this->readFlattenable<SkPixelRef>(); }
     SkRasterizer*  readRasterizer()  { return this->readFlattenable<SkRasterizer>(); }
     SkShader*      readShader()      { return this->readFlattenable<SkShader>(); }
+    SkUnitMapper*  readUnitMapper()  { return this->readFlattenable<SkUnitMapper>(); }
     SkXfermode*    readXfermode()    { return this->readFlattenable<SkXfermode>(); }
 
-    /**
-     *  Like readFlattenable() but explicitly just skips the data that was written for the
-     *  flattenable (or the sentinel that there wasn't one).
-     */
-    virtual void skipFlattenable();
 
     // binary data and arrays
     virtual bool readByteArray(void* value, size_t size);
diff --git a/include/core/SkUnitMapper.h b/include/core/SkUnitMapper.h
new file mode 100644
index 0000000..46f6edd
--- /dev/null
+++ b/include/core/SkUnitMapper.h
@@ -0,0 +1,37 @@
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkUnitMapper_DEFINED
+#define SkUnitMapper_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkScalar.h"
+
+#include "SkFlattenable.h"
+
+class SkUnitMapper : public SkFlattenable {
+public:
+    SK_DECLARE_INST_COUNT(SkUnitMapper)
+
+    SkUnitMapper() {}
+
+    /** Given a value in [0..0xFFFF], return a value in the same range.
+    */
+    virtual uint16_t mapUnit16(uint16_t x) = 0;
+
+    SK_DEFINE_FLATTENABLE_TYPE(SkUnitMapper)
+
+protected:
+    SkUnitMapper(SkReadBuffer& rb) : SkFlattenable(rb) {}
+
+private:
+    typedef SkFlattenable INHERITED;
+};
+
+#endif
diff --git a/include/effects/SkGradientShader.h b/include/effects/SkGradientShader.h
index a5b4f29..d9276c9 100644
--- a/include/effects/SkGradientShader.h
+++ b/include/effects/SkGradientShader.h
@@ -10,6 +10,8 @@
 
 #include "SkShader.h"
 
+class SkUnitMapper;
+
 /** \class SkGradientShader
 
     SkGradientShader hosts factories for creating subclasses of SkShader that
@@ -41,16 +43,21 @@
                         intermediate values must be strictly increasing.
         @param  count   Must be >=2. The number of colors (and pos if not NULL) entries.
         @param  mode    The tiling mode
+        @param  mapper  May be NULL. Callback to modify the spread of the colors.
     */
     static SkShader* CreateLinear(const SkPoint pts[2],
                                   const SkColor colors[], const SkScalar pos[], int count,
                                   SkShader::TileMode mode,
-                                  uint32_t flags, const SkMatrix* localMatrix);
+                                  SkUnitMapper* mapper = NULL,
+                                  uint32_t flags = 0,
+                                  const SkMatrix* localMatrix = NULL);
 
     static SkShader* CreateLinear(const SkPoint pts[2],
                                   const SkColor colors[], const SkScalar pos[], int count,
-                                  SkShader::TileMode mode) {
-        return CreateLinear(pts, colors, pos, count, mode, 0, NULL);
+                                  SkShader::TileMode mode,
+                                  uint32_t flags,
+                                  const SkMatrix* localMatrix) {
+        return CreateLinear(pts, colors, pos, count, mode, NULL, flags, localMatrix);
     }
 
     /** Returns a shader that generates a radial gradient given the center and radius.
@@ -68,16 +75,21 @@
                         intermediate values must be strictly increasing.
         @param  count   Must be >= 2. The number of colors (and pos if not NULL) entries
         @param  mode    The tiling mode
+        @param  mapper  May be NULL. Callback to modify the spread of the colors.
     */
     static SkShader* CreateRadial(const SkPoint& center, SkScalar radius,
                                   const SkColor colors[], const SkScalar pos[], int count,
                                   SkShader::TileMode mode,
-                                  uint32_t flags, const SkMatrix* localMatrix);
+                                  SkUnitMapper* mapper = NULL,
+                                  uint32_t flags = 0,
+                                  const SkMatrix* localMatrix = NULL);
 
     static SkShader* CreateRadial(const SkPoint& center, SkScalar radius,
                                   const SkColor colors[], const SkScalar pos[], int count,
-                                  SkShader::TileMode mode) {
-        return CreateRadial(center, radius, colors, pos, count, mode, 0, NULL);
+                                  SkShader::TileMode mode,
+                                  uint32_t flags,
+                                  const SkMatrix* localMatrix) {
+        return CreateRadial(center, radius, colors, pos, count, mode, NULL, flags, localMatrix);
     }
 
     /** Returns a shader that generates a radial gradient given the start position, start radius, end position and end radius.
@@ -98,19 +110,30 @@
                         intermediate values must be strictly increasing.
         @param  count   Must be >= 2. The number of colors (and pos if not NULL) entries
         @param  mode    The tiling mode
+        @param  mapper  May be NULL. Callback to modify the spread of the colors.
     */
-    static SkShader* CreateTwoPointRadial(const SkPoint& start, SkScalar startRadius,
-                                          const SkPoint& end, SkScalar endRadius,
-                                          const SkColor colors[], const SkScalar pos[], int count,
+    static SkShader* CreateTwoPointRadial(const SkPoint& start,
+                                          SkScalar startRadius,
+                                          const SkPoint& end,
+                                          SkScalar endRadius,
+                                          const SkColor colors[],
+                                          const SkScalar pos[], int count,
                                           SkShader::TileMode mode,
-                                          uint32_t flags, const SkMatrix* localMatrix);
+                                          SkUnitMapper* mapper = NULL,
+                                          uint32_t flags = 0,
+                                          const SkMatrix* localMatrix = NULL);
 
-    static SkShader* CreateTwoPointRadial(const SkPoint& start, SkScalar startRadius,
-                                          const SkPoint& end, SkScalar endRadius,
-                                          const SkColor colors[], const SkScalar pos[], int count,
-                                          SkShader::TileMode mode) {
+    static SkShader* CreateTwoPointRadial(const SkPoint& start,
+                                          SkScalar startRadius,
+                                          const SkPoint& end,
+                                          SkScalar endRadius,
+                                          const SkColor colors[],
+                                          const SkScalar pos[], int count,
+                                          SkShader::TileMode mode,
+                                          uint32_t flags,
+                                          const SkMatrix* localMatrix) {
         return CreateTwoPointRadial(start, startRadius, end, endRadius, colors, pos, count, mode,
-                                    0, NULL);
+                                    NULL, flags, localMatrix);
     }
 
     /**
@@ -119,18 +142,28 @@
      *  two circles according to the following HTML spec.
      *  http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient
      */
-    static SkShader* CreateTwoPointConical(const SkPoint& start, SkScalar startRadius,
-                                           const SkPoint& end, SkScalar endRadius,
-                                           const SkColor colors[], const SkScalar pos[], int count,
+    static SkShader* CreateTwoPointConical(const SkPoint& start,
+                                           SkScalar startRadius,
+                                           const SkPoint& end,
+                                           SkScalar endRadius,
+                                           const SkColor colors[],
+                                           const SkScalar pos[], int count,
                                            SkShader::TileMode mode,
-                                           uint32_t flags, const SkMatrix* localMatrix);
+                                           SkUnitMapper* mapper = NULL,
+                                           uint32_t flags = 0,
+                                           const SkMatrix* localMatrix = NULL);
 
-    static SkShader* CreateTwoPointConical(const SkPoint& start, SkScalar startRadius,
-                                           const SkPoint& end, SkScalar endRadius,
-                                           const SkColor colors[], const SkScalar pos[], int count,
-                                           SkShader::TileMode mode) {
+    static SkShader* CreateTwoPointConical(const SkPoint& start,
+                                           SkScalar startRadius,
+                                           const SkPoint& end,
+                                           SkScalar endRadius,
+                                           const SkColor colors[],
+                                           const SkScalar pos[], int count,
+                                           SkShader::TileMode mode,
+                                           uint32_t flags,
+                                           const SkMatrix* localMatrix) {
         return CreateTwoPointConical(start, startRadius, end, endRadius, colors, pos, count, mode,
-                                     0, NULL);
+                                     NULL, flags, localMatrix);
     }
 
     /** Returns a shader that generates a sweep gradient given a center.
@@ -147,14 +180,18 @@
                         If this is not null, the values must begin with 0, end with 1.0, and
                         intermediate values must be strictly increasing.
         @param  count   Must be >= 2. The number of colors (and pos if not NULL) entries
+        @param  mapper  May be NULL. Callback to modify the spread of the colors.
     */
     static SkShader* CreateSweep(SkScalar cx, SkScalar cy,
-                                 const SkColor colors[], const SkScalar pos[], int count,
-                                 uint32_t flags, const SkMatrix* localMatrix);
+                                 const SkColor colors[], const SkScalar pos[],
+                                 int count, SkUnitMapper* mapper = NULL,
+                                 uint32_t flags = 0,
+                                 const SkMatrix* localMatrix = NULL);
 
     static SkShader* CreateSweep(SkScalar cx, SkScalar cy,
-                                 const SkColor colors[], const SkScalar pos[], int count) {
-        return CreateSweep(cx, cy, colors, pos, count, 0, NULL);
+                                 const SkColor colors[], const SkScalar pos[], int count,
+                                 uint32_t flags, const SkMatrix* localMatrix) {
+        return CreateSweep(cx, cy, colors, pos, count, NULL, flags, localMatrix);
     }
 
     SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
index 92fe258..ea1f143 100644
--- a/samplecode/SampleAll.cpp
+++ b/samplecode/SampleAll.cpp
@@ -36,6 +36,7 @@
 #include "SkRandom.h"
 #include "SkTransparentShader.h"
 #include "SkTypeface.h"
+#include "SkUnitMappers.h"
 #include "SkUtils.h"
 #include "SkXfermode.h"
 
@@ -367,8 +368,10 @@
         SkScalar* linearPos = NULL;
         int linearCount = 2;
         SkShader::TileMode linearMode = SkShader::kMirror_TileMode;
+        SkUnitMapper* linearMapper = new SkDiscreteMapper(3);
+        SkAutoUnref unmapLinearMapper(linearMapper);
         SkShader* linear = SkGradientShader::CreateLinear(linearPoints,
-            linearColors, linearPos, linearCount, linearMode);
+            linearColors, linearPos, linearCount, linearMode, linearMapper);
 
         SkPoint radialCenter = { SkIntToScalar(25), SkIntToScalar(25) };
         SkScalar radialRadius = SkIntToScalar(25);
@@ -376,9 +379,11 @@
         SkScalar radialPos[] = { 0, SkIntToScalar(3) / 5, SkIntToScalar(1)};
         int radialCount = 3;
         SkShader::TileMode radialMode = SkShader::kRepeat_TileMode;
+        SkUnitMapper* radialMapper = new SkCosineMapper();
+        SkAutoUnref unmapRadialMapper(radialMapper);
         SkShader* radial = SkGradientShader::CreateRadial(radialCenter,
             radialRadius, radialColors, radialPos, radialCount,
-            radialMode);
+            radialMode, radialMapper);
 
         SkTransparentShader* transparentShader = new SkTransparentShader();
         SkEmbossMaskFilter::Light light;
diff --git a/samplecode/SampleGradients.cpp b/samplecode/SampleGradients.cpp
index f328d76..fead714 100644
--- a/samplecode/SampleGradients.cpp
+++ b/samplecode/SampleGradients.cpp
@@ -13,7 +13,8 @@
 static SkShader* setgrad(const SkRect& r, SkColor c0, SkColor c1) {
     SkColor colors[] = { c0, c1 };
     SkPoint pts[] = { { r.fLeft, r.fTop }, { r.fRight, r.fTop } };
-    return SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+    return SkGradientShader::CreateLinear(pts, colors, NULL, 2,
+                                          SkShader::kClamp_TileMode, NULL);
 }
 
 static void test_alphagradients(SkCanvas* canvas) {
@@ -63,26 +64,32 @@
     { 5, gColors, gPos2 }
 };
 
-static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
-    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
+    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+                                          data.fCount, tm, mapper);
 }
 
-static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
-                                          data.fPos, data.fCount, tm);
+                                          data.fPos, data.fCount, tm, mapper);
 }
 
-static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+                           SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
-    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
+    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+                                         data.fPos, data.fCount, mapper);
 }
 
-static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
+                           SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -91,22 +98,22 @@
     return SkGradientShader::CreateTwoPointRadial(
                             center1, (pts[1].fX - pts[0].fX) / 7,
                             center0, (pts[1].fX - pts[0].fX) / 2,
-                            data.fColors, data.fPos, data.fCount, tm);
+                            data.fColors, data.fPos, data.fCount, tm, mapper);
 }
 
 static SkShader* Make2RadialConcentric(const SkPoint pts[2], const GradData& data,
-                                       SkShader::TileMode tm) {
+                                       SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateTwoPointRadial(
                             center, (pts[1].fX - pts[0].fX) / 7,
                             center, (pts[1].fX - pts[0].fX) / 2,
-                            data.fColors, data.fPos, data.fCount, tm);
+                            data.fColors, data.fPos, data.fCount, tm, mapper);
 }
 
-typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
-
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+                     SkShader::TileMode tm, SkUnitMapper* mapper);
 static const GradMaker gGradMakers[] = {
     MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2RadialConcentric
 };
@@ -147,7 +154,7 @@
                 canvas->save();
                 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
                     SkShader* shader;
-                    shader = gGradMakers[j](pts, gGradData[i], (SkShader::TileMode)tm);
+                    shader = gGradMakers[j](pts, gGradData[i], (SkShader::TileMode)tm, NULL);
                     paint.setShader(shader)->unref();
                     canvas->drawRect(r, paint);
                     canvas->translate(0, SkIntToScalar(120));
diff --git a/samplecode/SampleLayers.cpp b/samplecode/SampleLayers.cpp
index 43f5d42..51f02a1 100644
--- a/samplecode/SampleLayers.cpp
+++ b/samplecode/SampleLayers.cpp
@@ -31,7 +31,7 @@
     SkColor colors[] = { 0, SK_ColorWHITE };
     SkPoint pts[] = { { 0, 0 }, { 0, SK_Scalar1*20 } };
     SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode,
-                                                 0, &localMatrix);
+                                                 NULL, 0, &localMatrix);
 
     paint->setShader(s)->unref();
     paint->setXfermodeMode(SkXfermode::kDstIn_Mode);
diff --git a/samplecode/SamplePatch.cpp b/samplecode/SamplePatch.cpp
index fe94bbf..09eb42f 100644
--- a/samplecode/SamplePatch.cpp
+++ b/samplecode/SamplePatch.cpp
@@ -42,7 +42,7 @@
                       { SkIntToScalar(size.fX), SkIntToScalar(size.fY) } };
     SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
     return SkGradientShader::CreateLinear(pts, colors, NULL,
-                    SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode);
+                    SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/samplecode/SampleShaderText.cpp b/samplecode/SampleShaderText.cpp
index 6f23a0b..c7048ab 100644
--- a/samplecode/SampleShaderText.cpp
+++ b/samplecode/SampleShaderText.cpp
@@ -1,14 +1,15 @@
+
 /*
  * Copyright 2011 Google Inc.
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-
 #include "SampleCode.h"
 #include "SkView.h"
 #include "SkCanvas.h"
 #include "SkGradientShader.h"
+#include "SkUnitMappers.h"
 
 static void makebm(SkBitmap* bm, int w, int h) {
     bm->allocN32Pixels(w, h);
@@ -21,9 +22,15 @@
     SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
     SkPaint     paint;
 
+    SkUnitMapper*   um = NULL;
+
+    um = new SkCosineMapper;
+
+    SkAutoUnref au(um);
+
     paint.setDither(true);
     paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
-                                    SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode))->unref();
+                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
     canvas.drawPaint(paint);
 }
 
@@ -53,26 +60,32 @@
     { 5, gColors, NULL },
 };
 
-static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
-    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
+    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+                                          data.fCount, tm, mapper);
 }
 
-static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
-                                          data.fPos, data.fCount, tm);
+                                          data.fPos, data.fCount, tm, mapper);
 }
 
-static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+                           SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
-    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
+    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+                                         data.fPos, data.fCount, mapper);
 }
 
-static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
+                           SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -81,11 +94,11 @@
     return SkGradientShader::CreateTwoPointRadial(
                             center1, (pts[1].fX - pts[0].fX) / 7,
                             center0, (pts[1].fX - pts[0].fX) / 2,
-                            data.fColors, data.fPos, data.fCount, tm);
+                            data.fColors, data.fPos, data.fCount, tm, mapper);
 }
 
-typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
-
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+                     SkShader::TileMode tm, SkUnitMapper* mapper);
 static const GradMaker gGradMakers[] = {
     MakeLinear, MakeRadial, MakeSweep, Make2Radial
 };
@@ -139,7 +152,8 @@
             for (size_t m = 0; m < SK_ARRAY_COUNT(gGradMakers); ++m) {
                 shaders[shdIdx++] = gGradMakers[m](pts,
                                                    gGradData[d],
-                                                   SkShader::kClamp_TileMode);
+                                                   SkShader::kClamp_TileMode,
+                                                   NULL);
             }
         }
         for (size_t tx = 0; tx < SK_ARRAY_COUNT(tileModes); ++tx) {
diff --git a/samplecode/SampleSlides.cpp b/samplecode/SampleSlides.cpp
index 6bc9a28..d828ae6 100644
--- a/samplecode/SampleSlides.cpp
+++ b/samplecode/SampleSlides.cpp
@@ -178,26 +178,32 @@
 { 5, gColors, gPos2 }
 };
 
-static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
-    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm);
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
+    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+                                          data.fCount, tm, mapper);
 }
 
-static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+                            SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
     return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
-                                          data.fPos, data.fCount, tm);
+                                          data.fPos, data.fCount, tm, mapper);
 }
 
-static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+                           SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center;
     center.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
-    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount);
+    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+                                         data.fPos, data.fCount, mapper);
 }
 
-static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm) {
+static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
+                             SkShader::TileMode tm, SkUnitMapper* mapper) {
     SkPoint center0, center1;
     center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                 SkScalarAve(pts[0].fY, pts[1].fY));
@@ -206,10 +212,11 @@
     return SkGradientShader::CreateTwoPointRadial(
                                                   center1, (pts[1].fX - pts[0].fX) / 7,
                                                   center0, (pts[1].fX - pts[0].fX) / 2,
-                                                  data.fColors, data.fPos, data.fCount, tm);
+                                                  data.fColors, data.fPos, data.fCount, tm, mapper);
 }
 
-typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, SkShader::TileMode tm);
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+                               SkShader::TileMode tm, SkUnitMapper* mapper);
 static const GradMaker gGradMakers[] = {
     MakeLinear, MakeRadial, MakeSweep, Make2Radial
 };
@@ -229,7 +236,7 @@
     for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
         canvas->save();
         for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
-            SkShader* shader = gGradMakers[j](pts, gGradData[i], tm);
+            SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
             paint.setShader(shader);
             canvas->drawRect(r, paint);
             shader->unref();
@@ -328,7 +335,7 @@
                       { SkIntToScalar(size.fX), SkIntToScalar(size.fY) } };
     SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
     return SkGradientShader::CreateLinear(pts, colors, NULL,
-                                          SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode);
+                                          SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
 }
 
 class Rec {
diff --git a/samplecode/SampleTiling.cpp b/samplecode/SampleTiling.cpp
index a59a802..cc3b529 100644
--- a/samplecode/SampleTiling.cpp
+++ b/samplecode/SampleTiling.cpp
@@ -21,6 +21,7 @@
 
 // effects
 #include "SkGradientShader.h"
+#include "SkUnitMappers.h"
 #include "SkBlurMask.h"
 #include "SkBlurDrawLooper.h"
 
@@ -34,9 +35,16 @@
     SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
     SkPaint     paint;
 
+    SkUnitMapper*   um = NULL;
+
+    um = new SkCosineMapper;
+//    um = new SkDiscreteMapper(12);
+
+    SkAutoUnref au(um);
+
     paint.setDither(true);
     paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
-                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode))->unref();
+                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
     canvas.drawPaint(paint);
 }
 
diff --git a/samplecode/SampleUnitMapper.cpp b/samplecode/SampleUnitMapper.cpp
new file mode 100644
index 0000000..db9af09
--- /dev/null
+++ b/samplecode/SampleUnitMapper.cpp
@@ -0,0 +1,172 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkUnitMappers.h"
+#include "SkCubicInterval.h"
+
+#include "SkWidgetViews.h"
+
+static SkStaticTextView* make_textview(SkView* parent,
+                                       const SkRect& bounds,
+                                       const SkPaint& paint) {
+    SkStaticTextView* view = new SkStaticTextView;
+    view->setMode(SkStaticTextView::kFixedSize_Mode);
+    view->setPaint(paint);
+    view->setVisibleP(true);
+    view->setSize(bounds.width(), bounds.height());
+    view->setLoc(bounds.fLeft, bounds.fTop);
+    parent->attachChildToFront(view)->unref();
+    return view;
+}
+
+static void set_scalar(SkStaticTextView* view, SkScalar value) {
+    SkString str;
+    str.appendScalar(value);
+    view->setText(str);
+}
+
+class UnitMapperView : public SampleView {
+    SkPoint fPts[4];
+    SkMatrix fMatrix;
+    SkStaticTextView* fViews[4];
+
+    void setViews() {
+        set_scalar(fViews[0], fPts[1].fX);
+        set_scalar(fViews[1], fPts[1].fY);
+        set_scalar(fViews[2], fPts[2].fX);
+        set_scalar(fViews[3], fPts[2].fY);
+    }
+
+public:
+    UnitMapperView() {
+        fPts[0].set(0, 0);
+        fPts[1].set(SK_Scalar1 / 3, SK_Scalar1 / 3);
+        fPts[2].set(SK_Scalar1 * 2 / 3, SK_Scalar1 * 2 / 3);
+        fPts[3].set(SK_Scalar1, SK_Scalar1);
+
+        fMatrix.setScale(SK_Scalar1 * 200, -SK_Scalar1 * 200);
+        fMatrix.postTranslate(SkIntToScalar(100), SkIntToScalar(300));
+
+        SkRect r = {
+            SkIntToScalar(350), SkIntToScalar(100),
+            SkIntToScalar(500), SkIntToScalar(130)
+        };
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setTextSize(SkIntToScalar(25));
+        for (int i = 0; i < 4; i++) {
+            fViews[i] = make_textview(this, r, paint);
+            r.offset(0, r.height());
+        }
+        this->setViews();
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "UnitMapper");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    virtual void onDrawContent(SkCanvas* canvas) {
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setColor(0xFF8888FF);
+
+        SkRect r = { 0, 0, SK_Scalar1, SK_Scalar1 };
+
+        canvas->concat(fMatrix);
+        canvas->drawRect(r, paint);
+
+        paint.setColor(SK_ColorBLACK);
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setStrokeWidth(0);
+        paint.setStrokeCap(SkPaint::kRound_Cap);
+
+        SkPath path;
+        path.moveTo(fPts[0]);
+        path.cubicTo(fPts[1], fPts[2], fPts[3]);
+        canvas->drawPath(path, paint);
+
+        paint.setColor(SK_ColorRED);
+        paint.setStrokeWidth(0);
+        canvas->drawLine(0, 0, SK_Scalar1, SK_Scalar1, paint);
+
+        paint.setColor(SK_ColorBLUE);
+        paint.setStrokeWidth(SK_Scalar1 / 60);
+        for (int i = 0; i < 50; i++) {
+            SkScalar x = i * SK_Scalar1 / 49;
+            canvas->drawPoint(x, SkEvalCubicInterval(&fPts[1], x), paint);
+        }
+
+        paint.setStrokeWidth(SK_Scalar1 / 20);
+        paint.setColor(SK_ColorGREEN);
+        canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, &fPts[1], paint);
+    }
+
+    bool invertPt(SkScalar x, SkScalar y, SkPoint* result) {
+        if (NULL == result)
+            return true;
+
+        SkMatrix m;
+        if (!fMatrix.invert(&m)) {
+            return false;
+        }
+
+        m.mapXY(x, y, result);
+        return true;
+    }
+
+    int hittest(SkScalar x, SkScalar y) {
+        SkPoint target = { x, y };
+        SkPoint pts[2] = { fPts[1], fPts[2] };
+        fMatrix.mapPoints(pts, 2);
+        for (int i = 0; i < 2; i++) {
+            if (SkPoint::Distance(pts[i], target) < SkIntToScalar(4)) {
+                return i + 1;
+            }
+        }
+        return -1;
+    }
+
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned) SK_OVERRIDE {
+        fDragIndex = hittest(x, y);
+        return fDragIndex >= 0 ? new Click(this) : NULL;
+    }
+
+    virtual bool onClick(Click* click) {
+        if (fDragIndex >= 0) {
+            if (!invertPt(click->fCurr.fX, click->fCurr.fY,
+                          &fPts[fDragIndex])) {
+                return false;
+            }
+
+            this->setViews();
+            this->inval(NULL);
+            return true;
+        }
+        return false;
+    }
+
+private:
+    int fDragIndex;
+
+    typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new UnitMapperView; }
+static SkViewRegister reg(MyFactory);
diff --git a/samplecode/SampleVertices.cpp b/samplecode/SampleVertices.cpp
index 1e568f5..4c3a17e 100644
--- a/samplecode/SampleVertices.cpp
+++ b/samplecode/SampleVertices.cpp
@@ -47,7 +47,7 @@
                       { SkIntToScalar(size.fX), SkIntToScalar(size.fY) } };
     SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
     return SkGradientShader::CreateLinear(pts, colors, NULL,
-                    SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode);
+                    SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
 }
 
 class VerticesView : public SampleView {
diff --git a/src/animator/SkDrawGradient.cpp b/src/animator/SkDrawGradient.cpp
index 70e5e44..c115595 100644
--- a/src/animator/SkDrawGradient.cpp
+++ b/src/animator/SkDrawGradient.cpp
@@ -11,6 +11,49 @@
 #include "SkAnimateMaker.h"
 #include "SkAnimatorScript.h"
 #include "SkGradientShader.h"
+#include "SkUnitMapper.h"
+
+static SkScalar SkUnitToScalar(U16CPU x) {
+    return x / 65535.0f;
+}
+
+static U16CPU SkScalarToUnit(SkScalar x) {
+    SkScalar pin =  SkScalarPin(x, 0, SK_Scalar1);
+    return (int) (pin * 65535.0f);
+}
+
+class SkDrawGradientUnitMapper : public SkUnitMapper {
+public:
+    SkDrawGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) {
+    }
+
+    SK_DECLARE_UNFLATTENABLE_OBJECT()
+
+protected:
+    virtual uint16_t mapUnit16(uint16_t x) {
+        fUnit = SkUnitToScalar(x);
+        SkScriptValue value;
+        SkAnimatorScript engine(*fMaker, NULL, SkType_Float);
+        engine.propertyCallBack(GetUnitValue, &fUnit);
+        if (engine.evaluate(fScript, &value, SkType_Float))
+            x = SkScalarToUnit(value.fOperand.fScalar);
+        return x;
+    }
+
+    static bool GetUnitValue(const char* token, size_t len, void* unitPtr, SkScriptValue* value) {
+        if (SK_LITERAL_STR_EQUAL("unit", token, len)) {
+            value->fOperand.fScalar = *(SkScalar*) unitPtr;
+            value->fType = SkType_Float;
+            return true;
+        }
+        return false;
+    }
+
+    SkAnimateMaker* fMaker;
+    const char* fScript;
+    SkScalar fUnit;
+};
+
 
 #if SK_USE_CONDENSED_INFO == 0
 
@@ -24,12 +67,13 @@
 
 DEFINE_GET_MEMBER(SkDrawGradient);
 
-SkDrawGradient::SkDrawGradient() {
+SkDrawGradient::SkDrawGradient() : fUnitMapper(NULL) {
 }
 
 SkDrawGradient::~SkDrawGradient() {
     for (int index = 0; index < fDrawColors.count(); index++)
         delete fDrawColors[index];
+    delete fUnitMapper;
 }
 
 bool SkDrawGradient::addChild(SkAnimateMaker& , SkDisplayable* child) {
@@ -94,6 +138,8 @@
             }
         }
     }
+    if (unitMapper.size() > 0)
+        fUnitMapper = new SkDrawGradientUnitMapper(&maker, unitMapper.c_str());
     INHERITED::onEndElement(maker);
 }
 
@@ -130,7 +176,7 @@
         return NULL;
     SkShader* shader = SkGradientShader::CreateLinear((SkPoint*)points.begin(),
         fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode,
-        0, getMatrix());
+        fUnitMapper, 0, getMatrix());
     SkAutoTDelete<SkShader> autoDel(shader);
     (void)autoDel.detach();
     return shader;
@@ -165,7 +211,7 @@
         return NULL;
     SkShader* shader = SkGradientShader::CreateRadial(center,
         radius, fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode,
-        0, getMatrix());
+        fUnitMapper, 0, getMatrix());
     SkAutoTDelete<SkShader> autoDel(shader);
     (void)autoDel.detach();
     return shader;
diff --git a/src/animator/SkDrawGradient.h b/src/animator/SkDrawGradient.h
index fa46a9e..ff79e3f 100644
--- a/src/animator/SkDrawGradient.h
+++ b/src/animator/SkDrawGradient.h
@@ -14,6 +14,8 @@
 #include "SkDrawShader.h"
 #include "SkIntArray.h"
 
+class SkUnitMapper;
+
 class SkDrawGradient : public SkDrawShader {
     DECLARE_PRIVATE_MEMBER_INFO(DrawGradient);
     SkDrawGradient();
@@ -28,6 +30,7 @@
     SkString unitMapper;
     SkTDColorArray fColors;
     SkTDDrawColorArray fDrawColors;
+    SkUnitMapper* fUnitMapper;
     int addPrelude();
 private:
     typedef SkDrawShader INHERITED;
diff --git a/src/core/SkReadBuffer.cpp b/src/core/SkReadBuffer.cpp
index c32c7bd..d016d9c 100644
--- a/src/core/SkReadBuffer.cpp
+++ b/src/core/SkReadBuffer.cpp
@@ -335,25 +335,3 @@
     }
     return obj;
 }
-
-/**
- *  Needs to follow the same pattern as readFlattenable(), but explicitly skip whatever data
- *  has been written.
- */
-void SkReadBuffer::skipFlattenable() {
-    if (fFactoryCount > 0) {
-        if (0 == fReader.readU32()) {
-            return;
-        }
-    } else if (fFactoryTDArray) {
-        if (0 == fReader.readU32()) {
-            return;
-        }
-    } else {
-        if (NULL == this->readFunctionPtr()) {
-            return;
-        }
-    }
-    uint32_t sizeRecorded = fReader.readU32();
-    fReader.skip(sizeRecorded);
-}
diff --git a/src/core/SkValidatingReadBuffer.cpp b/src/core/SkValidatingReadBuffer.cpp
index 96f20a2..0112f18 100644
--- a/src/core/SkValidatingReadBuffer.cpp
+++ b/src/core/SkValidatingReadBuffer.cpp
@@ -273,15 +273,3 @@
     }
     return obj;
 }
-
-void SkValidatingReadBuffer::skipFlattenable() {
-    SkString name;
-    this->readString(&name);
-    if (fError) {
-        return;
-    }
-    uint32_t sizeRecorded = this->readUInt();
-    this->skip(sizeRecorded);
-}
-
-
diff --git a/src/core/SkValidatingReadBuffer.h b/src/core/SkValidatingReadBuffer.h
index 12f5413..d5e192e 100644
--- a/src/core/SkValidatingReadBuffer.h
+++ b/src/core/SkValidatingReadBuffer.h
@@ -40,7 +40,6 @@
 
     // common data structures
     virtual SkFlattenable* readFlattenable(SkFlattenable::Type type) SK_OVERRIDE;
-    virtual void skipFlattenable() SK_OVERRIDE;
     virtual void readPoint(SkPoint* point) SK_OVERRIDE;
     virtual void readMatrix(SkMatrix* matrix) SK_OVERRIDE;
     virtual void readIRect(SkIRect* rect) SK_OVERRIDE;
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index ada9859..e43a026 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -17,6 +17,8 @@
 {
     SkASSERT(desc.fCount > 1);
 
+    fMapper = desc.fMapper;
+    SkSafeRef(fMapper);
     fGradFlags = SkToU8(desc.fGradFlags);
 
     SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
@@ -140,10 +142,7 @@
 }
 
 SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buffer) {
-    if (buffer.isVersionLT(SkReadBuffer::kNoUnitMappers_Version)) {
-        // skip the old SkUnitMapper slot
-        buffer.skipFlattenable();
-    }
+    fMapper = buffer.readUnitMapper();
 
     int colorCount = fColorCount = buffer.getArrayCount();
     if (colorCount > kColorStorageCount) {
@@ -182,6 +181,7 @@
     if (fOrigColors != fStorage) {
         sk_free(fOrigColors);
     }
+    SkSafeUnref(fMapper);
 }
 
 void SkGradientShaderBase::initCommon() {
@@ -194,6 +194,7 @@
 
 void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
     this->INHERITED::flatten(buffer);
+    buffer.writeFlattenable(fMapper);
     buffer.writeColorArray(fOrigColors, fColorCount);
     buffer.writeUInt(pack_mode_flags(fTileMode, fGradFlags));
     if (fColorCount > 2) {
@@ -515,6 +516,20 @@
             prevIndex = nextIndex;
         }
     }
+
+    if (cache->fShader.fMapper) {
+        cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
+        uint16_t* linear = cache->fCache16;         // just computed linear data
+        uint16_t* mapped = cache->fCache16Storage;  // storage for mapped data
+        SkUnitMapper* map = cache->fShader.fMapper;
+        for (int i = 0; i < kCache16Count; i++) {
+            int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift;
+            mapped[i] = linear[index];
+            mapped[i + kCache16Count] = linear[index + kCache16Count];
+        }
+        sk_free(cache->fCache16);
+        cache->fCache16 = cache->fCache16Storage;
+    }
 }
 
 const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() {
@@ -552,6 +567,23 @@
             prevIndex = nextIndex;
         }
     }
+
+    if (cache->fShader.fMapper) {
+        SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL);
+        SkPMColor* linear = cache->fCache32;           // just computed linear data
+        SkPMColor* mapped = (SkPMColor*)newPR->getAddr();    // storage for mapped data
+        SkUnitMapper* map = cache->fShader.fMapper;
+        for (int i = 0; i < kCache32Count; i++) {
+            int index = map->mapUnit16((i << 8) | i) >> 8;
+            mapped[i + kCache32Count*0] = linear[index + kCache32Count*0];
+            mapped[i + kCache32Count*1] = linear[index + kCache32Count*1];
+            mapped[i + kCache32Count*2] = linear[index + kCache32Count*2];
+            mapped[i + kCache32Count*3] = linear[index + kCache32Count*3];
+        }
+        cache->fCache32PixelRef->unref();
+        cache->fCache32PixelRef = newPR;
+        cache->fCache32 = (SkPMColor*)newPR->getAddr();
+    }
 }
 
 /*
@@ -583,6 +615,15 @@
     // built with 0xFF
     SkAutoTUnref<GradientShaderCache> cache(this->refCache(0xFF));
 
+    // don't have a way to put the mapper into our cache-key yet
+    if (fMapper) {
+        // force our cache32pixelref to be built
+        (void)cache->getCache32();
+        bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1));
+        bitmap->setPixelRef(cache->getCache32PixelRef());
+        return;
+    }
+
     // build our key: [numColors + colors[] + {positions[]} + flags ]
     int count = 1 + fColorCount + 1;
     if (fColorCount > 2) {
@@ -691,6 +732,8 @@
     str->append(" ");
     str->append(gTileModeName[fTileMode]);
 
+    // TODO: add "fMapper->toString(str);" when SkUnitMapper::toString is added
+
     this->INHERITED::toString(str);
 }
 #endif
@@ -715,11 +758,13 @@
 static void desc_init(SkGradientShaderBase::Descriptor* desc,
                       const SkColor colors[],
                       const SkScalar pos[], int colorCount,
-                      SkShader::TileMode mode, uint32_t flags) {
+                      SkShader::TileMode mode,
+                      SkUnitMapper* mapper, uint32_t flags) {
     desc->fColors       = colors;
     desc->fPos          = pos;
     desc->fCount        = colorCount;
     desc->fTileMode     = mode;
+    desc->fMapper       = mapper;
     desc->fGradFlags    = flags;
 }
 
@@ -727,6 +772,7 @@
                                          const SkColor colors[],
                                          const SkScalar pos[], int colorCount,
                                          SkShader::TileMode mode,
+                                         SkUnitMapper* mapper,
                                          uint32_t flags,
                                          const SkMatrix* localMatrix) {
     if (NULL == pts || NULL == colors || colorCount < 1) {
@@ -735,7 +781,7 @@
     EXPAND_1_COLOR(colorCount);
 
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, mode, flags);
+    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
     return SkNEW_ARGS(SkLinearGradient, (pts, desc, localMatrix));
 }
 
@@ -743,6 +789,7 @@
                                          const SkColor colors[],
                                          const SkScalar pos[], int colorCount,
                                          SkShader::TileMode mode,
+                                         SkUnitMapper* mapper,
                                          uint32_t flags,
                                          const SkMatrix* localMatrix) {
     if (radius <= 0 || NULL == colors || colorCount < 1) {
@@ -751,7 +798,7 @@
     EXPAND_1_COLOR(colorCount);
 
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, mode, flags);
+    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
     return SkNEW_ARGS(SkRadialGradient, (center, radius, desc, localMatrix));
 }
 
@@ -763,6 +810,7 @@
                                                  const SkScalar pos[],
                                                  int colorCount,
                                                  SkShader::TileMode mode,
+                                                 SkUnitMapper* mapper,
                                                  uint32_t flags,
                                                  const SkMatrix* localMatrix) {
     if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
@@ -771,7 +819,7 @@
     EXPAND_1_COLOR(colorCount);
 
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, mode, flags);
+    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
     return SkNEW_ARGS(SkTwoPointRadialGradient,
                       (start, startRadius, end, endRadius, desc, localMatrix));
 }
@@ -784,6 +832,7 @@
                                                   const SkScalar pos[],
                                                   int colorCount,
                                                   SkShader::TileMode mode,
+                                                  SkUnitMapper* mapper,
                                                   uint32_t flags,
                                                   const SkMatrix* localMatrix) {
     if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
@@ -800,7 +849,7 @@
     SkGradientShaderBase::Descriptor desc;
 
     if (!flipGradient) {
-        desc_init(&desc, colors, pos, colorCount, mode, flags);
+        desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
         return SkNEW_ARGS(SkTwoPointConicalGradient,
                           (start, startRadius, end, endRadius, flipGradient, desc, localMatrix));
     } else {
@@ -814,9 +863,9 @@
             for (int i = 0; i < colorCount; ++i) {
                 posNew[i] = 1 - pos[colorCount - i - 1];
             }
-            desc_init(&desc, colorsNew.get(), posNew.get(), colorCount, mode, flags);
+            desc_init(&desc, colorsNew.get(), posNew.get(), colorCount, mode, mapper, flags);
         } else {
-            desc_init(&desc, colorsNew.get(), NULL, colorCount, mode, flags);
+            desc_init(&desc, colorsNew.get(), NULL, colorCount, mode, mapper, flags);
         }
 
         return SkNEW_ARGS(SkTwoPointConicalGradient,
@@ -827,7 +876,7 @@
 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
                                         const SkColor colors[],
                                         const SkScalar pos[],
-                                        int colorCount,
+                                        int colorCount, SkUnitMapper* mapper,
                                         uint32_t flags,
                                         const SkMatrix* localMatrix) {
     if (NULL == colors || colorCount < 1) {
@@ -836,7 +885,7 @@
     EXPAND_1_COLOR(colorCount);
 
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, flags);
+    desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, mapper, flags);
     return SkNEW_ARGS(SkSweepGradient, (cx, cy, desc, localMatrix));
 }
 
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 9613537..a699c4c 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -14,6 +14,7 @@
 #include "SkReadBuffer.h"
 #include "SkWriteBuffer.h"
 #include "SkMallocPixelRef.h"
+#include "SkUnitMapper.h"
 #include "SkUtils.h"
 #include "SkTemplates.h"
 #include "SkBitmapCache.h"
@@ -93,6 +94,7 @@
         const SkScalar*     fPos;
         int                 fCount;
         SkShader::TileMode  fTileMode;
+        SkUnitMapper*       fMapper;
         uint32_t            fGradFlags;
     };
 
@@ -199,6 +201,7 @@
     virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
     SK_TO_STRING_OVERRIDE()
 
+    SkUnitMapper* fMapper;
     SkMatrix    fPtsToUnit;     // set by subclass
     TileMode    fTileMode;
     TileProc    fTileProc;
diff --git a/src/utils/SkUnitMappers.cpp b/src/utils/SkUnitMappers.cpp
new file mode 100644
index 0000000..336a26e
--- /dev/null
+++ b/src/utils/SkUnitMappers.cpp
@@ -0,0 +1,61 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkUnitMappers.h"
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+
+
+SkDiscreteMapper::SkDiscreteMapper(int segments) {
+    if (segments < 2) {
+        fSegments = 0;
+        fScale = 0;
+    } else {
+        if (segments > 0xFFFF) {
+            segments = 0xFFFF;
+        }
+        fSegments = segments;
+        fScale = (1 << 30) / (segments - 1);
+    }
+}
+
+uint16_t SkDiscreteMapper::mapUnit16(uint16_t input) {
+    SkFixed x = input * fSegments >> 16;
+    x = x * fScale >> 14;
+    x += x << 15 >> 31; // map 0x10000 to 0xFFFF
+    return SkToU16(x);
+}
+
+SkDiscreteMapper::SkDiscreteMapper(SkReadBuffer& rb)
+        : SkUnitMapper(rb) {
+    fSegments = rb.readInt();
+    fScale = rb.read32();
+}
+
+void SkDiscreteMapper::flatten(SkWriteBuffer& wb) const {
+    this->INHERITED::flatten(wb);
+
+    wb.writeInt(fSegments);
+    wb.write32(fScale);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+uint16_t SkCosineMapper::mapUnit16(uint16_t input)
+{
+    /*  we want to call cosine(input * pi/2) treating input as [0...1)
+        however, the straight multitply would overflow 32bits since input is
+        16bits and pi/2 is 17bits, so we shift down our pi const before we mul
+    */
+    SkFixed rads = (unsigned)(input * (SK_FixedPI >> 2)) >> 15;
+    SkFixed x = SkFixedCos(rads);
+    x += x << 15 >> 31; // map 0x10000 to 0xFFFF
+    return SkToU16(x);
+}
+
+SkCosineMapper::SkCosineMapper(SkReadBuffer& rb)
+    : SkUnitMapper(rb) {}
diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp
index 9ffb790..a5a763a 100644
--- a/tests/DeferredCanvasTest.cpp
+++ b/tests/DeferredCanvasTest.cpp
@@ -359,7 +359,7 @@
         const SkColor colors[2] = {SK_ColorWHITE, SK_ColorWHITE};
         const SkScalar pos[2] = {0, SK_Scalar1};
         SkShader* shader = SkGradientShader::CreateTwoPointConical(
-            pt1, r1, pt2, r2, colors, pos, 2, SkShader::kClamp_TileMode);
+            pt1, r1, pt2, r2, colors, pos, 2, SkShader::kClamp_TileMode, NULL);
         paint.setShader(shader)->unref();
         canvas->drawRect(fullRect, paint);
         REPORTER_ASSERT(reporter, !canvas->isFreshFrame());