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 #include "SkCanvas.h"
     10 #include "SkData.h"
     11 #include "SkDocument.h"
     12 #include "SkImage.h"
     13 #include "SkMatrix.h"
     14 #include "SkPaint.h"
     15 #include "SkPath.h"
     16 #include "SkPixelRef.h"
     17 #include "SkRRect.h"
     18 #include "SkString.h"
     19 #include "SkTypeface.h"
     20 
     21 extern "C" {
     22     #include "lua.h"
     23     #include "lualib.h"
     24     #include "lauxlib.h"
     25 }
     26 
     27 // return the metatable name for a given class
     28 template <typename T> const char* get_mtname();
     29 #define DEF_MTNAME(T)                           \
     30     template <> const char* get_mtname<T>() {   \
     31         return #T "_LuaMetaTableName";          \
     32     }
     33 
     34 DEF_MTNAME(SkCanvas)
     35 DEF_MTNAME(SkDocument)
     36 DEF_MTNAME(SkImage)
     37 DEF_MTNAME(SkMatrix)
     38 DEF_MTNAME(SkRRect)
     39 DEF_MTNAME(SkPath)
     40 DEF_MTNAME(SkPaint)
     41 DEF_MTNAME(SkShader)
     42 DEF_MTNAME(SkTypeface)
     43 
     44 template <typename T> T* push_new(lua_State* L) {
     45     T* addr = (T*)lua_newuserdata(L, sizeof(T));
     46     new (addr) T;
     47     luaL_getmetatable(L, get_mtname<T>());
     48     lua_setmetatable(L, -2);
     49     return addr;
     50 }
     51 
     52 template <typename T> void push_obj(lua_State* L, const T& obj) {
     53     new (lua_newuserdata(L, sizeof(T))) T(obj);
     54     luaL_getmetatable(L, get_mtname<T>());
     55     lua_setmetatable(L, -2);
     56 }
     57 
     58 template <typename T> void push_ref(lua_State* L, T* ref) {
     59     *(T**)lua_newuserdata(L, sizeof(T*)) = SkRef(ref);
     60     luaL_getmetatable(L, get_mtname<T>());
     61     lua_setmetatable(L, -2);
     62 }
     63 
     64 template <typename T> T* get_ref(lua_State* L, int index) {
     65     return *(T**)luaL_checkudata(L, index, get_mtname<T>());
     66 }
     67 
     68 template <typename T> T* get_obj(lua_State* L, int index) {
     69     return (T*)luaL_checkudata(L, index, get_mtname<T>());
     70 }
     71 
     72 static bool lua2bool(lua_State* L, int index) {
     73     return !!lua_toboolean(L, index);
     74 }
     75 
     76 ///////////////////////////////////////////////////////////////////////////////
     77 
     78 SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) {
     79     fL = luaL_newstate();
     80     luaL_openlibs(fL);
     81     SkLua::Load(fL);
     82 }
     83 
     84 SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {}
     85 
     86 SkLua::~SkLua() {
     87     if (fWeOwnL) {
     88         if (fTermCode.size() > 0) {
     89             lua_getglobal(fL, fTermCode.c_str());
     90             if (lua_pcall(fL, 0, 0, 0) != LUA_OK) {
     91                 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
     92             }
     93         }
     94         lua_close(fL);
     95     }
     96 }
     97 
     98 bool SkLua::runCode(const char code[]) {
     99     int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0);
    100     if (err) {
    101         SkDebugf("--- lua failed: %s\n", lua_tostring(fL, -1));
    102         return false;
    103     }
    104     return true;
    105 }
    106 
    107 bool SkLua::runCode(const void* code, size_t size) {
    108     SkString str((const char*)code, size);
    109     return this->runCode(str.c_str());
    110 }
    111 
    112 ///////////////////////////////////////////////////////////////////////////////
    113 
    114 #define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0)
    115 
    116 static void setfield_bool_if(lua_State* L, const char key[], bool pred) {
    117     if (pred) {
    118         lua_pushboolean(L, true);
    119         lua_setfield(L, -2, key);
    120     }
    121 }
    122 
    123 static void setfield_string(lua_State* L, const char key[], const char value[]) {
    124     lua_pushstring(L, value);
    125     lua_setfield(L, -2, key);
    126 }
    127 
    128 static void setfield_number(lua_State* L, const char key[], double value) {
    129     lua_pushnumber(L, value);
    130     lua_setfield(L, -2, key);
    131 }
    132 
    133 static void setfield_boolean(lua_State* L, const char key[], bool value) {
    134     lua_pushboolean(L, value);
    135     lua_setfield(L, -2, key);
    136 }
    137 
    138 static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
    139     setfield_number(L, key, SkScalarToLua(value));
    140 }
    141 
    142 static void setfield_function(lua_State* L,
    143                               const char key[], lua_CFunction value) {
    144     lua_pushcfunction(L, value);
    145     lua_setfield(L, -2, key);
    146 }
    147 
    148 static void setarray_number(lua_State* L, int index, double value) {
    149     lua_pushnumber(L, value);
    150     lua_rawseti(L, -2, index);
    151 }
    152 
    153 void SkLua::pushBool(bool value, const char key[]) {
    154     lua_pushboolean(fL, value);
    155     CHECK_SETFIELD(key);
    156 }
    157 
    158 void SkLua::pushString(const char str[], const char key[]) {
    159     lua_pushstring(fL, str);
    160     CHECK_SETFIELD(key);
    161 }
    162 
    163 void SkLua::pushString(const char str[], size_t length, const char key[]) {
    164     // TODO: how to do this w/o making a copy?
    165     SkString s(str, length);
    166     lua_pushstring(fL, s.c_str());
    167     CHECK_SETFIELD(key);
    168 }
    169 
    170 void SkLua::pushString(const SkString& str, const char key[]) {
    171     lua_pushstring(fL, str.c_str());
    172     CHECK_SETFIELD(key);
    173 }
    174 
    175 void SkLua::pushColor(SkColor color, const char key[]) {
    176     lua_newtable(fL);
    177     setfield_number(fL, "a", SkColorGetA(color) / 255.0);
    178     setfield_number(fL, "r", SkColorGetR(color) / 255.0);
    179     setfield_number(fL, "g", SkColorGetG(color) / 255.0);
    180     setfield_number(fL, "b", SkColorGetB(color) / 255.0);
    181     CHECK_SETFIELD(key);
    182 }
    183 
    184 void SkLua::pushU32(uint32_t value, const char key[]) {
    185     lua_pushnumber(fL, (double)value);
    186     CHECK_SETFIELD(key);
    187 }
    188 
    189 void SkLua::pushScalar(SkScalar value, const char key[]) {
    190     lua_pushnumber(fL, SkScalarToLua(value));
    191     CHECK_SETFIELD(key);
    192 }
    193 
    194 void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
    195     lua_newtable(fL);
    196     for (int i = 0; i < count; ++i) {
    197         // make it base-1 to match lua convention
    198         setarray_number(fL, i + 1, (double)array[i]);
    199     }
    200     CHECK_SETFIELD(key);
    201 }
    202 
    203 void SkLua::pushRect(const SkRect& r, const char key[]) {
    204     lua_newtable(fL);
    205     setfield_scalar(fL, "left", r.fLeft);
    206     setfield_scalar(fL, "top", r.fTop);
    207     setfield_scalar(fL, "right", r.fRight);
    208     setfield_scalar(fL, "bottom", r.fBottom);
    209     CHECK_SETFIELD(key);
    210 }
    211 
    212 void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
    213     push_obj(fL, rr);
    214     CHECK_SETFIELD(key);
    215 }
    216 
    217 void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
    218     push_obj(fL, matrix);
    219     CHECK_SETFIELD(key);
    220 }
    221 
    222 void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
    223     push_obj(fL, paint);
    224     CHECK_SETFIELD(key);
    225 }
    226 
    227 void SkLua::pushPath(const SkPath& path, const char key[]) {
    228     push_obj(fL, path);
    229     CHECK_SETFIELD(key);
    230 }
    231 
    232 void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
    233     push_ref(fL, canvas);
    234     CHECK_SETFIELD(key);
    235 }
    236 
    237 ///////////////////////////////////////////////////////////////////////////////
    238 ///////////////////////////////////////////////////////////////////////////////
    239 
    240 static SkScalar lua2scalar(lua_State* L, int index) {
    241     SkASSERT(lua_isnumber(L, index));
    242     return SkLuaToScalar(lua_tonumber(L, index));
    243 }
    244 
    245 static SkScalar lua2scalar_def(lua_State* L, int index, SkScalar defaultValue) {
    246     if (lua_isnumber(L, index)) {
    247         return SkLuaToScalar(lua_tonumber(L, index));
    248     } else {
    249         return defaultValue;
    250     }
    251 }
    252 
    253 static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
    254     SkASSERT(lua_istable(L, index));
    255     lua_pushstring(L, key);
    256     lua_gettable(L, index);
    257 
    258     SkScalar value = lua2scalar(L, -1);
    259     lua_pop(L, 1);
    260     return value;
    261 }
    262 
    263 static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
    264     SkASSERT(lua_istable(L, index));
    265     lua_pushstring(L, key);
    266     lua_gettable(L, index);
    267 
    268     SkScalar value;
    269     if (lua_isnil(L, -1)) {
    270         value = def;
    271     } else {
    272         value = lua2scalar(L, -1);
    273     }
    274     lua_pop(L, 1);
    275     return value;
    276 }
    277 
    278 static U8CPU unit2byte(SkScalar x) {
    279     if (x <= 0) {
    280         return 0;
    281     } else if (x >= 1) {
    282         return 255;
    283     } else {
    284         return SkScalarRoundToInt(x * 255);
    285     }
    286 }
    287 
    288 static SkColor lua2color(lua_State* L, int index) {
    289     return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
    290                           unit2byte(getfield_scalar(L, index, "r")),
    291                           unit2byte(getfield_scalar(L, index, "g")),
    292                           unit2byte(getfield_scalar(L, index, "b")));
    293 }
    294 
    295 static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
    296     rect->set(getfield_scalar_default(L, index, "left", 0),
    297               getfield_scalar_default(L, index, "top", 0),
    298               getfield_scalar(L, index, "right"),
    299               getfield_scalar(L, index, "bottom"));
    300     return rect;
    301 }
    302 
    303 static int lcanvas_drawColor(lua_State* L) {
    304     get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
    305     return 0;
    306 }
    307 
    308 static int lcanvas_drawRect(lua_State* L) {
    309     SkRect rect;
    310     get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
    311                                       *get_obj<SkPaint>(L, 3));
    312     return 0;
    313 }
    314 
    315 static int lcanvas_drawOval(lua_State* L) {
    316     SkRect rect;
    317     get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
    318                                       *get_obj<SkPaint>(L, 3));
    319     return 0;
    320 }
    321 
    322 static int lcanvas_drawCircle(lua_State* L) {
    323     get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
    324                                         lua2scalar(L, 3),
    325                                         lua2scalar(L, 4),
    326                                         *get_obj<SkPaint>(L, 5));
    327     return 0;
    328 }
    329 
    330 static int lcanvas_drawImage(lua_State* L) {
    331     SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
    332     SkImage* image = get_ref<SkImage>(L, 2);
    333     if (NULL == image) {
    334         return 0;
    335     }
    336     SkScalar x = lua2scalar(L, 3);
    337     SkScalar y = lua2scalar(L, 4);
    338 
    339     SkPaint paint;
    340     const SkPaint* paintPtr = NULL;
    341     if (lua_isnumber(L, 5)) {
    342         paint.setAlpha(SkScalarRoundToInt(lua2scalar(L, 5) * 255));
    343         paintPtr = &paint;
    344     }
    345     image->draw(canvas, x, y, paintPtr);
    346     return 0;
    347 }
    348 
    349 static int lcanvas_drawPath(lua_State* L) {
    350     get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
    351                                       *get_obj<SkPaint>(L, 3));
    352     return 0;
    353 }
    354 
    355 static int lcanvas_drawText(lua_State* L) {
    356     if (lua_gettop(L) < 5) {
    357         return 0;
    358     }
    359 
    360     if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
    361         size_t len;
    362         const char* text = lua_tolstring(L, 2, &len);
    363         get_ref<SkCanvas>(L, 1)->drawText(text, len,
    364                                           lua2scalar(L, 3), lua2scalar(L, 4),
    365                                           *get_obj<SkPaint>(L, 5));
    366     }
    367     return 0;
    368 }
    369 
    370 static int lcanvas_getSaveCount(lua_State* L) {
    371     lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
    372     return 1;
    373 }
    374 
    375 static int lcanvas_getTotalMatrix(lua_State* L) {
    376     SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
    377     return 1;
    378 }
    379 
    380 static int lcanvas_save(lua_State* L) {
    381     lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
    382     return 1;
    383 }
    384 
    385 static int lcanvas_restore(lua_State* L) {
    386     get_ref<SkCanvas>(L, 1)->restore();
    387     return 0;
    388 }
    389 
    390 static int lcanvas_scale(lua_State* L) {
    391     SkScalar sx = lua2scalar_def(L, 2, 1);
    392     SkScalar sy = lua2scalar_def(L, 3, sx);
    393     get_ref<SkCanvas>(L, 1)->scale(sx, sy);
    394     return 0;
    395 }
    396 
    397 static int lcanvas_translate(lua_State* L) {
    398     SkScalar tx = lua2scalar_def(L, 2, 0);
    399     SkScalar ty = lua2scalar_def(L, 3, 0);
    400     get_ref<SkCanvas>(L, 1)->translate(tx, ty);
    401     return 0;
    402 }
    403 
    404 static int lcanvas_rotate(lua_State* L) {
    405     SkScalar degrees = lua2scalar_def(L, 2, 0);
    406     get_ref<SkCanvas>(L, 1)->rotate(degrees);
    407     return 0;
    408 }
    409 
    410 static int lcanvas_gc(lua_State* L) {
    411     get_ref<SkCanvas>(L, 1)->unref();
    412     return 0;
    413 }
    414 
    415 static const struct luaL_Reg gSkCanvas_Methods[] = {
    416     { "drawColor", lcanvas_drawColor },
    417     { "drawRect", lcanvas_drawRect },
    418     { "drawOval", lcanvas_drawOval },
    419     { "drawCircle", lcanvas_drawCircle },
    420     { "drawImage", lcanvas_drawImage },
    421     { "drawPath", lcanvas_drawPath },
    422     { "drawText", lcanvas_drawText },
    423     { "getSaveCount", lcanvas_getSaveCount },
    424     { "getTotalMatrix", lcanvas_getTotalMatrix },
    425     { "save", lcanvas_save },
    426     { "restore", lcanvas_restore },
    427     { "scale", lcanvas_scale },
    428     { "translate", lcanvas_translate },
    429     { "rotate", lcanvas_rotate },
    430     { "__gc", lcanvas_gc },
    431     { NULL, NULL }
    432 };
    433 
    434 ///////////////////////////////////////////////////////////////////////////////
    435 
    436 static int ldocument_beginPage(lua_State* L) {
    437     const SkRect* contentPtr = NULL;
    438     push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
    439                                                      lua2scalar(L, 3),
    440                                                      contentPtr));
    441     return 1;
    442 }
    443 
    444 static int ldocument_endPage(lua_State* L) {
    445     get_ref<SkDocument>(L, 1)->endPage();
    446     return 0;
    447 }
    448 
    449 static int ldocument_close(lua_State* L) {
    450     get_ref<SkDocument>(L, 1)->close();
    451     return 0;
    452 }
    453 
    454 static int ldocument_gc(lua_State* L) {
    455     get_ref<SkDocument>(L, 1)->unref();
    456     return 0;
    457 }
    458 
    459 static const struct luaL_Reg gSkDocument_Methods[] = {
    460     { "beginPage", ldocument_beginPage },
    461     { "endPage", ldocument_endPage },
    462     { "close", ldocument_close },
    463     { "__gc", ldocument_gc },
    464     { NULL, NULL }
    465 };
    466 
    467 ///////////////////////////////////////////////////////////////////////////////
    468 
    469 static int lpaint_isAntiAlias(lua_State* L) {
    470     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
    471     return 1;
    472 }
    473 
    474 static int lpaint_setAntiAlias(lua_State* L) {
    475     get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
    476     return 0;
    477 }
    478 
    479 static int lpaint_getColor(lua_State* L) {
    480     SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
    481     return 1;
    482 }
    483 
    484 static int lpaint_setColor(lua_State* L) {
    485     get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
    486     return 0;
    487 }
    488 
    489 static int lpaint_getTextSize(lua_State* L) {
    490     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
    491     return 1;
    492 }
    493 
    494 static int lpaint_setTextSize(lua_State* L) {
    495     get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
    496     return 0;
    497 }
    498 
    499 static int lpaint_getTypeface(lua_State* L) {
    500     push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
    501     return 1;
    502 }
    503 
    504 static int lpaint_setTypeface(lua_State* L) {
    505     get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
    506     return 0;
    507 }
    508 
    509 static int lpaint_getFontID(lua_State* L) {
    510     SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
    511     SkLua(L).pushU32(SkTypeface::UniqueID(face));
    512     return 1;
    513 }
    514 
    515 static const struct {
    516     const char*     fLabel;
    517     SkPaint::Align  fAlign;
    518 } gAlignRec[] = {
    519     { "left",   SkPaint::kLeft_Align },
    520     { "center", SkPaint::kCenter_Align },
    521     { "right",  SkPaint::kRight_Align },
    522 };
    523 
    524 static int lpaint_getTextAlign(lua_State* L) {
    525     SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
    526     for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
    527         if (gAlignRec[i].fAlign == align) {
    528             lua_pushstring(L, gAlignRec[i].fLabel);
    529             return 1;
    530         }
    531     }
    532     return 0;
    533 }
    534 
    535 static int lpaint_setTextAlign(lua_State* L) {
    536     if (lua_isstring(L, 2)) {
    537         size_t len;
    538         const char* label = lua_tolstring(L, 2, &len);
    539 
    540         for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
    541             if (!strcmp(gAlignRec[i].fLabel, label)) {
    542                 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
    543                 break;
    544             }
    545         }
    546     }
    547     return 0;
    548 }
    549 
    550 static int lpaint_getStroke(lua_State* L) {
    551     lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
    552     return 1;
    553 }
    554 
    555 static int lpaint_setStroke(lua_State* L) {
    556     SkPaint::Style style;
    557 
    558     if (lua_toboolean(L, 2)) {
    559         style = SkPaint::kStroke_Style;
    560     } else {
    561         style = SkPaint::kFill_Style;
    562     }
    563     get_obj<SkPaint>(L, 1)->setStyle(style);
    564     return 0;
    565 }
    566 
    567 static int lpaint_getStrokeWidth(lua_State* L) {
    568     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
    569     return 1;
    570 }
    571 
    572 static int lpaint_setStrokeWidth(lua_State* L) {
    573     get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
    574     return 0;
    575 }
    576 
    577 static int lpaint_measureText(lua_State* L) {
    578     if (lua_isstring(L, 2)) {
    579         size_t len;
    580         const char* text = lua_tolstring(L, 2, &len);
    581         SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
    582         return 1;
    583     }
    584     return 0;
    585 }
    586 
    587 struct FontMetrics {
    588     SkScalar    fTop;       //!< The greatest distance above the baseline for any glyph (will be <= 0)
    589     SkScalar    fAscent;    //!< The recommended distance above the baseline (will be <= 0)
    590     SkScalar    fDescent;   //!< The recommended distance below the baseline (will be >= 0)
    591     SkScalar    fBottom;    //!< The greatest distance below the baseline for any glyph (will be >= 0)
    592     SkScalar    fLeading;   //!< The recommended distance to add between lines of text (will be >= 0)
    593     SkScalar    fAvgCharWidth;  //!< the average charactor width (>= 0)
    594     SkScalar    fXMin;      //!< The minimum bounding box x value for all glyphs
    595     SkScalar    fXMax;      //!< The maximum bounding box x value for all glyphs
    596     SkScalar    fXHeight;   //!< the height of an 'x' in px, or 0 if no 'x' in face
    597 };
    598 
    599 static int lpaint_getFontMetrics(lua_State* L) {
    600     SkPaint::FontMetrics fm;
    601     SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
    602 
    603     lua_newtable(L);
    604     setfield_scalar(L, "top", fm.fTop);
    605     setfield_scalar(L, "ascent", fm.fAscent);
    606     setfield_scalar(L, "descent", fm.fDescent);
    607     setfield_scalar(L, "bottom", fm.fBottom);
    608     setfield_scalar(L, "leading", fm.fLeading);
    609     SkLua(L).pushScalar(height);
    610     return 2;
    611 }
    612 
    613 static int lpaint_getEffects(lua_State* L) {
    614     const SkPaint* paint = get_obj<SkPaint>(L, 1);
    615 
    616     lua_newtable(L);
    617     setfield_bool_if(L, "looper", !!paint->getLooper());
    618     setfield_bool_if(L, "pathEffect", !!paint->getPathEffect());
    619     setfield_bool_if(L, "rasterizer", !!paint->getRasterizer());
    620     setfield_bool_if(L, "maskFilter", !!paint->getMaskFilter());
    621     setfield_bool_if(L, "shader", !!paint->getShader());
    622     setfield_bool_if(L, "colorFilter", !!paint->getColorFilter());
    623     setfield_bool_if(L, "imageFilter", !!paint->getImageFilter());
    624     setfield_bool_if(L, "xfermode", !!paint->getXfermode());
    625     return 1;
    626 }
    627 
    628 static int lpaint_getShader(lua_State* L) {
    629     const SkPaint* paint = get_obj<SkPaint>(L, 1);
    630     SkShader* shader = paint->getShader();
    631     if (shader) {
    632         push_ref(L, shader);
    633         return 1;
    634     }
    635     return 0;
    636 }
    637 
    638 static int lpaint_gc(lua_State* L) {
    639     get_obj<SkPaint>(L, 1)->~SkPaint();
    640     return 0;
    641 }
    642 
    643 static const struct luaL_Reg gSkPaint_Methods[] = {
    644     { "isAntiAlias", lpaint_isAntiAlias },
    645     { "setAntiAlias", lpaint_setAntiAlias },
    646     { "getColor", lpaint_getColor },
    647     { "setColor", lpaint_setColor },
    648     { "getTextSize", lpaint_getTextSize },
    649     { "setTextSize", lpaint_setTextSize },
    650     { "getTypeface", lpaint_getTypeface },
    651     { "setTypeface", lpaint_setTypeface },
    652     { "getFontID", lpaint_getFontID },
    653     { "getTextAlign", lpaint_getTextAlign },
    654     { "setTextAlign", lpaint_setTextAlign },
    655     { "getStroke", lpaint_getStroke },
    656     { "setStroke", lpaint_setStroke },
    657     { "getStrokeWidth", lpaint_getStrokeWidth },
    658     { "setStrokeWidth", lpaint_setStrokeWidth },
    659     { "measureText", lpaint_measureText },
    660     { "getFontMetrics", lpaint_getFontMetrics },
    661     { "getEffects", lpaint_getEffects },
    662     { "getShader", lpaint_getShader },
    663     { "__gc", lpaint_gc },
    664     { NULL, NULL }
    665 };
    666 
    667 ///////////////////////////////////////////////////////////////////////////////
    668 
    669 static const char* mode2string(SkShader::TileMode mode) {
    670     static const char* gNames[] = { "clamp", "repeat", "mirror" };
    671     SkASSERT((unsigned)mode < SK_ARRAY_COUNT(gNames));
    672     return gNames[mode];
    673 }
    674 
    675 static const char* gradtype2string(SkShader::GradientType t) {
    676     static const char* gNames[] = {
    677         "none", "color", "linear", "radial", "radial2", "sweep", "conical"
    678     };
    679     SkASSERT((unsigned)t < SK_ARRAY_COUNT(gNames));
    680     return gNames[t];
    681 }
    682 
    683 static int lshader_isOpaque(lua_State* L) {
    684     SkShader* shader = get_ref<SkShader>(L, 1);
    685     return shader && shader->isOpaque();
    686 }
    687 
    688 static int lshader_asABitmap(lua_State* L) {
    689     SkShader* shader = get_ref<SkShader>(L, 1);
    690     if (shader) {
    691         SkBitmap bm;
    692         SkMatrix matrix;
    693         SkShader::TileMode modes[2];
    694         switch (shader->asABitmap(&bm, &matrix, modes)) {
    695             case SkShader::kDefault_BitmapType:
    696                 lua_newtable(L);
    697                 setfield_number(L, "genID", bm.pixelRef() ? bm.pixelRef()->getGenerationID() : 0);
    698                 setfield_number(L, "width", bm.width());
    699                 setfield_number(L, "height", bm.height());
    700                 setfield_string(L, "tileX", mode2string(modes[0]));
    701                 setfield_string(L, "tileY", mode2string(modes[1]));
    702                 return 1;
    703             default:
    704                 break;
    705         }
    706     }
    707     return 0;
    708 }
    709 
    710 static int lshader_asAGradient(lua_State* L) {
    711     SkShader* shader = get_ref<SkShader>(L, 1);
    712     if (shader) {
    713         SkShader::GradientInfo info;
    714         sk_bzero(&info, sizeof(info));
    715 
    716         SkColor colors[3];  // hacked in for extracting info on 3 color case.
    717         SkScalar pos[3];
    718 
    719         info.fColorCount = 3;
    720         info.fColors = &colors[0];
    721         info.fColorOffsets = &pos[0];
    722 
    723         SkShader::GradientType t = shader->asAGradient(&info);
    724 
    725         if (SkShader::kNone_GradientType != t) {
    726             lua_newtable(L);
    727             setfield_string(L, "type", gradtype2string(t));
    728             setfield_number(L, "colorCount", info.fColorCount);
    729             setfield_string(L, "tile", mode2string(info.fTileMode));
    730 
    731             if (info.fColorCount == 3){
    732                 setfield_number(L, "midPos", pos[1]);
    733             }
    734 
    735             return 1;
    736         }
    737     }
    738     return 0;
    739 }
    740 
    741 static int lshader_gc(lua_State* L) {
    742     get_ref<SkShader>(L, 1)->unref();
    743     return 0;
    744 }
    745 
    746 static const struct luaL_Reg gSkShader_Methods[] = {
    747     { "isOpaque",       lshader_isOpaque },
    748     { "asABitmap",      lshader_asABitmap },
    749     { "asAGradient",    lshader_asAGradient },
    750     { "__gc",           lshader_gc },
    751     { NULL, NULL }
    752 };
    753 
    754 ///////////////////////////////////////////////////////////////////////////////
    755 
    756 static int lmatrix_getType(lua_State* L) {
    757     SkMatrix::TypeMask mask = get_obj<SkMatrix>(L, 1)->getType();
    758 
    759     lua_newtable(L);
    760     setfield_boolean(L, "translate",   SkToBool(mask & SkMatrix::kTranslate_Mask));
    761     setfield_boolean(L, "scale",       SkToBool(mask & SkMatrix::kScale_Mask));
    762     setfield_boolean(L, "affine",      SkToBool(mask & SkMatrix::kAffine_Mask));
    763     setfield_boolean(L, "perspective", SkToBool(mask & SkMatrix::kPerspective_Mask));
    764     return 1;
    765 }
    766 
    767 static int lmatrix_getScaleX(lua_State* L) {
    768     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleX());
    769     return 1;
    770 }
    771 
    772 static int lmatrix_getScaleY(lua_State* L) {
    773     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleY());
    774     return 1;
    775 }
    776 
    777 static int lmatrix_getTranslateX(lua_State* L) {
    778     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateX());
    779     return 1;
    780 }
    781 
    782 static int lmatrix_getTranslateY(lua_State* L) {
    783     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateY());
    784     return 1;
    785 }
    786 
    787 static const struct luaL_Reg gSkMatrix_Methods[] = {
    788     { "getType", lmatrix_getType },
    789     { "getScaleX", lmatrix_getScaleX },
    790     { "getScaleY", lmatrix_getScaleY },
    791     { "getTranslateX", lmatrix_getTranslateX },
    792     { "getTranslateY", lmatrix_getTranslateY },
    793     { NULL, NULL }
    794 };
    795 
    796 ///////////////////////////////////////////////////////////////////////////////
    797 
    798 static int lpath_getBounds(lua_State* L) {
    799     SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
    800     return 1;
    801 }
    802 
    803 static int lpath_isEmpty(lua_State* L) {
    804     lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
    805     return 1;
    806 }
    807 
    808 static int lpath_isRect(lua_State* L) {
    809     SkRect r;
    810     bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
    811     int ret_count = 1;
    812     lua_pushboolean(L, pred);
    813     if (pred) {
    814         SkLua(L).pushRect(r);
    815         ret_count += 1;
    816     }
    817     return ret_count;
    818 }
    819 
    820 static const char* dir2string(SkPath::Direction dir) {
    821     static const char* gStr[] = {
    822         "unknown", "cw", "ccw"
    823     };
    824     SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
    825     return gStr[dir];
    826 }
    827 
    828 static int lpath_isNestedRects(lua_State* L) {
    829     SkRect rects[2];
    830     SkPath::Direction dirs[2];
    831     bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
    832     int ret_count = 1;
    833     lua_pushboolean(L, pred);
    834     if (pred) {
    835         SkLua lua(L);
    836         lua.pushRect(rects[0]);
    837         lua.pushRect(rects[1]);
    838         lua_pushstring(L, dir2string(dirs[0]));
    839         lua_pushstring(L, dir2string(dirs[0]));
    840         ret_count += 4;
    841     }
    842     return ret_count;
    843 }
    844 
    845 static int lpath_reset(lua_State* L) {
    846     get_obj<SkPath>(L, 1)->reset();
    847     return 0;
    848 }
    849 
    850 static int lpath_moveTo(lua_State* L) {
    851     get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
    852     return 0;
    853 }
    854 
    855 static int lpath_lineTo(lua_State* L) {
    856     get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
    857     return 0;
    858 }
    859 
    860 static int lpath_quadTo(lua_State* L) {
    861     get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
    862                                   lua2scalar(L, 4), lua2scalar(L, 5));
    863     return 0;
    864 }
    865 
    866 static int lpath_cubicTo(lua_State* L) {
    867     get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
    868                                    lua2scalar(L, 4), lua2scalar(L, 5),
    869                                    lua2scalar(L, 6), lua2scalar(L, 7));
    870     return 0;
    871 }
    872 
    873 static int lpath_close(lua_State* L) {
    874     get_obj<SkPath>(L, 1)->close();
    875     return 0;
    876 }
    877 
    878 static int lpath_gc(lua_State* L) {
    879     get_obj<SkPath>(L, 1)->~SkPath();
    880     return 0;
    881 }
    882 
    883 static const struct luaL_Reg gSkPath_Methods[] = {
    884     { "getBounds", lpath_getBounds },
    885     { "isEmpty", lpath_isEmpty },
    886     { "isRect", lpath_isRect },
    887     { "isNestedRects", lpath_isNestedRects },
    888     { "reset", lpath_reset },
    889     { "moveTo", lpath_moveTo },
    890     { "lineTo", lpath_lineTo },
    891     { "quadTo", lpath_quadTo },
    892     { "cubicTo", lpath_cubicTo },
    893     { "close", lpath_close },
    894     { "__gc", lpath_gc },
    895     { NULL, NULL }
    896 };
    897 
    898 ///////////////////////////////////////////////////////////////////////////////
    899 
    900 static const char* rrect_type(const SkRRect& rr) {
    901     switch (rr.getType()) {
    902         case SkRRect::kUnknown_Type: return "unknown";
    903         case SkRRect::kEmpty_Type: return "empty";
    904         case SkRRect::kRect_Type: return "rect";
    905         case SkRRect::kOval_Type: return "oval";
    906         case SkRRect::kSimple_Type: return "simple";
    907         case SkRRect::kComplex_Type: return "complex";
    908     }
    909     SkASSERT(!"never get here");
    910     return "";
    911 }
    912 
    913 static int lrrect_rect(lua_State* L) {
    914     SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
    915     return 1;
    916 }
    917 
    918 static int lrrect_type(lua_State* L) {
    919     lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
    920     return 1;
    921 }
    922 
    923 static int lrrect_radii(lua_State* L) {
    924     int corner = lua_tointeger(L, 2);
    925     SkVector v;
    926     if (corner < 0 || corner > 3) {
    927         SkDebugf("bad corner index %d", corner);
    928         v.set(0, 0);
    929     } else {
    930         v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
    931     }
    932     lua_pushnumber(L, v.fX);
    933     lua_pushnumber(L, v.fY);
    934     return 2;
    935 }
    936 
    937 static int lrrect_gc(lua_State* L) {
    938     get_obj<SkRRect>(L, 1)->~SkRRect();
    939     return 0;
    940 }
    941 
    942 static const struct luaL_Reg gSkRRect_Methods[] = {
    943     { "rect", lrrect_rect },
    944     { "type", lrrect_type },
    945     { "radii", lrrect_radii },
    946     { "__gc", lrrect_gc },
    947     { NULL, NULL }
    948 };
    949 
    950 ///////////////////////////////////////////////////////////////////////////////
    951 
    952 static int limage_width(lua_State* L) {
    953     lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
    954     return 1;
    955 }
    956 
    957 static int limage_height(lua_State* L) {
    958     lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
    959     return 1;
    960 }
    961 
    962 static int limage_gc(lua_State* L) {
    963     get_ref<SkImage>(L, 1)->unref();
    964     return 0;
    965 }
    966 
    967 static const struct luaL_Reg gSkImage_Methods[] = {
    968     { "width", limage_width },
    969     { "height", limage_height },
    970     { "__gc", limage_gc },
    971     { NULL, NULL }
    972 };
    973 
    974 ///////////////////////////////////////////////////////////////////////////////
    975 
    976 static int ltypeface_gc(lua_State* L) {
    977     get_ref<SkTypeface>(L, 1)->unref();
    978     return 0;
    979 }
    980 
    981 static const struct luaL_Reg gSkTypeface_Methods[] = {
    982     { "__gc", ltypeface_gc },
    983     { NULL, NULL }
    984 };
    985 
    986 ///////////////////////////////////////////////////////////////////////////////
    987 
    988 class AutoCallLua {
    989 public:
    990     AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
    991         lua_getglobal(L, func);
    992         if (!lua_isfunction(L, -1)) {
    993             int t = lua_type(L, -1);
    994             SkDebugf("--- expected function %d\n", t);
    995         }
    996 
    997         lua_newtable(L);
    998         setfield_string(L, "verb", verb);
    999     }
   1000 
   1001     ~AutoCallLua() {
   1002         if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
   1003             SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
   1004         }
   1005         lua_settop(fL, -1);
   1006     }
   1007 
   1008 private:
   1009     lua_State* fL;
   1010 };
   1011 
   1012 #define AUTO_LUA(verb)  AutoCallLua acl(fL, fFunc.c_str(), verb)
   1013 
   1014 ///////////////////////////////////////////////////////////////////////////////
   1015 
   1016 static int lsk_newDocumentPDF(lua_State* L) {
   1017     const char* file = NULL;
   1018     if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
   1019         file = lua_tolstring(L, 1, NULL);
   1020     }
   1021 
   1022     SkDocument* doc = SkDocument::CreatePDF(file);
   1023     if (NULL == doc) {
   1024         // do I need to push a nil on the stack and return 1?
   1025         return 0;
   1026     } else {
   1027         push_ref(L, doc);
   1028         doc->unref();
   1029         return 1;
   1030     }
   1031 }
   1032 
   1033 static int lsk_newPaint(lua_State* L) {
   1034     push_new<SkPaint>(L);
   1035     return 1;
   1036 }
   1037 
   1038 static int lsk_newPath(lua_State* L) {
   1039     push_new<SkPath>(L);
   1040     return 1;
   1041 }
   1042 
   1043 static int lsk_newRRect(lua_State* L) {
   1044     SkRRect* rr = push_new<SkRRect>(L);
   1045     rr->setEmpty();
   1046     return 1;
   1047 }
   1048 
   1049 static int lsk_newTypeface(lua_State* L) {
   1050     const char* name = NULL;
   1051     int style = SkTypeface::kNormal;
   1052 
   1053     int count = lua_gettop(L);
   1054     if (count > 0 && lua_isstring(L, 1)) {
   1055         name = lua_tolstring(L, 1, NULL);
   1056         if (count > 1 && lua_isnumber(L, 2)) {
   1057             style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
   1058         }
   1059     }
   1060 
   1061     SkTypeface* face = SkTypeface::CreateFromName(name,
   1062                                                   (SkTypeface::Style)style);
   1063 //    SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
   1064     if (NULL == face) {
   1065         face = SkTypeface::RefDefault();
   1066     }
   1067     push_ref(L, face);
   1068     face->unref();
   1069     return 1;
   1070 }
   1071 
   1072 static int lsk_loadImage(lua_State* L) {
   1073     if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
   1074         const char* name = lua_tolstring(L, 1, NULL);
   1075         SkAutoDataUnref data(SkData::NewFromFileName(name));
   1076         if (data.get()) {
   1077             SkImage* image = SkImage::NewEncodedData(data.get());
   1078             if (image) {
   1079                 push_ref(L, image);
   1080                 image->unref();
   1081                 return 1;
   1082             }
   1083         }
   1084     }
   1085     return 0;
   1086 }
   1087 
   1088 static void register_Sk(lua_State* L) {
   1089     lua_newtable(L);
   1090     lua_pushvalue(L, -1);
   1091     lua_setglobal(L, "Sk");
   1092     // the Sk table is still on top
   1093 
   1094     setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
   1095     setfield_function(L, "loadImage", lsk_loadImage);
   1096     setfield_function(L, "newPaint", lsk_newPaint);
   1097     setfield_function(L, "newPath", lsk_newPath);
   1098     setfield_function(L, "newRRect", lsk_newRRect);
   1099     setfield_function(L, "newTypeface", lsk_newTypeface);
   1100     lua_pop(L, 1);  // pop off the Sk table
   1101 }
   1102 
   1103 #define REG_CLASS(L, C)                             \
   1104     do {                                            \
   1105         luaL_newmetatable(L, get_mtname<C>());      \
   1106         lua_pushvalue(L, -1);                       \
   1107         lua_setfield(L, -2, "__index");             \
   1108         luaL_setfuncs(L, g##C##_Methods, 0);        \
   1109         lua_pop(L, 1); /* pop off the meta-table */ \
   1110     } while (0)
   1111 
   1112 void SkLua::Load(lua_State* L) {
   1113     register_Sk(L);
   1114     REG_CLASS(L, SkCanvas);
   1115     REG_CLASS(L, SkDocument);
   1116     REG_CLASS(L, SkImage);
   1117     REG_CLASS(L, SkPath);
   1118     REG_CLASS(L, SkPaint);
   1119     REG_CLASS(L, SkRRect);
   1120     REG_CLASS(L, SkShader);
   1121     REG_CLASS(L, SkTypeface);
   1122     REG_CLASS(L, SkMatrix);
   1123 }
   1124 
   1125 extern "C" int luaopen_skia(lua_State* L);
   1126 extern "C" int luaopen_skia(lua_State* L) {
   1127     SkLua::Load(L);
   1128     return 0;
   1129 }
   1130