Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / utils / SkLua.cpp
index 8bc646f..b12e3e9 100644 (file)
@@ -6,16 +6,27 @@
  */
 
 #include "SkLua.h"
+
+#if SK_SUPPORT_GPU
+#include "GrReducedClip.h"
+#endif
+
+#include "SkBlurImageFilter.h"
 #include "SkCanvas.h"
 #include "SkData.h"
+#include "SkDecodingImageGenerator.h"
 #include "SkDocument.h"
+#include "SkGradientShader.h"
 #include "SkImage.h"
 #include "SkMatrix.h"
 #include "SkPaint.h"
 #include "SkPath.h"
+#include "SkPictureRecorder.h"
 #include "SkPixelRef.h"
 #include "SkRRect.h"
 #include "SkString.h"
+#include "SkSurface.h"
+#include "SkTextBlob.h"
 #include "SkTypeface.h"
 
 extern "C" {
@@ -34,11 +45,17 @@ template <typename T> const char* get_mtname();
 DEF_MTNAME(SkCanvas)
 DEF_MTNAME(SkDocument)
 DEF_MTNAME(SkImage)
+DEF_MTNAME(SkImageFilter)
 DEF_MTNAME(SkMatrix)
 DEF_MTNAME(SkRRect)
 DEF_MTNAME(SkPath)
 DEF_MTNAME(SkPaint)
+DEF_MTNAME(SkPathEffect)
+DEF_MTNAME(SkPicture)
+DEF_MTNAME(SkPictureRecorder)
 DEF_MTNAME(SkShader)
+DEF_MTNAME(SkSurface)
+DEF_MTNAME(SkTextBlob)
 DEF_MTNAME(SkTypeface)
 
 template <typename T> T* push_new(lua_State* L) {
@@ -55,10 +72,11 @@ template <typename T> void push_obj(lua_State* L, const T& obj) {
     lua_setmetatable(L, -2);
 }
 
-template <typename T> void push_ref(lua_State* L, T* ref) {
+template <typename T> T* push_ref(lua_State* L, T* ref) {
     *(T**)lua_newuserdata(L, sizeof(T*)) = SkSafeRef(ref);
     luaL_getmetatable(L, get_mtname<T>());
     lua_setmetatable(L, -2);
+    return ref;
 }
 
 template <typename T> T* get_ref(lua_State* L, int index) {
@@ -150,6 +168,10 @@ static void setarray_number(lua_State* L, int index, double value) {
     lua_rawseti(L, -2, index);
 }
 
+static void setarray_scalar(lua_State* L, int index, SkScalar value) {
+    setarray_number(L, index, SkScalarToLua(value));
+}
+
 void SkLua::pushBool(bool value, const char key[]) {
     lua_pushboolean(fL, value);
     CHECK_SETFIELD(key);
@@ -200,6 +222,27 @@ void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
     CHECK_SETFIELD(key);
 }
 
+void SkLua::pushArrayPoint(const SkPoint array[], int count, const char key[]) {
+    lua_newtable(fL);
+    for (int i = 0; i < count; ++i) {
+        // make it base-1 to match lua convention
+        lua_newtable(fL);
+        this->pushScalar(array[i].fX, "x");
+        this->pushScalar(array[i].fY, "y");
+        lua_rawseti(fL, -2, i + 1);
+    }
+    CHECK_SETFIELD(key);
+}
+
+void SkLua::pushArrayScalar(const SkScalar array[], int count, const char key[]) {
+    lua_newtable(fL);
+    for (int i = 0; i < count; ++i) {
+        // make it base-1 to match lua convention
+        setarray_scalar(fL, i + 1, array[i]);
+    }
+    CHECK_SETFIELD(key);
+}
+
 void SkLua::pushRect(const SkRect& r, const char key[]) {
     lua_newtable(fL);
     setfield_scalar(fL, "left", r.fLeft);
@@ -214,6 +257,14 @@ void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
     CHECK_SETFIELD(key);
 }
 
+void SkLua::pushDash(const SkPathEffect::DashInfo& info, const char key[]) {
+    lua_newtable(fL);
+    setfield_scalar(fL, "phase", info.fPhase);
+    this->pushArrayScalar(info.fIntervals, info.fCount, "intervals");
+    CHECK_SETFIELD(key);
+}
+
+
 void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
     push_obj(fL, matrix);
     CHECK_SETFIELD(key);
@@ -234,9 +285,89 @@ void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
     CHECK_SETFIELD(key);
 }
 
+void SkLua::pushTextBlob(const SkTextBlob* blob, const char key[]) {
+    push_ref(fL, const_cast<SkTextBlob*>(blob));
+    CHECK_SETFIELD(key);
+}
+
+static const char* element_type(SkClipStack::Element::Type type) {
+    switch (type) {
+        case SkClipStack::Element::kEmpty_Type:
+            return "empty";
+        case SkClipStack::Element::kRect_Type:
+            return "rect";
+        case SkClipStack::Element::kRRect_Type:
+            return "rrect";
+        case SkClipStack::Element::kPath_Type:
+            return "path";
+    }
+    return "unknown";
+}
+
+static const char* region_op(SkRegion::Op op) {
+    switch (op) {
+        case SkRegion::kDifference_Op:
+            return "difference";
+        case SkRegion::kIntersect_Op:
+            return "intersect";
+        case SkRegion::kUnion_Op:
+            return "union";
+        case SkRegion::kXOR_Op:
+            return "xor";
+        case SkRegion::kReverseDifference_Op:
+            return "reverse-difference";
+        case SkRegion::kReplace_Op:
+            return "replace";
+    }
+    return "unknown";
+}
+
+void SkLua::pushClipStack(const SkClipStack& stack, const char* key) {
+    lua_newtable(fL);
+    SkClipStack::B2TIter iter(stack);
+    const SkClipStack::Element* element;
+    int i = 0;
+    while ((element = iter.next())) {
+        this->pushClipStackElement(*element);
+        lua_rawseti(fL, -2, ++i);
+    }
+    CHECK_SETFIELD(key);
+}
+
+void SkLua::pushClipStackElement(const SkClipStack::Element& element, const char* key) {
+    lua_newtable(fL);
+    SkClipStack::Element::Type type = element.getType();
+    this->pushString(element_type(type), "type");
+    switch (type) {
+        case SkClipStack::Element::kEmpty_Type:
+            break;
+        case SkClipStack::Element::kRect_Type:
+            this->pushRect(element.getRect(), "rect");
+            break;
+        case SkClipStack::Element::kRRect_Type:
+            this->pushRRect(element.getRRect(), "rrect");
+            break;
+        case SkClipStack::Element::kPath_Type:
+            this->pushPath(element.getPath(), "path");
+            break;
+    }
+    this->pushString(region_op(element.getOp()), "op");
+    this->pushBool(element.isAA(), "aa");
+    CHECK_SETFIELD(key);
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
+static int lua2int_def(lua_State* L, int index, int defaultValue) {
+    if (lua_isnumber(L, index)) {
+        return (int)lua_tonumber(L, index);
+    } else {
+        return defaultValue;
+    }
+}
+
 static SkScalar lua2scalar(lua_State* L, int index) {
     SkASSERT(lua_isnumber(L, index));
     return SkLuaToScalar(lua_tonumber(L, index));
@@ -275,6 +406,10 @@ static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[
     return value;
 }
 
+static SkScalar byte2unit(U8CPU byte) {
+    return byte / 255.0f;
+}
+
 static U8CPU unit2byte(SkScalar x) {
     if (x <= 0) {
         return 0;
@@ -286,10 +421,10 @@ static U8CPU unit2byte(SkScalar x) {
 }
 
 static SkColor lua2color(lua_State* L, int index) {
-    return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
-                          unit2byte(getfield_scalar(L, index, "r")),
-                          unit2byte(getfield_scalar(L, index, "g")),
-                          unit2byte(getfield_scalar(L, index, "b")));
+    return SkColorSetARGB(unit2byte(getfield_scalar_default(L, index, "a", 1)),
+                          unit2byte(getfield_scalar_default(L, index, "r", 0)),
+                          unit2byte(getfield_scalar_default(L, index, "g", 0)),
+                          unit2byte(getfield_scalar_default(L, index, "b", 0)));
 }
 
 static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
@@ -300,11 +435,21 @@ static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
     return rect;
 }
 
+static int lcanvas_clear(lua_State* L) {
+    get_ref<SkCanvas>(L, 1)->clear(0);
+    return 0;
+}
+
 static int lcanvas_drawColor(lua_State* L) {
     get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
     return 0;
 }
 
+static int lcanvas_drawPaint(lua_State* L) {
+    get_ref<SkCanvas>(L, 1)->drawPaint(*get_obj<SkPaint>(L, 2));
+    return 0;
+}
+
 static int lcanvas_drawRect(lua_State* L) {
     SkRect rect;
     get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
@@ -327,6 +472,20 @@ static int lcanvas_drawCircle(lua_State* L) {
     return 0;
 }
 
+static SkPaint* lua2OptionalPaint(lua_State* L, int index, SkPaint* paint) {
+    if (lua_isnumber(L, index)) {
+        paint->setAlpha(SkScalarRoundToInt(lua2scalar(L, index) * 255));
+        return paint;
+    } else if (lua_isuserdata(L, index)) {
+        const SkPaint* ptr = get_obj<SkPaint>(L, index);
+        if (ptr) {
+            *paint = *ptr;
+            return paint;
+        }
+    }
+    return NULL;
+}
+
 static int lcanvas_drawImage(lua_State* L) {
     SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
     SkImage* image = get_ref<SkImage>(L, 2);
@@ -337,12 +496,26 @@ static int lcanvas_drawImage(lua_State* L) {
     SkScalar y = lua2scalar(L, 4);
 
     SkPaint paint;
-    const SkPaint* paintPtr = NULL;
-    if (lua_isnumber(L, 5)) {
-        paint.setAlpha(SkScalarRoundToInt(lua2scalar(L, 5) * 255));
-        paintPtr = &paint;
+    canvas->drawImage(image, x, y, lua2OptionalPaint(L, 5, &paint));
+    return 0;
+}
+
+static int lcanvas_drawImageRect(lua_State* L) {
+    SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
+    SkImage* image = get_ref<SkImage>(L, 2);
+    if (NULL == image) {
+        return 0;
     }
-    image->draw(canvas, x, y, paintPtr);
+
+    SkRect srcR, dstR;
+    SkRect* srcRPtr = NULL;
+    if (!lua_isnil(L, 3)) {
+        srcRPtr = lua2rect(L, 3, &srcR);
+    }
+    lua2rect(L, 4, &dstR);
+    
+    SkPaint paint;
+    canvas->drawImageRect(image, srcRPtr, dstR, lua2OptionalPaint(L, 5, &paint));
     return 0;
 }
 
@@ -352,6 +525,22 @@ static int lcanvas_drawPath(lua_State* L) {
     return 0;
 }
 
+// drawPicture(pic, x, y, paint)
+static int lcanvas_drawPicture(lua_State* L) {
+    SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
+    SkPicture* picture = get_ref<SkPicture>(L, 2);
+    SkScalar x = lua2scalar_def(L, 3, 0);
+    SkScalar y = lua2scalar_def(L, 4, 0);
+    SkMatrix matrix, *matrixPtr = NULL;
+    if (x || y) {
+        matrix.setTranslate(x, y);
+        matrixPtr = &matrix;
+    }
+    SkPaint paint;
+    canvas->drawPicture(picture, matrixPtr, lua2OptionalPaint(L, 5, &paint));
+    return 0;
+}
+
 static int lcanvas_drawText(lua_State* L) {
     if (lua_gettop(L) < 5) {
         return 0;
@@ -367,6 +556,15 @@ static int lcanvas_drawText(lua_State* L) {
     return 0;
 }
 
+static int lcanvas_drawTextBlob(lua_State* L) {
+    const SkTextBlob* blob = get_ref<SkTextBlob>(L, 2);
+    SkScalar x = lua2scalar(L, 3);
+    SkScalar y = lua2scalar(L, 4);
+    const SkPaint& paint = *get_obj<SkPaint>(L, 5);
+    get_ref<SkCanvas>(L, 1)->drawTextBlob(blob, x, y, paint);
+    return 0;
+}
+
 static int lcanvas_getSaveCount(lua_State* L) {
     lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
     return 1;
@@ -377,11 +575,61 @@ static int lcanvas_getTotalMatrix(lua_State* L) {
     return 1;
 }
 
+static int lcanvas_getClipStack(lua_State* L) {
+    SkLua(L).pushClipStack(*get_ref<SkCanvas>(L, 1)->getClipStack());
+    return 1;
+}
+
+int SkLua::lcanvas_getReducedClipStack(lua_State* L) {
+#if SK_SUPPORT_GPU
+    const SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
+    SkISize layerSize = canvas->getTopLayerSize();
+    SkIPoint layerOrigin = canvas->getTopLayerOrigin();
+    SkIRect queryBounds = SkIRect::MakeXYWH(layerOrigin.fX, layerOrigin.fY,
+                                            layerSize.fWidth, layerSize.fHeight);
+
+    GrReducedClip::ElementList elements;
+    GrReducedClip::InitialState initialState;
+    int32_t genID;
+    SkIRect resultBounds;
+
+    const SkClipStack& stack = *canvas->getClipStack();
+
+    GrReducedClip::ReduceClipStack(stack,
+                                   queryBounds,
+                                   &elements,
+                                   &genID,
+                                   &initialState,
+                                   &resultBounds,
+                                   NULL);
+
+    GrReducedClip::ElementList::Iter iter(elements);
+    int i = 0;
+    lua_newtable(L);
+    while(iter.get()) {
+        SkLua(L).pushClipStackElement(*iter.get());
+        iter.next();
+        lua_rawseti(L, -2, ++i);
+    }
+    // Currently this only returns the element list to lua, not the initial state or result bounds.
+    // It could return these as additional items on the lua stack.
+    return 1;
+#else
+    return 0;
+#endif
+}
+
 static int lcanvas_save(lua_State* L) {
     lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
     return 1;
 }
 
+static int lcanvas_saveLayer(lua_State* L) {
+    SkPaint paint;
+    lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->saveLayer(NULL, lua2OptionalPaint(L, 2, &paint)));
+    return 1;
+}
+
 static int lcanvas_restore(lua_State* L) {
     get_ref<SkCanvas>(L, 1)->restore();
     return 0;
@@ -407,26 +655,58 @@ static int lcanvas_rotate(lua_State* L) {
     return 0;
 }
 
+static int lcanvas_concat(lua_State* L) {
+    get_ref<SkCanvas>(L, 1)->concat(*get_obj<SkMatrix>(L, 2));
+    return 0;
+}
+
+static int lcanvas_newSurface(lua_State* L) {
+    int width = lua2int_def(L, 2, 0);
+    int height = lua2int_def(L, 2, 0);
+    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
+    SkSurface* surface = get_ref<SkCanvas>(L, 1)->newSurface(info);
+    if (NULL == surface) {
+        lua_pushnil(L);
+    } else {
+        push_ref(L, surface)->unref();
+    }
+    return 1;
+}
+
 static int lcanvas_gc(lua_State* L) {
     get_ref<SkCanvas>(L, 1)->unref();
     return 0;
 }
 
-static const struct luaL_Reg gSkCanvas_Methods[] = {
+const struct luaL_Reg gSkCanvas_Methods[] = {
+    { "clear", lcanvas_clear },
     { "drawColor", lcanvas_drawColor },
+    { "drawPaint", lcanvas_drawPaint },
     { "drawRect", lcanvas_drawRect },
     { "drawOval", lcanvas_drawOval },
     { "drawCircle", lcanvas_drawCircle },
     { "drawImage", lcanvas_drawImage },
+    { "drawImageRect", lcanvas_drawImageRect },
     { "drawPath", lcanvas_drawPath },
+    { "drawPicture", lcanvas_drawPicture },
     { "drawText", lcanvas_drawText },
+    { "drawTextBlob", lcanvas_drawTextBlob },
     { "getSaveCount", lcanvas_getSaveCount },
     { "getTotalMatrix", lcanvas_getTotalMatrix },
+    { "getClipStack", lcanvas_getClipStack },
+#if SK_SUPPORT_GPU
+    { "getReducedClipStack", SkLua::lcanvas_getReducedClipStack },
+#endif
     { "save", lcanvas_save },
+    { "saveLayer", lcanvas_saveLayer },
     { "restore", lcanvas_restore },
     { "scale", lcanvas_scale },
     { "translate", lcanvas_translate },
     { "rotate", lcanvas_rotate },
+    { "concat", lcanvas_concat },
+
+    { "newSurface", lcanvas_newSurface },
+
     { "__gc", lcanvas_gc },
     { NULL, NULL }
 };
@@ -481,6 +761,11 @@ static int lpaint_isDither(lua_State* L) {
     return 1;
 }
 
+static int lpaint_setDither(lua_State* L) {
+    get_obj<SkPaint>(L, 1)->setDither(lua2bool(L, 2));
+    return 0;
+}
+
 static int lpaint_isUnderlineText(lua_State* L) {
     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isUnderlineText());
     return 1;
@@ -506,6 +791,11 @@ static int lpaint_isSubpixelText(lua_State* L) {
     return 1;
 }
 
+static int lpaint_setSubpixelText(lua_State* L) {
+    get_obj<SkPaint>(L, 1)->setSubpixelText(lua2bool(L, 2));
+    return 1;
+}
+
 static int lpaint_isDevKernText(lua_State* L) {
     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDevKernText());
     return 1;
@@ -516,6 +806,11 @@ static int lpaint_isLCDRenderText(lua_State* L) {
     return 1;
 }
 
+static int lpaint_setLCDRenderText(lua_State* L) {
+    get_obj<SkPaint>(L, 1)->setLCDRenderText(lua2bool(L, 2));
+    return 1;
+}
+
 static int lpaint_isEmbeddedBitmapText(lua_State* L) {
     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isEmbeddedBitmapText());
     return 1;
@@ -531,6 +826,16 @@ static int lpaint_isVerticalText(lua_State* L) {
     return 1;
 }
 
+static int lpaint_getAlpha(lua_State* L) {
+    SkLua(L).pushScalar(byte2unit(get_obj<SkPaint>(L, 1)->getAlpha()));
+    return 1;
+}
+
+static int lpaint_setAlpha(lua_State* L) {
+    get_obj<SkPaint>(L, 1)->setAlpha(unit2byte(lua2scalar(L, 2)));
+    return 0;
+}
+
 static int lpaint_getColor(lua_State* L) {
     SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
     return 1;
@@ -704,17 +1009,33 @@ static int lpaint_getEffects(lua_State* L) {
     const SkPaint* paint = get_obj<SkPaint>(L, 1);
 
     lua_newtable(L);
-    setfield_bool_if(L, "looper", !!paint->getLooper());
-    setfield_bool_if(L, "pathEffect", !!paint->getPathEffect());
-    setfield_bool_if(L, "rasterizer", !!paint->getRasterizer());
-    setfield_bool_if(L, "maskFilter", !!paint->getMaskFilter());
-    setfield_bool_if(L, "shader", !!paint->getShader());
+    setfield_bool_if(L, "looper",      !!paint->getLooper());
+    setfield_bool_if(L, "pathEffect",  !!paint->getPathEffect());
+    setfield_bool_if(L, "rasterizer",  !!paint->getRasterizer());
+    setfield_bool_if(L, "maskFilter",  !!paint->getMaskFilter());
+    setfield_bool_if(L, "shader",      !!paint->getShader());
     setfield_bool_if(L, "colorFilter", !!paint->getColorFilter());
     setfield_bool_if(L, "imageFilter", !!paint->getImageFilter());
-    setfield_bool_if(L, "xfermode", !!paint->getXfermode());
+    setfield_bool_if(L, "xfermode",    !!paint->getXfermode());
     return 1;
 }
 
+static int lpaint_getImageFilter(lua_State* L) {
+    const SkPaint* paint = get_obj<SkPaint>(L, 1);
+    SkImageFilter* imf = paint->getImageFilter();
+    if (imf) {
+        push_ref(L, imf);
+        return 1;
+    }
+    return 0;
+}
+
+static int lpaint_setImageFilter(lua_State* L) {
+    SkPaint* paint = get_obj<SkPaint>(L, 1);
+    paint->setImageFilter(get_ref<SkImageFilter>(L, 2));
+    return 0;
+}
+
 static int lpaint_getShader(lua_State* L) {
     const SkPaint* paint = get_obj<SkPaint>(L, 1);
     SkShader* shader = paint->getShader();
@@ -725,6 +1046,22 @@ static int lpaint_getShader(lua_State* L) {
     return 0;
 }
 
+static int lpaint_setShader(lua_State* L) {
+    SkPaint* paint = get_obj<SkPaint>(L, 1);
+    paint->setShader(get_ref<SkShader>(L, 2));
+    return 0;
+}
+
+static int lpaint_getPathEffect(lua_State* L) {
+    const SkPaint* paint = get_obj<SkPaint>(L, 1);
+    SkPathEffect* pe = paint->getPathEffect();
+    if (pe) {
+        push_ref(L, pe);
+        return 1;
+    }
+    return 0;
+}
+
 static int lpaint_gc(lua_State* L) {
     get_obj<SkPaint>(L, 1)->~SkPaint();
     return 0;
@@ -734,16 +1071,21 @@ static const struct luaL_Reg gSkPaint_Methods[] = {
     { "isAntiAlias", lpaint_isAntiAlias },
     { "setAntiAlias", lpaint_setAntiAlias },
     { "isDither", lpaint_isDither },
+    { "setDither", lpaint_setDither },
     { "isUnderlineText", lpaint_isUnderlineText },
     { "isStrikeThruText", lpaint_isStrikeThruText },
     { "isFakeBoldText", lpaint_isFakeBoldText },
     { "isLinearText", lpaint_isLinearText },
     { "isSubpixelText", lpaint_isSubpixelText },
+    { "setSubpixelText", lpaint_setSubpixelText },
     { "isDevKernText", lpaint_isDevKernText },
     { "isLCDRenderText", lpaint_isLCDRenderText },
+    { "setLCDRenderText", lpaint_setLCDRenderText },
     { "isEmbeddedBitmapText", lpaint_isEmbeddedBitmapText },
     { "isAutohinted", lpaint_isAutohinted },
     { "isVerticalText", lpaint_isVerticalText },
+    { "getAlpha", lpaint_getAlpha },
+    { "setAlpha", lpaint_setAlpha },
     { "getColor", lpaint_getColor },
     { "setColor", lpaint_setColor },
     { "getTextSize", lpaint_getTextSize },
@@ -767,7 +1109,11 @@ static const struct luaL_Reg gSkPaint_Methods[] = {
     { "measureText", lpaint_measureText },
     { "getFontMetrics", lpaint_getFontMetrics },
     { "getEffects", lpaint_getEffects },
+    { "getImageFilter", lpaint_getImageFilter },
+    { "setImageFilter", lpaint_setImageFilter },
     { "getShader", lpaint_getShader },
+    { "setShader", lpaint_setShader },
+    { "getPathEffect", lpaint_getPathEffect },
     { "__gc", lpaint_gc },
     { NULL, NULL }
 };
@@ -861,6 +1207,47 @@ static const struct luaL_Reg gSkShader_Methods[] = {
 
 ///////////////////////////////////////////////////////////////////////////////
 
+static int lpatheffect_asADash(lua_State* L) {
+    SkPathEffect* pe = get_ref<SkPathEffect>(L, 1);
+    if (pe) {
+        SkPathEffect::DashInfo info;
+        SkPathEffect::DashType dashType = pe->asADash(&info);
+        if (SkPathEffect::kDash_DashType == dashType) {
+            SkAutoTArray<SkScalar> intervals(info.fCount);
+            info.fIntervals = intervals.get();
+            pe->asADash(&info);
+            SkLua(L).pushDash(info);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int lpatheffect_gc(lua_State* L) {
+    get_ref<SkPathEffect>(L, 1)->unref();
+    return 0;
+}
+
+static const struct luaL_Reg gSkPathEffect_Methods[] = {
+    { "asADash",        lpatheffect_asADash },
+    { "__gc",           lpatheffect_gc },
+    { NULL, NULL }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int lpimagefilter_gc(lua_State* L) {
+    get_ref<SkImageFilter>(L, 1)->unref();
+    return 0;
+}
+
+static const struct luaL_Reg gSkImageFilter_Methods[] = {
+    { "__gc",       lpimagefilter_gc },
+    { NULL, NULL }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
 static int lmatrix_getType(lua_State* L) {
     SkMatrix::TypeMask mask = get_obj<SkMatrix>(L, 1)->getType();
 
@@ -892,12 +1279,44 @@ static int lmatrix_getTranslateY(lua_State* L) {
     return 1;
 }
 
+static int lmatrix_setRectToRect(lua_State* L) {
+    SkMatrix* matrix = get_obj<SkMatrix>(L, 1);
+    SkRect srcR, dstR;
+    lua2rect(L, 2, &srcR);
+    lua2rect(L, 3, &dstR);
+    const char* scaleToFitStr = lua_tostring(L, 4);
+    SkMatrix::ScaleToFit scaleToFit = SkMatrix::kFill_ScaleToFit;
+
+    if (scaleToFitStr) {
+        const struct {
+            const char* fName;
+            SkMatrix::ScaleToFit fScaleToFit;
+        } rec[] = {
+            { "fill",   SkMatrix::kFill_ScaleToFit },
+            { "start",  SkMatrix::kStart_ScaleToFit },
+            { "center", SkMatrix::kCenter_ScaleToFit },
+            { "end",    SkMatrix::kEnd_ScaleToFit },
+        };
+
+        for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) {
+            if (strcmp(rec[i].fName, scaleToFitStr) == 0) {
+                scaleToFit = rec[i].fScaleToFit;
+                break;
+            }
+        }
+    }
+
+    matrix->setRectToRect(srcR, dstR, scaleToFit);
+    return 0;
+}
+
 static const struct luaL_Reg gSkMatrix_Methods[] = {
     { "getType", lmatrix_getType },
     { "getScaleX", lmatrix_getScaleX },
     { "getScaleY", lmatrix_getScaleY },
     { "getTranslateX", lmatrix_getTranslateX },
     { "getTranslateY", lmatrix_getTranslateY },
+    { "setRectToRect", lmatrix_setRectToRect },
     { NULL, NULL }
 };
 
@@ -908,6 +1327,73 @@ static int lpath_getBounds(lua_State* L) {
     return 1;
 }
 
+static const char* fill_type_to_str(SkPath::FillType fill) {
+    switch (fill) {
+        case SkPath::kEvenOdd_FillType:
+            return "even-odd";
+        case SkPath::kWinding_FillType:
+            return "winding";
+        case SkPath::kInverseEvenOdd_FillType:
+            return "inverse-even-odd";
+        case SkPath::kInverseWinding_FillType:
+            return "inverse-winding";
+    }
+    return "unknown";
+}
+
+static int lpath_getFillType(lua_State* L) {
+    SkPath::FillType fill = get_obj<SkPath>(L, 1)->getFillType();
+    SkLua(L).pushString(fill_type_to_str(fill));
+    return 1;
+}
+
+static SkString segment_masks_to_str(uint32_t segmentMasks) {
+    SkString result;
+    bool first = true;
+    if (SkPath::kLine_SegmentMask & segmentMasks) {
+        result.append("line");
+        first = false;
+        SkDEBUGCODE(segmentMasks &= ~SkPath::kLine_SegmentMask;)
+    }
+    if (SkPath::kQuad_SegmentMask & segmentMasks) {
+        if (!first) {
+            result.append(" ");
+        }
+        result.append("quad");
+        first = false;
+        SkDEBUGCODE(segmentMasks &= ~SkPath::kQuad_SegmentMask;)
+    }
+    if (SkPath::kConic_SegmentMask & segmentMasks) {
+        if (!first) {
+            result.append(" ");
+        }
+        result.append("conic");
+        first = false;
+        SkDEBUGCODE(segmentMasks &= ~SkPath::kConic_SegmentMask;)
+    }
+    if (SkPath::kCubic_SegmentMask & segmentMasks) {
+        if (!first) {
+            result.append(" ");
+        }
+        result.append("cubic");
+        SkDEBUGCODE(segmentMasks &= ~SkPath::kCubic_SegmentMask;)
+    }
+    SkASSERT(0 == segmentMasks);
+    return result;
+}
+
+static int lpath_getSegmentTypes(lua_State* L) {
+    uint32_t segMasks = get_obj<SkPath>(L, 1)->getSegmentMasks();
+    SkLua(L).pushString(segment_masks_to_str(segMasks));
+    return 1;
+}
+
+static int lpath_isConvex(lua_State* L) {
+    bool isConvex = SkPath::kConvex_Convexity == get_obj<SkPath>(L, 1)->getConvexity();
+    SkLua(L).pushBool(isConvex);
+    return 1;
+}
+
 static int lpath_isEmpty(lua_State* L) {
     lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
     return 1;
@@ -950,6 +1436,11 @@ static int lpath_isNestedRects(lua_State* L) {
     return ret_count;
 }
 
+static int lpath_countPoints(lua_State* L) {
+    lua_pushinteger(L, get_obj<SkPath>(L, 1)->countPoints());
+    return 1;
+}
+
 static int lpath_reset(lua_State* L) {
     get_obj<SkPath>(L, 1)->reset();
     return 0;
@@ -990,9 +1481,13 @@ static int lpath_gc(lua_State* L) {
 
 static const struct luaL_Reg gSkPath_Methods[] = {
     { "getBounds", lpath_getBounds },
+    { "getFillType", lpath_getFillType },
+    { "getSegmentTypes", lpath_getSegmentTypes },
+    { "isConvex", lpath_isConvex },
     { "isEmpty", lpath_isEmpty },
     { "isRect", lpath_isRect },
     { "isNestedRects", lpath_isNestedRects },
+    { "countPoints", lpath_countPoints },
     { "reset", lpath_reset },
     { "moveTo", lpath_moveTo },
     { "lineTo", lpath_lineTo },
@@ -1012,6 +1507,7 @@ static const char* rrect_type(const SkRRect& rr) {
         case SkRRect::kRect_Type: return "rect";
         case SkRRect::kOval_Type: return "oval";
         case SkRRect::kSimple_Type: return "simple";
+        case SkRRect::kNinePatch_Type: return "nine-patch";
         case SkRRect::kComplex_Type: return "complex";
     }
     SkDEBUGFAIL("never get here");
@@ -1029,7 +1525,7 @@ static int lrrect_type(lua_State* L) {
 }
 
 static int lrrect_radii(lua_State* L) {
-    int corner = lua_tointeger(L, 2);
+    int corner = SkToInt(lua_tointeger(L, 2));
     SkVector v;
     if (corner < 0 || corner > 3) {
         SkDebugf("bad corner index %d", corner);
@@ -1081,12 +1577,186 @@ static const struct luaL_Reg gSkImage_Methods[] = {
 
 ///////////////////////////////////////////////////////////////////////////////
 
+static int lsurface_width(lua_State* L) {
+    lua_pushinteger(L, get_ref<SkSurface>(L, 1)->width());
+    return 1;
+}
+
+static int lsurface_height(lua_State* L) {
+    lua_pushinteger(L, get_ref<SkSurface>(L, 1)->height());
+    return 1;
+}
+
+static int lsurface_getCanvas(lua_State* L) {
+    SkCanvas* canvas = get_ref<SkSurface>(L, 1)->getCanvas();
+    if (NULL == canvas) {
+        lua_pushnil(L);
+    } else {
+        push_ref(L, canvas);
+        // note: we don't unref canvas, since getCanvas did not ref it.
+        // warning: this is weird: now Lua owns a ref on this canvas, but what if they let
+        // the real owner (the surface) go away, but still hold onto the canvas?
+        // *really* we want to sort of ref the surface again, but have the native object
+        // know that it is supposed to be treated as a canvas...
+    }
+    return 1;
+}
+
+static int lsurface_newImageSnapshot(lua_State* L) {
+    SkImage* image = get_ref<SkSurface>(L, 1)->newImageSnapshot();
+    if (NULL == image) {
+        lua_pushnil(L);
+    } else {
+        push_ref(L, image)->unref();
+    }
+    return 1;
+}
+
+static int lsurface_newSurface(lua_State* L) {
+    int width = lua2int_def(L, 2, 0);
+    int height = lua2int_def(L, 3, 0);
+    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
+    SkSurface* surface = get_ref<SkSurface>(L, 1)->newSurface(info);
+    if (NULL == surface) {
+        lua_pushnil(L);
+    } else {
+        push_ref(L, surface)->unref();
+    }
+    return 1;
+}
+
+static int lsurface_gc(lua_State* L) {
+    get_ref<SkSurface>(L, 1)->unref();
+    return 0;
+}
+
+static const struct luaL_Reg gSkSurface_Methods[] = {
+    { "width", lsurface_width },
+    { "height", lsurface_height },
+    { "getCanvas", lsurface_getCanvas },
+    { "newImageSnapshot", lsurface_newImageSnapshot },
+    { "newSurface", lsurface_newSurface },
+    { "__gc", lsurface_gc },
+    { NULL, NULL }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int lpicturerecorder_beginRecording(lua_State* L) {
+    const SkScalar w = lua2scalar_def(L, 2, -1);
+    const SkScalar h = lua2scalar_def(L, 3, -1);
+    if (w <= 0 || h <= 0) {
+        lua_pushnil(L);
+        return 1;
+    }
+
+    SkCanvas* canvas = get_obj<SkPictureRecorder>(L, 1)->beginRecording(w, h);
+    if (NULL == canvas) {
+        lua_pushnil(L);
+        return 1;
+    }
+
+    push_ref(L, canvas);
+    return 1;
+}
+
+static int lpicturerecorder_getCanvas(lua_State* L) {
+    SkCanvas* canvas = get_obj<SkPictureRecorder>(L, 1)->getRecordingCanvas();
+    if (NULL == canvas) {
+        lua_pushnil(L);
+        return 1;
+    }
+    push_ref(L, canvas);
+    return 1;
+}
+
+static int lpicturerecorder_endRecording(lua_State* L) {
+    SkPicture* pic = get_obj<SkPictureRecorder>(L, 1)->endRecording();
+    if (NULL == pic) {
+        lua_pushnil(L);
+        return 1;
+    }
+    push_ref(L, pic)->unref();
+    return 1;
+}
+
+static int lpicturerecorder_gc(lua_State* L) {
+    get_obj<SkPictureRecorder>(L, 1)->~SkPictureRecorder();
+    return 0;
+}
+
+static const struct luaL_Reg gSkPictureRecorder_Methods[] = {
+    { "beginRecording", lpicturerecorder_beginRecording },
+    { "getCanvas", lpicturerecorder_getCanvas },
+    { "endRecording", lpicturerecorder_endRecording },
+    { "__gc", lpicturerecorder_gc },
+    { NULL, NULL }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int lpicture_width(lua_State* L) {
+    lua_pushnumber(L, get_ref<SkPicture>(L, 1)->cullRect().width());
+    return 1;
+}
+
+static int lpicture_height(lua_State* L) {
+    lua_pushnumber(L, get_ref<SkPicture>(L, 1)->cullRect().height());
+    return 1;
+}
+
+static int lpicture_gc(lua_State* L) {
+    get_ref<SkPicture>(L, 1)->unref();
+    return 0;
+}
+
+static const struct luaL_Reg gSkPicture_Methods[] = {
+    { "width", lpicture_width },
+    { "height", lpicture_height },
+    { "__gc", lpicture_gc },
+    { NULL, NULL }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int ltextblob_bounds(lua_State* L) {
+    SkLua(L).pushRect(get_ref<SkTextBlob>(L, 1)->bounds());
+    return 1;
+}
+
+static int ltextblob_gc(lua_State* L) {
+    SkSafeUnref(get_ref<SkTextBlob>(L, 1));
+    return 0;
+}
+
+static const struct luaL_Reg gSkTextBlob_Methods[] = {
+    { "bounds", ltextblob_bounds },
+    { "__gc", ltextblob_gc },
+    { NULL, NULL }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int ltypeface_getFamilyName(lua_State* L) {
+    SkString str;
+    get_ref<SkTypeface>(L, 1)->getFamilyName(&str);
+    lua_pushstring(L, str.c_str());
+    return 1;
+}
+
+static int ltypeface_getStyle(lua_State* L) {
+    lua_pushnumber(L, (double)get_ref<SkTypeface>(L, 1)->style());
+    return 1;
+}
+
 static int ltypeface_gc(lua_State* L) {
     SkSafeUnref(get_ref<SkTypeface>(L, 1));
     return 0;
 }
 
 static const struct luaL_Reg gSkTypeface_Methods[] = {
+    { "getFamilyName", ltypeface_getFamilyName },
+    { "getStyle", ltypeface_getStyle },
     { "__gc", ltypeface_gc },
     { NULL, NULL }
 };
@@ -1132,12 +1802,47 @@ static int lsk_newDocumentPDF(lua_State* L) {
         // do I need to push a nil on the stack and return 1?
         return 0;
     } else {
-        push_ref(L, doc);
-        doc->unref();
+        push_ref(L, doc)->unref();
         return 1;
     }
 }
 
+static int lsk_newBlurImageFilter(lua_State* L) {
+    SkScalar sigmaX = lua2scalar_def(L, 1, 0);
+    SkScalar sigmaY = lua2scalar_def(L, 2, 0);
+    SkImageFilter* imf = SkBlurImageFilter::Create(sigmaX, sigmaY);
+    if (NULL == imf) {
+        lua_pushnil(L);
+    } else {
+        push_ref(L, imf)->unref();
+    }
+    return 1;
+}
+
+static int lsk_newLinearGradient(lua_State* L) {
+    SkScalar x0 = lua2scalar_def(L, 1, 0);
+    SkScalar y0 = lua2scalar_def(L, 2, 0);
+    SkColor  c0 = lua2color(L, 3);
+    SkScalar x1 = lua2scalar_def(L, 4, 0);
+    SkScalar y1 = lua2scalar_def(L, 5, 0);
+    SkColor  c1 = lua2color(L, 6);
+
+    SkPoint pts[] = { { x0, y0 }, { x1, y1 } };
+    SkColor colors[] = { c0, c1 };
+    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+    if (NULL == s) {
+        lua_pushnil(L);
+    } else {
+        push_ref(L, s)->unref();
+    }
+    return 1;
+}
+
+static int lsk_newMatrix(lua_State* L) {
+    push_new<SkMatrix>(L)->reset();
+    return 1;
+}
+
 static int lsk_newPaint(lua_State* L) {
     push_new<SkPaint>(L);
     return 1;
@@ -1148,12 +1853,36 @@ static int lsk_newPath(lua_State* L) {
     return 1;
 }
 
+static int lsk_newPictureRecorder(lua_State* L) {
+    push_new<SkPictureRecorder>(L);
+    return 1;
+}
+
 static int lsk_newRRect(lua_State* L) {
-    SkRRect* rr = push_new<SkRRect>(L);
-    rr->setEmpty();
+    push_new<SkRRect>(L)->setEmpty();
     return 1;
 }
 
+#include "SkTextBox.h"
+// Sk.newTextBlob(text, rect, paint)
+static int lsk_newTextBlob(lua_State* L) {
+    const char* text = lua_tolstring(L, 1, NULL);
+    SkRect bounds;
+    lua2rect(L, 2, &bounds);
+    const SkPaint& paint = *get_obj<SkPaint>(L, 3);
+
+    SkTextBox box;
+    box.setMode(SkTextBox::kLineBreak_Mode);
+    box.setBox(bounds);
+    box.setText(text, strlen(text), paint);
+
+    SkScalar newBottom;
+    SkAutoTUnref<SkTextBlob> blob(box.snapshotTextBlob(&newBottom));
+    push_ref<SkTextBlob>(L, blob);
+    SkLua(L).pushScalar(newBottom);
+    return 2;
+}
+
 static int lsk_newTypeface(lua_State* L) {
     const char* name = NULL;
     int style = SkTypeface::kNormal;
@@ -1172,8 +1901,20 @@ static int lsk_newTypeface(lua_State* L) {
     if (NULL == face) {
         face = SkTypeface::RefDefault();
     }
-    push_ref(L, face);
-    face->unref();
+    push_ref(L, face)->unref();
+    return 1;
+}
+
+static int lsk_newRasterSurface(lua_State* L) {
+    int width = lua2int_def(L, 1, 0);
+    int height = lua2int_def(L, 2, 0);
+    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
+    SkSurface* surface = SkSurface::NewRaster(info);
+    if (NULL == surface) {
+        lua_pushnil(L);
+    } else {
+        push_ref(L, surface)->unref();
+    }
     return 1;
 }
 
@@ -1182,10 +1923,11 @@ static int lsk_loadImage(lua_State* L) {
         const char* name = lua_tolstring(L, 1, NULL);
         SkAutoDataUnref data(SkData::NewFromFileName(name));
         if (data.get()) {
-            SkImage* image = SkImage::NewEncodedData(data.get());
+            SkImage* image = SkImage::NewFromGenerator(
+                SkDecodingImageGenerator::Create(data, SkDecodingImageGenerator::Options()));
+
             if (image) {
-                push_ref(L, image);
-                image->unref();
+                push_ref(L, image)->unref();
                 return 1;
             }
         }
@@ -1201,9 +1943,15 @@ static void register_Sk(lua_State* L) {
 
     setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
     setfield_function(L, "loadImage", lsk_loadImage);
+    setfield_function(L, "newBlurImageFilter", lsk_newBlurImageFilter);
+    setfield_function(L, "newLinearGradient", lsk_newLinearGradient);
+    setfield_function(L, "newMatrix", lsk_newMatrix);
     setfield_function(L, "newPaint", lsk_newPaint);
     setfield_function(L, "newPath", lsk_newPath);
+    setfield_function(L, "newPictureRecorder", lsk_newPictureRecorder);
     setfield_function(L, "newRRect", lsk_newRRect);
+    setfield_function(L, "newRasterSurface", lsk_newRasterSurface);
+    setfield_function(L, "newTextBlob", lsk_newTextBlob);
     setfield_function(L, "newTypeface", lsk_newTypeface);
     lua_pop(L, 1);  // pop off the Sk table
 }
@@ -1222,12 +1970,18 @@ void SkLua::Load(lua_State* L) {
     REG_CLASS(L, SkCanvas);
     REG_CLASS(L, SkDocument);
     REG_CLASS(L, SkImage);
-    REG_CLASS(L, SkPath);
+    REG_CLASS(L, SkImageFilter);
+    REG_CLASS(L, SkMatrix);
     REG_CLASS(L, SkPaint);
+    REG_CLASS(L, SkPath);
+    REG_CLASS(L, SkPathEffect);
+    REG_CLASS(L, SkPicture);
+    REG_CLASS(L, SkPictureRecorder);
     REG_CLASS(L, SkRRect);
     REG_CLASS(L, SkShader);
+    REG_CLASS(L, SkSurface);
+    REG_CLASS(L, SkTextBlob);
     REG_CLASS(L, SkTypeface);
-    REG_CLASS(L, SkMatrix);
 }
 
 extern "C" int luaopen_skia(lua_State* L);