Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright 2013 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkLua.h"
      9 
     10 #if SK_SUPPORT_GPU
     11 #include "GrReducedClip.h"
     12 #endif
     13 
     14 #include "SkCanvas.h"
     15 #include "SkData.h"
     16 #include "SkDecodingImageGenerator.h"
     17 #include "SkDocument.h"
     18 #include "SkImage.h"
     19 #include "SkMatrix.h"
     20 #include "SkPaint.h"
     21 #include "SkPath.h"
     22 #include "SkPixelRef.h"
     23 #include "SkRRect.h"
     24 #include "SkString.h"
     25 #include "SkTextBlob.h"
     26 #include "SkTypeface.h"
     27 
     28 extern "C" {
     29     #include "lua.h"
     30     #include "lualib.h"
     31     #include "lauxlib.h"
     32 }
     33 
     34 // return the metatable name for a given class
     35 template <typename T> const char* get_mtname();
     36 #define DEF_MTNAME(T)                           \
     37     template <> const char* get_mtname<T>() {   \
     38         return #T "_LuaMetaTableName";          \
     39     }
     40 
     41 DEF_MTNAME(SkCanvas)
     42 DEF_MTNAME(SkDocument)
     43 DEF_MTNAME(SkImage)
     44 DEF_MTNAME(SkMatrix)
     45 DEF_MTNAME(SkRRect)
     46 DEF_MTNAME(SkPath)
     47 DEF_MTNAME(SkPaint)
     48 DEF_MTNAME(SkPathEffect)
     49 DEF_MTNAME(SkShader)
     50 DEF_MTNAME(SkTextBlob)
     51 DEF_MTNAME(SkTypeface)
     52 
     53 template <typename T> T* push_new(lua_State* L) {
     54     T* addr = (T*)lua_newuserdata(L, sizeof(T));
     55     new (addr) T;
     56     luaL_getmetatable(L, get_mtname<T>());
     57     lua_setmetatable(L, -2);
     58     return addr;
     59 }
     60 
     61 template <typename T> void push_obj(lua_State* L, const T& obj) {
     62     new (lua_newuserdata(L, sizeof(T))) T(obj);
     63     luaL_getmetatable(L, get_mtname<T>());
     64     lua_setmetatable(L, -2);
     65 }
     66 
     67 template <typename T> void push_ref(lua_State* L, T* ref) {
     68     *(T**)lua_newuserdata(L, sizeof(T*)) = SkSafeRef(ref);
     69     luaL_getmetatable(L, get_mtname<T>());
     70     lua_setmetatable(L, -2);
     71 }
     72 
     73 template <typename T> T* get_ref(lua_State* L, int index) {
     74     return *(T**)luaL_checkudata(L, index, get_mtname<T>());
     75 }
     76 
     77 template <typename T> T* get_obj(lua_State* L, int index) {
     78     return (T*)luaL_checkudata(L, index, get_mtname<T>());
     79 }
     80 
     81 static bool lua2bool(lua_State* L, int index) {
     82     return !!lua_toboolean(L, index);
     83 }
     84 
     85 ///////////////////////////////////////////////////////////////////////////////
     86 
     87 SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) {
     88     fL = luaL_newstate();
     89     luaL_openlibs(fL);
     90     SkLua::Load(fL);
     91 }
     92 
     93 SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {}
     94 
     95 SkLua::~SkLua() {
     96     if (fWeOwnL) {
     97         if (fTermCode.size() > 0) {
     98             lua_getglobal(fL, fTermCode.c_str());
     99             if (lua_pcall(fL, 0, 0, 0) != LUA_OK) {
    100                 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
    101             }
    102         }
    103         lua_close(fL);
    104     }
    105 }
    106 
    107 bool SkLua::runCode(const char code[]) {
    108     int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0);
    109     if (err) {
    110         SkDebugf("--- lua failed: %s\n", lua_tostring(fL, -1));
    111         return false;
    112     }
    113     return true;
    114 }
    115 
    116 bool SkLua::runCode(const void* code, size_t size) {
    117     SkString str((const char*)code, size);
    118     return this->runCode(str.c_str());
    119 }
    120 
    121 ///////////////////////////////////////////////////////////////////////////////
    122 
    123 #define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0)
    124 
    125 static void setfield_bool_if(lua_State* L, const char key[], bool pred) {
    126     if (pred) {
    127         lua_pushboolean(L, true);
    128         lua_setfield(L, -2, key);
    129     }
    130 }
    131 
    132 static void setfield_string(lua_State* L, const char key[], const char value[]) {
    133     lua_pushstring(L, value);
    134     lua_setfield(L, -2, key);
    135 }
    136 
    137 static void setfield_number(lua_State* L, const char key[], double value) {
    138     lua_pushnumber(L, value);
    139     lua_setfield(L, -2, key);
    140 }
    141 
    142 static void setfield_boolean(lua_State* L, const char key[], bool value) {
    143     lua_pushboolean(L, value);
    144     lua_setfield(L, -2, key);
    145 }
    146 
    147 static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
    148     setfield_number(L, key, SkScalarToLua(value));
    149 }
    150 
    151 static void setfield_function(lua_State* L,
    152                               const char key[], lua_CFunction value) {
    153     lua_pushcfunction(L, value);
    154     lua_setfield(L, -2, key);
    155 }
    156 
    157 static void setarray_number(lua_State* L, int index, double value) {
    158     lua_pushnumber(L, value);
    159     lua_rawseti(L, -2, index);
    160 }
    161 
    162 static void setarray_scalar(lua_State* L, int index, SkScalar value) {
    163     setarray_number(L, index, SkScalarToLua(value));
    164 }
    165 
    166 void SkLua::pushBool(bool value, const char key[]) {
    167     lua_pushboolean(fL, value);
    168     CHECK_SETFIELD(key);
    169 }
    170 
    171 void SkLua::pushString(const char str[], const char key[]) {
    172     lua_pushstring(fL, str);
    173     CHECK_SETFIELD(key);
    174 }
    175 
    176 void SkLua::pushString(const char str[], size_t length, const char key[]) {
    177     // TODO: how to do this w/o making a copy?
    178     SkString s(str, length);
    179     lua_pushstring(fL, s.c_str());
    180     CHECK_SETFIELD(key);
    181 }
    182 
    183 void SkLua::pushString(const SkString& str, const char key[]) {
    184     lua_pushstring(fL, str.c_str());
    185     CHECK_SETFIELD(key);
    186 }
    187 
    188 void SkLua::pushColor(SkColor color, const char key[]) {
    189     lua_newtable(fL);
    190     setfield_number(fL, "a", SkColorGetA(color) / 255.0);
    191     setfield_number(fL, "r", SkColorGetR(color) / 255.0);
    192     setfield_number(fL, "g", SkColorGetG(color) / 255.0);
    193     setfield_number(fL, "b", SkColorGetB(color) / 255.0);
    194     CHECK_SETFIELD(key);
    195 }
    196 
    197 void SkLua::pushU32(uint32_t value, const char key[]) {
    198     lua_pushnumber(fL, (double)value);
    199     CHECK_SETFIELD(key);
    200 }
    201 
    202 void SkLua::pushScalar(SkScalar value, const char key[]) {
    203     lua_pushnumber(fL, SkScalarToLua(value));
    204     CHECK_SETFIELD(key);
    205 }
    206 
    207 void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
    208     lua_newtable(fL);
    209     for (int i = 0; i < count; ++i) {
    210         // make it base-1 to match lua convention
    211         setarray_number(fL, i + 1, (double)array[i]);
    212     }
    213     CHECK_SETFIELD(key);
    214 }
    215 
    216 void SkLua::pushArrayPoint(const SkPoint array[], int count, const char key[]) {
    217     lua_newtable(fL);
    218     for (int i = 0; i < count; ++i) {
    219         // make it base-1 to match lua convention
    220         lua_newtable(fL);
    221         this->pushScalar(array[i].fX, "x");
    222         this->pushScalar(array[i].fY, "y");
    223         lua_rawseti(fL, -2, i + 1);
    224     }
    225     CHECK_SETFIELD(key);
    226 }
    227 
    228 void SkLua::pushArrayScalar(const SkScalar array[], int count, const char key[]) {
    229     lua_newtable(fL);
    230     for (int i = 0; i < count; ++i) {
    231         // make it base-1 to match lua convention
    232         setarray_scalar(fL, i + 1, array[i]);
    233     }
    234     CHECK_SETFIELD(key);
    235 }
    236 
    237 void SkLua::pushRect(const SkRect& r, const char key[]) {
    238     lua_newtable(fL);
    239     setfield_scalar(fL, "left", r.fLeft);
    240     setfield_scalar(fL, "top", r.fTop);
    241     setfield_scalar(fL, "right", r.fRight);
    242     setfield_scalar(fL, "bottom", r.fBottom);
    243     CHECK_SETFIELD(key);
    244 }
    245 
    246 void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
    247     push_obj(fL, rr);
    248     CHECK_SETFIELD(key);
    249 }
    250 
    251 void SkLua::pushDash(const SkPathEffect::DashInfo& info, const char key[]) {
    252     lua_newtable(fL);
    253     setfield_scalar(fL, "phase", info.fPhase);
    254     this->pushArrayScalar(info.fIntervals, info.fCount, "intervals");
    255     CHECK_SETFIELD(key);
    256 }
    257 
    258 
    259 void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
    260     push_obj(fL, matrix);
    261     CHECK_SETFIELD(key);
    262 }
    263 
    264 void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
    265     push_obj(fL, paint);
    266     CHECK_SETFIELD(key);
    267 }
    268 
    269 void SkLua::pushPath(const SkPath& path, const char key[]) {
    270     push_obj(fL, path);
    271     CHECK_SETFIELD(key);
    272 }
    273 
    274 void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
    275     push_ref(fL, canvas);
    276     CHECK_SETFIELD(key);
    277 }
    278 
    279 void SkLua::pushTextBlob(const SkTextBlob* blob, const char key[]) {
    280     push_ref(fL, const_cast<SkTextBlob*>(blob));
    281     CHECK_SETFIELD(key);
    282 }
    283 
    284 static const char* element_type(SkClipStack::Element::Type type) {
    285     switch (type) {
    286         case SkClipStack::Element::kEmpty_Type:
    287             return "empty";
    288         case SkClipStack::Element::kRect_Type:
    289             return "rect";
    290         case SkClipStack::Element::kRRect_Type:
    291             return "rrect";
    292         case SkClipStack::Element::kPath_Type:
    293             return "path";
    294     }
    295     return "unknown";
    296 }
    297 
    298 static const char* region_op(SkRegion::Op op) {
    299     switch (op) {
    300         case SkRegion::kDifference_Op:
    301             return "difference";
    302         case SkRegion::kIntersect_Op:
    303             return "intersect";
    304         case SkRegion::kUnion_Op:
    305             return "union";
    306         case SkRegion::kXOR_Op:
    307             return "xor";
    308         case SkRegion::kReverseDifference_Op:
    309             return "reverse-difference";
    310         case SkRegion::kReplace_Op:
    311             return "replace";
    312     }
    313     return "unknown";
    314 }
    315 
    316 void SkLua::pushClipStack(const SkClipStack& stack, const char* key) {
    317     lua_newtable(fL);
    318     SkClipStack::B2TIter iter(stack);
    319     const SkClipStack::Element* element;
    320     int i = 0;
    321     while ((element = iter.next())) {
    322         this->pushClipStackElement(*element);
    323         lua_rawseti(fL, -2, ++i);
    324     }
    325     CHECK_SETFIELD(key);
    326 }
    327 
    328 void SkLua::pushClipStackElement(const SkClipStack::Element& element, const char* key) {
    329     lua_newtable(fL);
    330     SkClipStack::Element::Type type = element.getType();
    331     this->pushString(element_type(type), "type");
    332     switch (type) {
    333         case SkClipStack::Element::kEmpty_Type:
    334             break;
    335         case SkClipStack::Element::kRect_Type:
    336             this->pushRect(element.getRect(), "rect");
    337             break;
    338         case SkClipStack::Element::kRRect_Type:
    339             this->pushRRect(element.getRRect(), "rrect");
    340             break;
    341         case SkClipStack::Element::kPath_Type:
    342             this->pushPath(element.getPath(), "path");
    343             break;
    344     }
    345     this->pushString(region_op(element.getOp()), "op");
    346     this->pushBool(element.isAA(), "aa");
    347     CHECK_SETFIELD(key);
    348 }
    349 
    350 
    351 ///////////////////////////////////////////////////////////////////////////////
    352 ///////////////////////////////////////////////////////////////////////////////
    353 
    354 static SkScalar lua2scalar(lua_State* L, int index) {
    355     SkASSERT(lua_isnumber(L, index));
    356     return SkLuaToScalar(lua_tonumber(L, index));
    357 }
    358 
    359 static SkScalar lua2scalar_def(lua_State* L, int index, SkScalar defaultValue) {
    360     if (lua_isnumber(L, index)) {
    361         return SkLuaToScalar(lua_tonumber(L, index));
    362     } else {
    363         return defaultValue;
    364     }
    365 }
    366 
    367 static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
    368     SkASSERT(lua_istable(L, index));
    369     lua_pushstring(L, key);
    370     lua_gettable(L, index);
    371 
    372     SkScalar value = lua2scalar(L, -1);
    373     lua_pop(L, 1);
    374     return value;
    375 }
    376 
    377 static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
    378     SkASSERT(lua_istable(L, index));
    379     lua_pushstring(L, key);
    380     lua_gettable(L, index);
    381 
    382     SkScalar value;
    383     if (lua_isnil(L, -1)) {
    384         value = def;
    385     } else {
    386         value = lua2scalar(L, -1);
    387     }
    388     lua_pop(L, 1);
    389     return value;
    390 }
    391 
    392 static U8CPU unit2byte(SkScalar x) {
    393     if (x <= 0) {
    394         return 0;
    395     } else if (x >= 1) {
    396         return 255;
    397     } else {
    398         return SkScalarRoundToInt(x * 255);
    399     }
    400 }
    401 
    402 static SkColor lua2color(lua_State* L, int index) {
    403     return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
    404                           unit2byte(getfield_scalar(L, index, "r")),
    405                           unit2byte(getfield_scalar(L, index, "g")),
    406                           unit2byte(getfield_scalar(L, index, "b")));
    407 }
    408 
    409 static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
    410     rect->set(getfield_scalar_default(L, index, "left", 0),
    411               getfield_scalar_default(L, index, "top", 0),
    412               getfield_scalar(L, index, "right"),
    413               getfield_scalar(L, index, "bottom"));
    414     return rect;
    415 }
    416 
    417 static int lcanvas_drawColor(lua_State* L) {
    418     get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
    419     return 0;
    420 }
    421 
    422 static int lcanvas_drawRect(lua_State* L) {
    423     SkRect rect;
    424     get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
    425                                       *get_obj<SkPaint>(L, 3));
    426     return 0;
    427 }
    428 
    429 static int lcanvas_drawOval(lua_State* L) {
    430     SkRect rect;
    431     get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
    432                                       *get_obj<SkPaint>(L, 3));
    433     return 0;
    434 }
    435 
    436 static int lcanvas_drawCircle(lua_State* L) {
    437     get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
    438                                         lua2scalar(L, 3),
    439                                         lua2scalar(L, 4),
    440                                         *get_obj<SkPaint>(L, 5));
    441     return 0;
    442 }
    443 
    444 static int lcanvas_drawImage(lua_State* L) {
    445     SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
    446     SkImage* image = get_ref<SkImage>(L, 2);
    447     if (NULL == image) {
    448         return 0;
    449     }
    450     SkScalar x = lua2scalar(L, 3);
    451     SkScalar y = lua2scalar(L, 4);
    452 
    453     SkPaint paint;
    454     const SkPaint* paintPtr = NULL;
    455     if (lua_isnumber(L, 5)) {
    456         paint.setAlpha(SkScalarRoundToInt(lua2scalar(L, 5) * 255));
    457         paintPtr = &paint;
    458     }
    459     canvas->drawImage(image, x, y, paintPtr);
    460     return 0;
    461 }
    462 
    463 static int lcanvas_drawPath(lua_State* L) {
    464     get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
    465                                       *get_obj<SkPaint>(L, 3));
    466     return 0;
    467 }
    468 
    469 static int lcanvas_drawText(lua_State* L) {
    470     if (lua_gettop(L) < 5) {
    471         return 0;
    472     }
    473 
    474     if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
    475         size_t len;
    476         const char* text = lua_tolstring(L, 2, &len);
    477         get_ref<SkCanvas>(L, 1)->drawText(text, len,
    478                                           lua2scalar(L, 3), lua2scalar(L, 4),
    479                                           *get_obj<SkPaint>(L, 5));
    480     }
    481     return 0;
    482 }
    483 
    484 static int lcanvas_getSaveCount(lua_State* L) {
    485     lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
    486     return 1;
    487 }
    488 
    489 static int lcanvas_getTotalMatrix(lua_State* L) {
    490     SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
    491     return 1;
    492 }
    493 
    494 static int lcanvas_getClipStack(lua_State* L) {
    495     SkLua(L).pushClipStack(*get_ref<SkCanvas>(L, 1)->getClipStack());
    496     return 1;
    497 }
    498 
    499 int SkLua::lcanvas_getReducedClipStack(lua_State* L) {
    500 #if SK_SUPPORT_GPU
    501     const SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
    502     SkISize layerSize = canvas->getTopLayerSize();
    503     SkIPoint layerOrigin = canvas->getTopLayerOrigin();
    504     SkIRect queryBounds = SkIRect::MakeXYWH(layerOrigin.fX, layerOrigin.fY,
    505                                             layerSize.fWidth, layerSize.fHeight);
    506 
    507     GrReducedClip::ElementList elements;
    508     GrReducedClip::InitialState initialState;
    509     int32_t genID;
    510     SkIRect resultBounds;
    511 
    512     const SkClipStack& stack = *canvas->getClipStack();
    513 
    514     GrReducedClip::ReduceClipStack(stack,
    515                                    queryBounds,
    516                                    &elements,
    517                                    &genID,
    518                                    &initialState,
    519                                    &resultBounds,
    520                                    NULL);
    521 
    522     GrReducedClip::ElementList::Iter iter(elements);
    523     int i = 0;
    524     lua_newtable(L);
    525     while(iter.get()) {
    526         SkLua(L).pushClipStackElement(*iter.get());
    527         iter.next();
    528         lua_rawseti(L, -2, ++i);
    529     }
    530     // Currently this only returns the element list to lua, not the initial state or result bounds.
    531     // It could return these as additional items on the lua stack.
    532     return 1;
    533 #else
    534     return 0;
    535 #endif
    536 }
    537 
    538 static int lcanvas_save(lua_State* L) {
    539     lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
    540     return 1;
    541 }
    542 
    543 static int lcanvas_restore(lua_State* L) {
    544     get_ref<SkCanvas>(L, 1)->restore();
    545     return 0;
    546 }
    547 
    548 static int lcanvas_scale(lua_State* L) {
    549     SkScalar sx = lua2scalar_def(L, 2, 1);
    550     SkScalar sy = lua2scalar_def(L, 3, sx);
    551     get_ref<SkCanvas>(L, 1)->scale(sx, sy);
    552     return 0;
    553 }
    554 
    555 static int lcanvas_translate(lua_State* L) {
    556     SkScalar tx = lua2scalar_def(L, 2, 0);
    557     SkScalar ty = lua2scalar_def(L, 3, 0);
    558     get_ref<SkCanvas>(L, 1)->translate(tx, ty);
    559     return 0;
    560 }
    561 
    562 static int lcanvas_rotate(lua_State* L) {
    563     SkScalar degrees = lua2scalar_def(L, 2, 0);
    564     get_ref<SkCanvas>(L, 1)->rotate(degrees);
    565     return 0;
    566 }
    567 
    568 static int lcanvas_gc(lua_State* L) {
    569     get_ref<SkCanvas>(L, 1)->unref();
    570     return 0;
    571 }
    572 
    573 const struct luaL_Reg gSkCanvas_Methods[] = {
    574     { "drawColor", lcanvas_drawColor },
    575     { "drawRect", lcanvas_drawRect },
    576     { "drawOval", lcanvas_drawOval },
    577     { "drawCircle", lcanvas_drawCircle },
    578     { "drawImage", lcanvas_drawImage },
    579     { "drawPath", lcanvas_drawPath },
    580     { "drawText", lcanvas_drawText },
    581     { "getSaveCount", lcanvas_getSaveCount },
    582     { "getTotalMatrix", lcanvas_getTotalMatrix },
    583     { "getClipStack", lcanvas_getClipStack },
    584 #if SK_SUPPORT_GPU
    585     { "getReducedClipStack", SkLua::lcanvas_getReducedClipStack },
    586 #endif
    587     { "save", lcanvas_save },
    588     { "restore", lcanvas_restore },
    589     { "scale", lcanvas_scale },
    590     { "translate", lcanvas_translate },
    591     { "rotate", lcanvas_rotate },
    592     { "__gc", lcanvas_gc },
    593     { NULL, NULL }
    594 };
    595 
    596 ///////////////////////////////////////////////////////////////////////////////
    597 
    598 static int ldocument_beginPage(lua_State* L) {
    599     const SkRect* contentPtr = NULL;
    600     push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
    601                                                      lua2scalar(L, 3),
    602                                                      contentPtr));
    603     return 1;
    604 }
    605 
    606 static int ldocument_endPage(lua_State* L) {
    607     get_ref<SkDocument>(L, 1)->endPage();
    608     return 0;
    609 }
    610 
    611 static int ldocument_close(lua_State* L) {
    612     get_ref<SkDocument>(L, 1)->close();
    613     return 0;
    614 }
    615 
    616 static int ldocument_gc(lua_State* L) {
    617     get_ref<SkDocument>(L, 1)->unref();
    618     return 0;
    619 }
    620 
    621 static const struct luaL_Reg gSkDocument_Methods[] = {
    622     { "beginPage", ldocument_beginPage },
    623     { "endPage", ldocument_endPage },
    624     { "close", ldocument_close },
    625     { "__gc", ldocument_gc },
    626     { NULL, NULL }
    627 };
    628 
    629 ///////////////////////////////////////////////////////////////////////////////
    630 
    631 static int lpaint_isAntiAlias(lua_State* L) {
    632     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
    633     return 1;
    634 }
    635 
    636 static int lpaint_setAntiAlias(lua_State* L) {
    637     get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
    638     return 0;
    639 }
    640 
    641 static int lpaint_isDither(lua_State* L) {
    642     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDither());
    643     return 1;
    644 }
    645 
    646 static int lpaint_isUnderlineText(lua_State* L) {
    647     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isUnderlineText());
    648     return 1;
    649 }
    650 
    651 static int lpaint_isStrikeThruText(lua_State* L) {
    652     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isStrikeThruText());
    653     return 1;
    654 }
    655 
    656 static int lpaint_isFakeBoldText(lua_State* L) {
    657     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isFakeBoldText());
    658     return 1;
    659 }
    660 
    661 static int lpaint_isLinearText(lua_State* L) {
    662     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLinearText());
    663     return 1;
    664 }
    665 
    666 static int lpaint_isSubpixelText(lua_State* L) {
    667     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isSubpixelText());
    668     return 1;
    669 }
    670 
    671 static int lpaint_isDevKernText(lua_State* L) {
    672     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDevKernText());
    673     return 1;
    674 }
    675 
    676 static int lpaint_isLCDRenderText(lua_State* L) {
    677     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLCDRenderText());
    678     return 1;
    679 }
    680 
    681 static int lpaint_isEmbeddedBitmapText(lua_State* L) {
    682     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isEmbeddedBitmapText());
    683     return 1;
    684 }
    685 
    686 static int lpaint_isAutohinted(lua_State* L) {
    687     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAutohinted());
    688     return 1;
    689 }
    690 
    691 static int lpaint_isVerticalText(lua_State* L) {
    692     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isVerticalText());
    693     return 1;
    694 }
    695 
    696 static int lpaint_getColor(lua_State* L) {
    697     SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
    698     return 1;
    699 }
    700 
    701 static int lpaint_setColor(lua_State* L) {
    702     get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
    703     return 0;
    704 }
    705 
    706 static int lpaint_getTextSize(lua_State* L) {
    707     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
    708     return 1;
    709 }
    710 
    711 static int lpaint_getTextScaleX(lua_State* L) {
    712     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextScaleX());
    713     return 1;
    714 }
    715 
    716 static int lpaint_getTextSkewX(lua_State* L) {
    717     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSkewX());
    718     return 1;
    719 }
    720 
    721 static int lpaint_setTextSize(lua_State* L) {
    722     get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
    723     return 0;
    724 }
    725 
    726 static int lpaint_getTypeface(lua_State* L) {
    727     push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
    728     return 1;
    729 }
    730 
    731 static int lpaint_setTypeface(lua_State* L) {
    732     get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
    733     return 0;
    734 }
    735 
    736 static int lpaint_getHinting(lua_State* L) {
    737     SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getHinting());
    738     return 1;
    739 }
    740 
    741 static int lpaint_getFontID(lua_State* L) {
    742     SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
    743     SkLua(L).pushU32(SkTypeface::UniqueID(face));
    744     return 1;
    745 }
    746 
    747 static const struct {
    748     const char*     fLabel;
    749     SkPaint::Align  fAlign;
    750 } gAlignRec[] = {
    751     { "left",   SkPaint::kLeft_Align },
    752     { "center", SkPaint::kCenter_Align },
    753     { "right",  SkPaint::kRight_Align },
    754 };
    755 
    756 static int lpaint_getTextAlign(lua_State* L) {
    757     SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
    758     for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
    759         if (gAlignRec[i].fAlign == align) {
    760             lua_pushstring(L, gAlignRec[i].fLabel);
    761             return 1;
    762         }
    763     }
    764     return 0;
    765 }
    766 
    767 static int lpaint_setTextAlign(lua_State* L) {
    768     if (lua_isstring(L, 2)) {
    769         size_t len;
    770         const char* label = lua_tolstring(L, 2, &len);
    771 
    772         for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
    773             if (!strcmp(gAlignRec[i].fLabel, label)) {
    774                 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
    775                 break;
    776             }
    777         }
    778     }
    779     return 0;
    780 }
    781 
    782 static int lpaint_getStroke(lua_State* L) {
    783     lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
    784     return 1;
    785 }
    786 
    787 static int lpaint_setStroke(lua_State* L) {
    788     SkPaint::Style style;
    789 
    790     if (lua_toboolean(L, 2)) {
    791         style = SkPaint::kStroke_Style;
    792     } else {
    793         style = SkPaint::kFill_Style;
    794     }
    795     get_obj<SkPaint>(L, 1)->setStyle(style);
    796     return 0;
    797 }
    798 
    799 static int lpaint_getStrokeCap(lua_State* L) {
    800     SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeCap());
    801     return 1;
    802 }
    803 
    804 static int lpaint_getStrokeJoin(lua_State* L) {
    805     SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeJoin());
    806     return 1;
    807 }
    808 
    809 static int lpaint_getTextEncoding(lua_State* L) {
    810     SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getTextEncoding());
    811     return 1;
    812 }
    813 
    814 static int lpaint_getStrokeWidth(lua_State* L) {
    815     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
    816     return 1;
    817 }
    818 
    819 static int lpaint_setStrokeWidth(lua_State* L) {
    820     get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
    821     return 0;
    822 }
    823 
    824 static int lpaint_getStrokeMiter(lua_State* L) {
    825     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeMiter());
    826     return 1;
    827 }
    828 
    829 static int lpaint_measureText(lua_State* L) {
    830     if (lua_isstring(L, 2)) {
    831         size_t len;
    832         const char* text = lua_tolstring(L, 2, &len);
    833         SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
    834         return 1;
    835     }
    836     return 0;
    837 }
    838 
    839 struct FontMetrics {
    840     SkScalar    fTop;       //!< The greatest distance above the baseline for any glyph (will be <= 0)
    841     SkScalar    fAscent;    //!< The recommended distance above the baseline (will be <= 0)
    842     SkScalar    fDescent;   //!< The recommended distance below the baseline (will be >= 0)
    843     SkScalar    fBottom;    //!< The greatest distance below the baseline for any glyph (will be >= 0)
    844     SkScalar    fLeading;   //!< The recommended distance to add between lines of text (will be >= 0)
    845     SkScalar    fAvgCharWidth;  //!< the average charactor width (>= 0)
    846     SkScalar    fXMin;      //!< The minimum bounding box x value for all glyphs
    847     SkScalar    fXMax;      //!< The maximum bounding box x value for all glyphs
    848     SkScalar    fXHeight;   //!< the height of an 'x' in px, or 0 if no 'x' in face
    849 };
    850 
    851 static int lpaint_getFontMetrics(lua_State* L) {
    852     SkPaint::FontMetrics fm;
    853     SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
    854 
    855     lua_newtable(L);
    856     setfield_scalar(L, "top", fm.fTop);
    857     setfield_scalar(L, "ascent", fm.fAscent);
    858     setfield_scalar(L, "descent", fm.fDescent);
    859     setfield_scalar(L, "bottom", fm.fBottom);
    860     setfield_scalar(L, "leading", fm.fLeading);
    861     SkLua(L).pushScalar(height);
    862     return 2;
    863 }
    864 
    865 static int lpaint_getEffects(lua_State* L) {
    866     const SkPaint* paint = get_obj<SkPaint>(L, 1);
    867 
    868     lua_newtable(L);
    869     setfield_bool_if(L, "looper", !!paint->getLooper());
    870     setfield_bool_if(L, "pathEffect", !!paint->getPathEffect());
    871     setfield_bool_if(L, "rasterizer", !!paint->getRasterizer());
    872     setfield_bool_if(L, "maskFilter", !!paint->getMaskFilter());
    873     setfield_bool_if(L, "shader", !!paint->getShader());
    874     setfield_bool_if(L, "colorFilter", !!paint->getColorFilter());
    875     setfield_bool_if(L, "imageFilter", !!paint->getImageFilter());
    876     setfield_bool_if(L, "xfermode", !!paint->getXfermode());
    877     return 1;
    878 }
    879 
    880 static int lpaint_getShader(lua_State* L) {
    881     const SkPaint* paint = get_obj<SkPaint>(L, 1);
    882     SkShader* shader = paint->getShader();
    883     if (shader) {
    884         push_ref(L, shader);
    885         return 1;
    886     }
    887     return 0;
    888 }
    889 
    890 static int lpaint_getPathEffect(lua_State* L) {
    891     const SkPaint* paint = get_obj<SkPaint>(L, 1);
    892     SkPathEffect* pe = paint->getPathEffect();
    893     if (pe) {
    894         push_ref(L, pe);
    895         return 1;
    896     }
    897     return 0;
    898 }
    899 
    900 static int lpaint_gc(lua_State* L) {
    901     get_obj<SkPaint>(L, 1)->~SkPaint();
    902     return 0;
    903 }
    904 
    905 static const struct luaL_Reg gSkPaint_Methods[] = {
    906     { "isAntiAlias", lpaint_isAntiAlias },
    907     { "setAntiAlias", lpaint_setAntiAlias },
    908     { "isDither", lpaint_isDither },
    909     { "isUnderlineText", lpaint_isUnderlineText },
    910     { "isStrikeThruText", lpaint_isStrikeThruText },
    911     { "isFakeBoldText", lpaint_isFakeBoldText },
    912     { "isLinearText", lpaint_isLinearText },
    913     { "isSubpixelText", lpaint_isSubpixelText },
    914     { "isDevKernText", lpaint_isDevKernText },
    915     { "isLCDRenderText", lpaint_isLCDRenderText },
    916     { "isEmbeddedBitmapText", lpaint_isEmbeddedBitmapText },
    917     { "isAutohinted", lpaint_isAutohinted },
    918     { "isVerticalText", lpaint_isVerticalText },
    919     { "getColor", lpaint_getColor },
    920     { "setColor", lpaint_setColor },
    921     { "getTextSize", lpaint_getTextSize },
    922     { "setTextSize", lpaint_setTextSize },
    923     { "getTextScaleX", lpaint_getTextScaleX },
    924     { "getTextSkewX", lpaint_getTextSkewX },
    925     { "getTypeface", lpaint_getTypeface },
    926     { "setTypeface", lpaint_setTypeface },
    927     { "getHinting", lpaint_getHinting },
    928     { "getFontID", lpaint_getFontID },
    929     { "getTextAlign", lpaint_getTextAlign },
    930     { "setTextAlign", lpaint_setTextAlign },
    931     { "getStroke", lpaint_getStroke },
    932     { "setStroke", lpaint_setStroke },
    933     { "getStrokeCap", lpaint_getStrokeCap },
    934     { "getStrokeJoin", lpaint_getStrokeJoin },
    935     { "getTextEncoding", lpaint_getTextEncoding },
    936     { "getStrokeWidth", lpaint_getStrokeWidth },
    937     { "setStrokeWidth", lpaint_setStrokeWidth },
    938     { "getStrokeMiter", lpaint_getStrokeMiter },
    939     { "measureText", lpaint_measureText },
    940     { "getFontMetrics", lpaint_getFontMetrics },
    941     { "getEffects", lpaint_getEffects },
    942     { "getShader", lpaint_getShader },
    943     { "getPathEffect", lpaint_getPathEffect },
    944     { "__gc", lpaint_gc },
    945     { NULL, NULL }
    946 };
    947 
    948 ///////////////////////////////////////////////////////////////////////////////
    949 
    950 static const char* mode2string(SkShader::TileMode mode) {
    951     static const char* gNames[] = { "clamp", "repeat", "mirror" };
    952     SkASSERT((unsigned)mode < SK_ARRAY_COUNT(gNames));
    953     return gNames[mode];
    954 }
    955 
    956 static const char* gradtype2string(SkShader::GradientType t) {
    957     static const char* gNames[] = {
    958         "none", "color", "linear", "radial", "radial2", "sweep", "conical"
    959     };
    960     SkASSERT((unsigned)t < SK_ARRAY_COUNT(gNames));
    961     return gNames[t];
    962 }
    963 
    964 static int lshader_isOpaque(lua_State* L) {
    965     SkShader* shader = get_ref<SkShader>(L, 1);
    966     return shader && shader->isOpaque();
    967 }
    968 
    969 static int lshader_asABitmap(lua_State* L) {
    970     SkShader* shader = get_ref<SkShader>(L, 1);
    971     if (shader) {
    972         SkBitmap bm;
    973         SkMatrix matrix;
    974         SkShader::TileMode modes[2];
    975         switch (shader->asABitmap(&bm, &matrix, modes)) {
    976             case SkShader::kDefault_BitmapType:
    977                 lua_newtable(L);
    978                 setfield_number(L, "genID", bm.pixelRef() ? bm.pixelRef()->getGenerationID() : 0);
    979                 setfield_number(L, "width", bm.width());
    980                 setfield_number(L, "height", bm.height());
    981                 setfield_string(L, "tileX", mode2string(modes[0]));
    982                 setfield_string(L, "tileY", mode2string(modes[1]));
    983                 return 1;
    984             default:
    985                 break;
    986         }
    987     }
    988     return 0;
    989 }
    990 
    991 static int lshader_asAGradient(lua_State* L) {
    992     SkShader* shader = get_ref<SkShader>(L, 1);
    993     if (shader) {
    994         SkShader::GradientInfo info;
    995         sk_bzero(&info, sizeof(info));
    996 
    997         SkColor colors[3];  // hacked in for extracting info on 3 color case.
    998         SkScalar pos[3];
    999 
   1000         info.fColorCount = 3;
   1001         info.fColors = &colors[0];
   1002         info.fColorOffsets = &pos[0];
   1003 
   1004         SkShader::GradientType t = shader->asAGradient(&info);
   1005 
   1006         if (SkShader::kNone_GradientType != t) {
   1007             lua_newtable(L);
   1008             setfield_string(L, "type", gradtype2string(t));
   1009             setfield_number(L, "colorCount", info.fColorCount);
   1010             setfield_string(L, "tile", mode2string(info.fTileMode));
   1011 
   1012             if (info.fColorCount == 3){
   1013                 setfield_number(L, "midPos", pos[1]);
   1014             }
   1015 
   1016             return 1;
   1017         }
   1018     }
   1019     return 0;
   1020 }
   1021 
   1022 static int lshader_gc(lua_State* L) {
   1023     get_ref<SkShader>(L, 1)->unref();
   1024     return 0;
   1025 }
   1026 
   1027 static const struct luaL_Reg gSkShader_Methods[] = {
   1028     { "isOpaque",       lshader_isOpaque },
   1029     { "asABitmap",      lshader_asABitmap },
   1030     { "asAGradient",    lshader_asAGradient },
   1031     { "__gc",           lshader_gc },
   1032     { NULL, NULL }
   1033 };
   1034 
   1035 ///////////////////////////////////////////////////////////////////////////////
   1036 
   1037 static int lpatheffect_asADash(lua_State* L) {
   1038     SkPathEffect* pe = get_ref<SkPathEffect>(L, 1);
   1039     if (pe) {
   1040         SkPathEffect::DashInfo info;
   1041         SkPathEffect::DashType dashType = pe->asADash(&info);
   1042         if (SkPathEffect::kDash_DashType == dashType) {
   1043             SkAutoTArray<SkScalar> intervals(info.fCount);
   1044             info.fIntervals = intervals.get();
   1045             pe->asADash(&info);
   1046             SkLua(L).pushDash(info);
   1047             return 1;
   1048         }
   1049     }
   1050     return 0;
   1051 }
   1052 
   1053 static int lpatheffect_gc(lua_State* L) {
   1054     get_ref<SkPathEffect>(L, 1)->unref();
   1055     return 0;
   1056 }
   1057 
   1058 static const struct luaL_Reg gSkPathEffect_Methods[] = {
   1059     { "asADash",        lpatheffect_asADash },
   1060     { "__gc",           lpatheffect_gc },
   1061     { NULL, NULL }
   1062 };
   1063 
   1064 ///////////////////////////////////////////////////////////////////////////////
   1065 
   1066 static int lmatrix_getType(lua_State* L) {
   1067     SkMatrix::TypeMask mask = get_obj<SkMatrix>(L, 1)->getType();
   1068 
   1069     lua_newtable(L);
   1070     setfield_boolean(L, "translate",   SkToBool(mask & SkMatrix::kTranslate_Mask));
   1071     setfield_boolean(L, "scale",       SkToBool(mask & SkMatrix::kScale_Mask));
   1072     setfield_boolean(L, "affine",      SkToBool(mask & SkMatrix::kAffine_Mask));
   1073     setfield_boolean(L, "perspective", SkToBool(mask & SkMatrix::kPerspective_Mask));
   1074     return 1;
   1075 }
   1076 
   1077 static int lmatrix_getScaleX(lua_State* L) {
   1078     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleX());
   1079     return 1;
   1080 }
   1081 
   1082 static int lmatrix_getScaleY(lua_State* L) {
   1083     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleY());
   1084     return 1;
   1085 }
   1086 
   1087 static int lmatrix_getTranslateX(lua_State* L) {
   1088     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateX());
   1089     return 1;
   1090 }
   1091 
   1092 static int lmatrix_getTranslateY(lua_State* L) {
   1093     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateY());
   1094     return 1;
   1095 }
   1096 
   1097 static const struct luaL_Reg gSkMatrix_Methods[] = {
   1098     { "getType", lmatrix_getType },
   1099     { "getScaleX", lmatrix_getScaleX },
   1100     { "getScaleY", lmatrix_getScaleY },
   1101     { "getTranslateX", lmatrix_getTranslateX },
   1102     { "getTranslateY", lmatrix_getTranslateY },
   1103     { NULL, NULL }
   1104 };
   1105 
   1106 ///////////////////////////////////////////////////////////////////////////////
   1107 
   1108 static int lpath_getBounds(lua_State* L) {
   1109     SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
   1110     return 1;
   1111 }
   1112 
   1113 static const char* fill_type_to_str(SkPath::FillType fill) {
   1114     switch (fill) {
   1115         case SkPath::kEvenOdd_FillType:
   1116             return "even-odd";
   1117         case SkPath::kWinding_FillType:
   1118             return "winding";
   1119         case SkPath::kInverseEvenOdd_FillType:
   1120             return "inverse-even-odd";
   1121         case SkPath::kInverseWinding_FillType:
   1122             return "inverse-winding";
   1123     }
   1124     return "unknown";
   1125 }
   1126 
   1127 static int lpath_getFillType(lua_State* L) {
   1128     SkPath::FillType fill = get_obj<SkPath>(L, 1)->getFillType();
   1129     SkLua(L).pushString(fill_type_to_str(fill));
   1130     return 1;
   1131 }
   1132 
   1133 static SkString segment_masks_to_str(uint32_t segmentMasks) {
   1134     SkString result;
   1135     bool first = true;
   1136     if (SkPath::kLine_SegmentMask & segmentMasks) {
   1137         result.append("line");
   1138         first = false;
   1139         SkDEBUGCODE(segmentMasks &= ~SkPath::kLine_SegmentMask;)
   1140     }
   1141     if (SkPath::kQuad_SegmentMask & segmentMasks) {
   1142         if (!first) {
   1143             result.append(" ");
   1144         }
   1145         result.append("quad");
   1146         first = false;
   1147         SkDEBUGCODE(segmentMasks &= ~SkPath::kQuad_SegmentMask;)
   1148     }
   1149     if (SkPath::kConic_SegmentMask & segmentMasks) {
   1150         if (!first) {
   1151             result.append(" ");
   1152         }
   1153         result.append("conic");
   1154         first = false;
   1155         SkDEBUGCODE(segmentMasks &= ~SkPath::kConic_SegmentMask;)
   1156     }
   1157     if (SkPath::kCubic_SegmentMask & segmentMasks) {
   1158         if (!first) {
   1159             result.append(" ");
   1160         }
   1161         result.append("cubic");
   1162         SkDEBUGCODE(segmentMasks &= ~SkPath::kCubic_SegmentMask;)
   1163     }
   1164     SkASSERT(0 == segmentMasks);
   1165     return result;
   1166 }
   1167 
   1168 static int lpath_getSegmentTypes(lua_State* L) {
   1169     uint32_t segMasks = get_obj<SkPath>(L, 1)->getSegmentMasks();
   1170     SkLua(L).pushString(segment_masks_to_str(segMasks));
   1171     return 1;
   1172 }
   1173 
   1174 static int lpath_isConvex(lua_State* L) {
   1175     bool isConvex = SkPath::kConvex_Convexity == get_obj<SkPath>(L, 1)->getConvexity();
   1176     SkLua(L).pushBool(isConvex);
   1177     return 1;
   1178 }
   1179 
   1180 static int lpath_isEmpty(lua_State* L) {
   1181     lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
   1182     return 1;
   1183 }
   1184 
   1185 static int lpath_isRect(lua_State* L) {
   1186     SkRect r;
   1187     bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
   1188     int ret_count = 1;
   1189     lua_pushboolean(L, pred);
   1190     if (pred) {
   1191         SkLua(L).pushRect(r);
   1192         ret_count += 1;
   1193     }
   1194     return ret_count;
   1195 }
   1196 
   1197 static const char* dir2string(SkPath::Direction dir) {
   1198     static const char* gStr[] = {
   1199         "unknown", "cw", "ccw"
   1200     };
   1201     SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
   1202     return gStr[dir];
   1203 }
   1204 
   1205 static int lpath_isNestedRects(lua_State* L) {
   1206     SkRect rects[2];
   1207     SkPath::Direction dirs[2];
   1208     bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
   1209     int ret_count = 1;
   1210     lua_pushboolean(L, pred);
   1211     if (pred) {
   1212         SkLua lua(L);
   1213         lua.pushRect(rects[0]);
   1214         lua.pushRect(rects[1]);
   1215         lua_pushstring(L, dir2string(dirs[0]));
   1216         lua_pushstring(L, dir2string(dirs[0]));
   1217         ret_count += 4;
   1218     }
   1219     return ret_count;
   1220 }
   1221 
   1222 static int lpath_countPoints(lua_State* L) {
   1223     lua_pushinteger(L, get_obj<SkPath>(L, 1)->countPoints());
   1224     return 1;
   1225 }
   1226 
   1227 static int lpath_reset(lua_State* L) {
   1228     get_obj<SkPath>(L, 1)->reset();
   1229     return 0;
   1230 }
   1231 
   1232 static int lpath_moveTo(lua_State* L) {
   1233     get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
   1234     return 0;
   1235 }
   1236 
   1237 static int lpath_lineTo(lua_State* L) {
   1238     get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
   1239     return 0;
   1240 }
   1241 
   1242 static int lpath_quadTo(lua_State* L) {
   1243     get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
   1244                                   lua2scalar(L, 4), lua2scalar(L, 5));
   1245     return 0;
   1246 }
   1247 
   1248 static int lpath_cubicTo(lua_State* L) {
   1249     get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
   1250                                    lua2scalar(L, 4), lua2scalar(L, 5),
   1251                                    lua2scalar(L, 6), lua2scalar(L, 7));
   1252     return 0;
   1253 }
   1254 
   1255 static int lpath_close(lua_State* L) {
   1256     get_obj<SkPath>(L, 1)->close();
   1257     return 0;
   1258 }
   1259 
   1260 static int lpath_gc(lua_State* L) {
   1261     get_obj<SkPath>(L, 1)->~SkPath();
   1262     return 0;
   1263 }
   1264 
   1265 static const struct luaL_Reg gSkPath_Methods[] = {
   1266     { "getBounds", lpath_getBounds },
   1267     { "getFillType", lpath_getFillType },
   1268     { "getSegmentTypes", lpath_getSegmentTypes },
   1269     { "isConvex", lpath_isConvex },
   1270     { "isEmpty", lpath_isEmpty },
   1271     { "isRect", lpath_isRect },
   1272     { "isNestedRects", lpath_isNestedRects },
   1273     { "countPoints", lpath_countPoints },
   1274     { "reset", lpath_reset },
   1275     { "moveTo", lpath_moveTo },
   1276     { "lineTo", lpath_lineTo },
   1277     { "quadTo", lpath_quadTo },
   1278     { "cubicTo", lpath_cubicTo },
   1279     { "close", lpath_close },
   1280     { "__gc", lpath_gc },
   1281     { NULL, NULL }
   1282 };
   1283 
   1284 ///////////////////////////////////////////////////////////////////////////////
   1285 
   1286 static const char* rrect_type(const SkRRect& rr) {
   1287     switch (rr.getType()) {
   1288         case SkRRect::kUnknown_Type: return "unknown";
   1289         case SkRRect::kEmpty_Type: return "empty";
   1290         case SkRRect::kRect_Type: return "rect";
   1291         case SkRRect::kOval_Type: return "oval";
   1292         case SkRRect::kSimple_Type: return "simple";
   1293         case SkRRect::kNinePatch_Type: return "nine-patch";
   1294         case SkRRect::kComplex_Type: return "complex";
   1295     }
   1296     SkDEBUGFAIL("never get here");
   1297     return "";
   1298 }
   1299 
   1300 static int lrrect_rect(lua_State* L) {
   1301     SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
   1302     return 1;
   1303 }
   1304 
   1305 static int lrrect_type(lua_State* L) {
   1306     lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
   1307     return 1;
   1308 }
   1309 
   1310 static int lrrect_radii(lua_State* L) {
   1311     int corner = SkToInt(lua_tointeger(L, 2));
   1312     SkVector v;
   1313     if (corner < 0 || corner > 3) {
   1314         SkDebugf("bad corner index %d", corner);
   1315         v.set(0, 0);
   1316     } else {
   1317         v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
   1318     }
   1319     lua_pushnumber(L, v.fX);
   1320     lua_pushnumber(L, v.fY);
   1321     return 2;
   1322 }
   1323 
   1324 static int lrrect_gc(lua_State* L) {
   1325     get_obj<SkRRect>(L, 1)->~SkRRect();
   1326     return 0;
   1327 }
   1328 
   1329 static const struct luaL_Reg gSkRRect_Methods[] = {
   1330     { "rect", lrrect_rect },
   1331     { "type", lrrect_type },
   1332     { "radii", lrrect_radii },
   1333     { "__gc", lrrect_gc },
   1334     { NULL, NULL }
   1335 };
   1336 
   1337 ///////////////////////////////////////////////////////////////////////////////
   1338 
   1339 static int limage_width(lua_State* L) {
   1340     lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
   1341     return 1;
   1342 }
   1343 
   1344 static int limage_height(lua_State* L) {
   1345     lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
   1346     return 1;
   1347 }
   1348 
   1349 static int limage_gc(lua_State* L) {
   1350     get_ref<SkImage>(L, 1)->unref();
   1351     return 0;
   1352 }
   1353 
   1354 static const struct luaL_Reg gSkImage_Methods[] = {
   1355     { "width", limage_width },
   1356     { "height", limage_height },
   1357     { "__gc", limage_gc },
   1358     { NULL, NULL }
   1359 };
   1360 
   1361 ///////////////////////////////////////////////////////////////////////////////
   1362 
   1363 static int ltypeface_gc(lua_State* L) {
   1364     SkSafeUnref(get_ref<SkTypeface>(L, 1));
   1365     return 0;
   1366 }
   1367 
   1368 static const struct luaL_Reg gSkTypeface_Methods[] = {
   1369     { "__gc", ltypeface_gc },
   1370     { NULL, NULL }
   1371 };
   1372 
   1373 ///////////////////////////////////////////////////////////////////////////////
   1374 
   1375 class AutoCallLua {
   1376 public:
   1377     AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
   1378         lua_getglobal(L, func);
   1379         if (!lua_isfunction(L, -1)) {
   1380             int t = lua_type(L, -1);
   1381             SkDebugf("--- expected function %d\n", t);
   1382         }
   1383 
   1384         lua_newtable(L);
   1385         setfield_string(L, "verb", verb);
   1386     }
   1387 
   1388     ~AutoCallLua() {
   1389         if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
   1390             SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
   1391         }
   1392         lua_settop(fL, -1);
   1393     }
   1394 
   1395 private:
   1396     lua_State* fL;
   1397 };
   1398 
   1399 #define AUTO_LUA(verb)  AutoCallLua acl(fL, fFunc.c_str(), verb)
   1400 
   1401 ///////////////////////////////////////////////////////////////////////////////
   1402 
   1403 static int lsk_newDocumentPDF(lua_State* L) {
   1404     const char* file = NULL;
   1405     if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
   1406         file = lua_tolstring(L, 1, NULL);
   1407     }
   1408 
   1409     SkDocument* doc = SkDocument::CreatePDF(file);
   1410     if (NULL == doc) {
   1411         // do I need to push a nil on the stack and return 1?
   1412         return 0;
   1413     } else {
   1414         push_ref(L, doc);
   1415         doc->unref();
   1416         return 1;
   1417     }
   1418 }
   1419 
   1420 static int lsk_newPaint(lua_State* L) {
   1421     push_new<SkPaint>(L);
   1422     return 1;
   1423 }
   1424 
   1425 static int lsk_newPath(lua_State* L) {
   1426     push_new<SkPath>(L);
   1427     return 1;
   1428 }
   1429 
   1430 static int lsk_newRRect(lua_State* L) {
   1431     SkRRect* rr = push_new<SkRRect>(L);
   1432     rr->setEmpty();
   1433     return 1;
   1434 }
   1435 
   1436 static int lsk_newTypeface(lua_State* L) {
   1437     const char* name = NULL;
   1438     int style = SkTypeface::kNormal;
   1439 
   1440     int count = lua_gettop(L);
   1441     if (count > 0 && lua_isstring(L, 1)) {
   1442         name = lua_tolstring(L, 1, NULL);
   1443         if (count > 1 && lua_isnumber(L, 2)) {
   1444             style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
   1445         }
   1446     }
   1447 
   1448     SkTypeface* face = SkTypeface::CreateFromName(name,
   1449                                                   (SkTypeface::Style)style);
   1450 //    SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
   1451     if (NULL == face) {
   1452         face = SkTypeface::RefDefault();
   1453     }
   1454     push_ref(L, face);
   1455     face->unref();
   1456     return 1;
   1457 }
   1458 
   1459 static int lsk_loadImage(lua_State* L) {
   1460     if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
   1461         const char* name = lua_tolstring(L, 1, NULL);
   1462         SkAutoDataUnref data(SkData::NewFromFileName(name));
   1463         if (data.get()) {
   1464             SkImage* image = SkImage::NewFromGenerator(
   1465                 SkDecodingImageGenerator::Create(data, SkDecodingImageGenerator::Options()));
   1466 
   1467             if (image) {
   1468                 push_ref(L, image);
   1469                 image->unref();
   1470                 return 1;
   1471             }
   1472         }
   1473     }
   1474     return 0;
   1475 }
   1476 
   1477 static void register_Sk(lua_State* L) {
   1478     lua_newtable(L);
   1479     lua_pushvalue(L, -1);
   1480     lua_setglobal(L, "Sk");
   1481     // the Sk table is still on top
   1482 
   1483     setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
   1484     setfield_function(L, "loadImage", lsk_loadImage);
   1485     setfield_function(L, "newPaint", lsk_newPaint);
   1486     setfield_function(L, "newPath", lsk_newPath);
   1487     setfield_function(L, "newRRect", lsk_newRRect);
   1488     setfield_function(L, "newTypeface", lsk_newTypeface);
   1489     lua_pop(L, 1);  // pop off the Sk table
   1490 }
   1491 
   1492 #define REG_CLASS(L, C)                             \
   1493     do {                                            \
   1494         luaL_newmetatable(L, get_mtname<C>());      \
   1495         lua_pushvalue(L, -1);                       \
   1496         lua_setfield(L, -2, "__index");             \
   1497         luaL_setfuncs(L, g##C##_Methods, 0);        \
   1498         lua_pop(L, 1); /* pop off the meta-table */ \
   1499     } while (0)
   1500 
   1501 void SkLua::Load(lua_State* L) {
   1502     register_Sk(L);
   1503     REG_CLASS(L, SkCanvas);
   1504     REG_CLASS(L, SkDocument);
   1505     REG_CLASS(L, SkImage);
   1506     REG_CLASS(L, SkPaint);
   1507     REG_CLASS(L, SkPath);
   1508     REG_CLASS(L, SkPathEffect);
   1509     REG_CLASS(L, SkRRect);
   1510     REG_CLASS(L, SkShader);
   1511     REG_CLASS(L, SkTypeface);
   1512     REG_CLASS(L, SkMatrix);
   1513 }
   1514 
   1515 extern "C" int luaopen_skia(lua_State* L);
   1516 extern "C" int luaopen_skia(lua_State* L) {
   1517     SkLua::Load(L);
   1518     return 0;
   1519 }
   1520