more c

BUG=skia:
TBR=

Review URL: https://codereview.chromium.org/736133006
diff --git a/gm/cgm.c b/gm/cgm.c
new file mode 100644
index 0000000..cddb2c1
--- /dev/null
+++ b/gm/cgm.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#include "sk_canvas.h"
+#include "sk_paint.h"
+#include "sk_shader.h"
+#include "sk_surface.h"
+
+extern void sk_test_c_api(sk_canvas_t*);
+
+#define W   256
+#define H   256
+
+static sk_shader_t* make_shader() {
+    sk_point_t pts[] = { { 0, 0 }, { W, H } };
+    sk_color_t colors[] = { 0xFF00FF00, 0xFF0000FF };
+    return sk_shader_new_linear_gradient(pts, colors, NULL, 2, CLAMP_SK_SHADER_TILEMODE, NULL);
+}
+
+void sk_test_c_api(sk_canvas_t* canvas) {
+    sk_paint_t* paint = sk_paint_new();
+    sk_paint_set_antialias(paint, true);
+
+    sk_paint_set_color(paint, 0xFFFFFFFF);
+    sk_canvas_draw_paint(canvas, paint);
+
+    sk_rect_t r = { 10, 10, W - 10, H - 10 };
+
+    sk_paint_set_color(paint, 0xFFFF0000);
+    sk_canvas_draw_rect(canvas, &r, paint);
+
+    sk_shader_t* shader = make_shader();
+    sk_paint_set_shader(paint, shader);
+    sk_shader_unref(shader);
+
+    sk_canvas_draw_oval(canvas, &r, paint);
+
+    sk_paint_delete(paint);
+}
+
+
diff --git a/gm/cgms.cpp b/gm/cgms.cpp
new file mode 100644
index 0000000..4f2c1b1
--- /dev/null
+++ b/gm/cgms.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "sk_types.h"
+
+extern "C" void sk_test_c_api(sk_canvas_t*);
+
+class C_GM : public skiagm::GM {
+public:
+    C_GM() {}
+
+protected:
+    SkString onShortName() SK_OVERRIDE {
+        return SkString("c_gms");
+    }
+
+    SkISize onISize() SK_OVERRIDE {
+        return SkISize::Make(640, 480);
+    }
+
+    void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+        sk_test_c_api((sk_canvas_t*)canvas);
+    }
+
+private:
+    typedef GM INHERITED;
+};
+
+DEF_GM( return new C_GM; )
+
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index 66427e8..f1ab2b7 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -43,6 +43,8 @@
         '../gm/circularclips.cpp',
         '../gm/clip_strokerect.cpp',
         '../gm/clippedbitmapshaders.cpp',
+        '../gm/cgms.cpp',
+        '../gm/cgm.c',
         '../gm/colorcube.cpp',
         '../gm/coloremoji.cpp',
         '../gm/colorfilterimagefilter.cpp',
diff --git a/include/c/sk_matrix.h b/include/c/sk_matrix.h
new file mode 100644
index 0000000..12d9465
--- /dev/null
+++ b/include/c/sk_matrix.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_matrix_DEFINED
+#define sk_matrix_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+void sk_matrix_set_identity(sk_matrix_t*);
+
+void sk_matrix_set_translate(sk_matrix_t*, float tx, float ty);
+void sk_matrix_pre_translate(sk_matrix_t*, float tx, float ty);
+void sk_matrix_post_translate(sk_matrix_t*, float tx, float ty);
+
+void sk_matrix_set_scale(sk_matrix_t*, float sx, float sy);
+void sk_matrix_pre_scale(sk_matrix_t*, float sx, float sy);
+void sk_matrix_post_scale(sk_matrix_t*, float sx, float sy);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
diff --git a/include/c/sk_paint.h b/include/c/sk_paint.h
index 840433b..92ac5d5 100644
--- a/include/c/sk_paint.h
+++ b/include/c/sk_paint.h
@@ -17,11 +17,19 @@
 
 sk_paint_t* sk_paint_new();
 void sk_paint_delete(sk_paint_t*);
+
 bool sk_paint_is_antialias(const sk_paint_t*);
 void sk_paint_set_antialias(sk_paint_t*, bool);
+
 sk_color_t sk_paint_get_color(const sk_paint_t*);
 void sk_paint_set_color(sk_paint_t*, sk_color_t);
 
+/**
+ *  Set the paint's shader to the specified parameter. This will automatically call unref() on
+ *  any previous value, and call ref() on the new value.
+ */
+void sk_paint_set_shader(sk_paint_t*, sk_shader_t*);
+
 SK_C_PLUS_PLUS_END_GUARD
 
 #endif
diff --git a/include/c/sk_shader.h b/include/c/sk_shader.h
new file mode 100644
index 0000000..9f83ff0
--- /dev/null
+++ b/include/c/sk_shader.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_shader_DEFINED
+#define sk_shader_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+void sk_shader_ref(sk_shader_t*);
+void sk_shader_unref(sk_shader_t*);
+
+typedef enum {
+    CLAMP_SK_SHADER_TILEMODE,
+    REPEAT_SK_SHADER_TILEMODE,
+    MIRROR_SK_SHADER_TILEMODE,
+} sk_shader_tilemode_t;
+
+sk_shader_t* sk_shader_new_linear_gradient(const sk_point_t pts[2],
+                                           const sk_color_t colors[],
+                                           const float colorPos[],
+                                           int colorCount,
+                                           sk_shader_tilemode_t tileMode,
+                                           const sk_matrix_t* localMatrix);
+
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
diff --git a/include/c/sk_surface.h b/include/c/sk_surface.h
index 96aa32f..ce7a568 100644
--- a/include/c/sk_surface.h
+++ b/include/c/sk_surface.h
@@ -17,7 +17,7 @@
 
 sk_surface_t* sk_surface_new_raster(const sk_imageinfo_t*);
 sk_surface_t* sk_surface_new_raster_direct(const sk_imageinfo_t*, void* pixels, size_t rowBytes);
-void sk_surface_delete(sk_surface_t*);
+void sk_surface_unref(sk_surface_t*);
 
 /**
  *  Return the canvas associated with this surface. Note: the canvas is owned by the surface,
diff --git a/include/c/sk_types.h b/include/c/sk_types.h
index 71ce219..4c63896 100644
--- a/include/c/sk_types.h
+++ b/include/c/sk_types.h
@@ -58,16 +58,26 @@
 } sk_imageinfo_t;
 
 typedef struct {
+    float   x;
+    float   y;
+} sk_point_t;
+
+typedef struct {
     float   left;
     float   top;
     float   right;
     float   bottom;
 } sk_rect_t;
 
+typedef struct {
+    float   mat[9];
+} sk_matrix_t;
+
 typedef struct sk_canvas_t sk_canvas_t;
 typedef struct sk_image_t sk_image_t;
 typedef struct sk_paint_t sk_paint_t;
 typedef struct sk_path_t sk_path_t;
+typedef struct sk_shader_t sk_shader_t;
 typedef struct sk_surface_t sk_surface_t;
 
 //////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/c/sk_surface.cpp b/src/c/sk_surface.cpp
index 45a1ef9..1cd4f3d 100644
--- a/src/c/sk_surface.cpp
+++ b/src/c/sk_surface.cpp
@@ -147,6 +147,10 @@
     return reinterpret_cast<SkCanvas*>(ccanvas);
 }
 
+static SkShader* AsShader(sk_shader_t* cshader) {
+    return reinterpret_cast<SkShader*>(cshader);
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////
 
 sk_colortype_t sk_colortype_get_default_8888() {
@@ -214,6 +218,10 @@
     AsPaint(cpaint)->setColor(c);
 }
 
+void sk_paint_set_shader(sk_paint_t* cpaint, sk_shader_t* cshader) {
+    AsPaint(cpaint)->setShader(AsShader(cshader));
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////
 
 sk_path_t* sk_path_new() {
@@ -340,9 +348,8 @@
     return (sk_surface_t*)SkSurface::NewRasterDirect(info, pixels, rowBytes);
 }
 
-void sk_surface_delete(sk_surface_t* csurf) {
-    SkSurface* surf = (SkSurface*)csurf;
-    SkSafeUnref(surf);
+void sk_surface_unref(sk_surface_t* csurf) {
+    SkSafeUnref((SkSurface*)csurf);
 }
 
 sk_canvas_t* sk_surface_get_canvas(sk_surface_t* csurf) {
@@ -355,8 +362,66 @@
     return (sk_image_t*)surf->newImageSnapshot();
 }
 
+///////////////////////////////////////////////////////////////////////////////////////////
 
-///////////////////
+#include "../../include/effects/SkGradientShader.h"
+#include "sk_shader.h"
+
+const struct {
+    sk_shader_tilemode_t    fC;
+    SkShader::TileMode      fSK;
+} gTileModeMap[] = {
+    { CLAMP_SK_SHADER_TILEMODE,     SkShader::kClamp_TileMode },
+    { REPEAT_SK_SHADER_TILEMODE,    SkShader::kRepeat_TileMode },
+    { MIRROR_SK_SHADER_TILEMODE,    SkShader::kMirror_TileMode  },
+};
+
+static bool from_c_tilemode(sk_shader_tilemode_t cMode, SkShader::TileMode* skMode) {
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gTileModeMap); ++i) {
+        if (cMode == gTileModeMap[i].fC) {
+            if (skMode) {
+                *skMode = gTileModeMap[i].fSK;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+void sk_shader_ref(sk_shader_t* cshader) {
+    SkSafeRef(AsShader(cshader));
+}
+
+void sk_shader_unref(sk_shader_t* cshader) {
+    SkSafeUnref(AsShader(cshader));
+}
+
+sk_shader_t* sk_shader_new_linear_gradient(const sk_point_t pts[2],
+                                           const sk_color_t colors[],
+                                           const float colorPos[],
+                                           int colorCount,
+                                           sk_shader_tilemode_t cmode,
+                                           const sk_matrix_t* cmatrix) {
+    SkShader::TileMode mode;
+    if (!from_c_tilemode(cmode, &mode)) {
+        return NULL;
+    }
+    SkMatrix matrix;
+    if (cmatrix) {
+        matrix.setAll(cmatrix->mat[0], cmatrix->mat[1], cmatrix->mat[2],
+                      cmatrix->mat[3], cmatrix->mat[4], cmatrix->mat[5],
+                      cmatrix->mat[6], cmatrix->mat[7], cmatrix->mat[8]);
+    } else {
+        matrix.setIdentity();
+    }
+    SkShader* s = SkGradientShader::CreateLinear(reinterpret_cast<const SkPoint*>(pts),
+                                                 reinterpret_cast<const SkColor*>(colors),
+                                                 colorPos, colorCount, mode, 0, &matrix);
+    return (sk_shader_t*)s;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////
 
 void sk_test_capi(SkCanvas* canvas) {
     sk_imageinfo_t cinfo;
@@ -398,5 +463,5 @@
     sk_path_delete(cpath);
     sk_paint_delete(cpaint);
     sk_image_unref(cimage);
-    sk_surface_delete(csurface);
+    sk_surface_unref(csurface);
 }
diff --git a/tests/CTest.cpp b/tests/CTest.cpp
index 8127e9b..81702ac 100644
--- a/tests/CTest.cpp
+++ b/tests/CTest.cpp
@@ -31,7 +31,7 @@
     REPORTER_ASSERT(reporter, 0xFFFFFFFF == pixel[0]);
 
     sk_paint_delete(paint);
-    sk_surface_delete(surface);
+    sk_surface_unref(surface);
 }
 
 DEF_TEST(C_API, reporter) {