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
28extern "C" {
29    #include "lua.h"
30    #include "lualib.h"
31    #include "lauxlib.h"
32}
33
34// return the metatable name for a given class
35template <typename T> const char* get_mtname();
36#define DEF_MTNAME(T)                           \
37    template <> const char* get_mtname<T>() {   \
38        return #T "_LuaMetaTableName";          \
39    }
40
41DEF_MTNAME(SkCanvas)
42DEF_MTNAME(SkDocument)
43DEF_MTNAME(SkImage)
44DEF_MTNAME(SkMatrix)
45DEF_MTNAME(SkRRect)
46DEF_MTNAME(SkPath)
47DEF_MTNAME(SkPaint)
48DEF_MTNAME(SkPathEffect)
49DEF_MTNAME(SkShader)
50DEF_MTNAME(SkTextBlob)
51DEF_MTNAME(SkTypeface)
52
53template <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
61template <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
67template <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
73template <typename T> T* get_ref(lua_State* L, int index) {
74    return *(T**)luaL_checkudata(L, index, get_mtname<T>());
75}
76
77template <typename T> T* get_obj(lua_State* L, int index) {
78    return (T*)luaL_checkudata(L, index, get_mtname<T>());
79}
80
81static bool lua2bool(lua_State* L, int index) {
82    return !!lua_toboolean(L, index);
83}
84
85///////////////////////////////////////////////////////////////////////////////
86
87SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) {
88    fL = luaL_newstate();
89    luaL_openlibs(fL);
90    SkLua::Load(fL);
91}
92
93SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {}
94
95SkLua::~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
107bool 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
116bool 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
125static 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
132static 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
137static void setfield_number(lua_State* L, const char key[], double value) {
138    lua_pushnumber(L, value);
139    lua_setfield(L, -2, key);
140}
141
142static void setfield_boolean(lua_State* L, const char key[], bool value) {
143    lua_pushboolean(L, value);
144    lua_setfield(L, -2, key);
145}
146
147static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
148    setfield_number(L, key, SkScalarToLua(value));
149}
150
151static 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
157static void setarray_number(lua_State* L, int index, double value) {
158    lua_pushnumber(L, value);
159    lua_rawseti(L, -2, index);
160}
161
162static void setarray_scalar(lua_State* L, int index, SkScalar value) {
163    setarray_number(L, index, SkScalarToLua(value));
164}
165
166void SkLua::pushBool(bool value, const char key[]) {
167    lua_pushboolean(fL, value);
168    CHECK_SETFIELD(key);
169}
170
171void SkLua::pushString(const char str[], const char key[]) {
172    lua_pushstring(fL, str);
173    CHECK_SETFIELD(key);
174}
175
176void 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
183void SkLua::pushString(const SkString& str, const char key[]) {
184    lua_pushstring(fL, str.c_str());
185    CHECK_SETFIELD(key);
186}
187
188void 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
197void SkLua::pushU32(uint32_t value, const char key[]) {
198    lua_pushnumber(fL, (double)value);
199    CHECK_SETFIELD(key);
200}
201
202void SkLua::pushScalar(SkScalar value, const char key[]) {
203    lua_pushnumber(fL, SkScalarToLua(value));
204    CHECK_SETFIELD(key);
205}
206
207void 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
216void 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
228void 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
237void 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
246void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
247    push_obj(fL, rr);
248    CHECK_SETFIELD(key);
249}
250
251void 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
259void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
260    push_obj(fL, matrix);
261    CHECK_SETFIELD(key);
262}
263
264void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
265    push_obj(fL, paint);
266    CHECK_SETFIELD(key);
267}
268
269void SkLua::pushPath(const SkPath& path, const char key[]) {
270    push_obj(fL, path);
271    CHECK_SETFIELD(key);
272}
273
274void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
275    push_ref(fL, canvas);
276    CHECK_SETFIELD(key);
277}
278
279void SkLua::pushTextBlob(const SkTextBlob* blob, const char key[]) {
280    push_ref(fL, const_cast<SkTextBlob*>(blob));
281    CHECK_SETFIELD(key);
282}
283
284static 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
298static 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
316void 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
328void 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
354static SkScalar lua2scalar(lua_State* L, int index) {
355    SkASSERT(lua_isnumber(L, index));
356    return SkLuaToScalar(lua_tonumber(L, index));
357}
358
359static 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
367static 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
377static 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
392static 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
402static 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
409static 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
417static int lcanvas_drawColor(lua_State* L) {
418    get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
419    return 0;
420}
421
422static 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
429static 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
436static 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
444static 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
463static 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
469static 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
484static int lcanvas_getSaveCount(lua_State* L) {
485    lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
486    return 1;
487}
488
489static int lcanvas_getTotalMatrix(lua_State* L) {
490    SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
491    return 1;
492}
493
494static int lcanvas_getClipStack(lua_State* L) {
495    SkLua(L).pushClipStack(*get_ref<SkCanvas>(L, 1)->getClipStack());
496    return 1;
497}
498
499int 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
538static int lcanvas_save(lua_State* L) {
539    lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
540    return 1;
541}
542
543static int lcanvas_restore(lua_State* L) {
544    get_ref<SkCanvas>(L, 1)->restore();
545    return 0;
546}
547
548static 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
555static 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
562static 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
568static int lcanvas_gc(lua_State* L) {
569    get_ref<SkCanvas>(L, 1)->unref();
570    return 0;
571}
572
573const 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
598static 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
606static int ldocument_endPage(lua_State* L) {
607    get_ref<SkDocument>(L, 1)->endPage();
608    return 0;
609}
610
611static int ldocument_close(lua_State* L) {
612    get_ref<SkDocument>(L, 1)->close();
613    return 0;
614}
615
616static int ldocument_gc(lua_State* L) {
617    get_ref<SkDocument>(L, 1)->unref();
618    return 0;
619}
620
621static 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
631static int lpaint_isAntiAlias(lua_State* L) {
632    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
633    return 1;
634}
635
636static int lpaint_setAntiAlias(lua_State* L) {
637    get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
638    return 0;
639}
640
641static int lpaint_isDither(lua_State* L) {
642    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDither());
643    return 1;
644}
645
646static int lpaint_isUnderlineText(lua_State* L) {
647    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isUnderlineText());
648    return 1;
649}
650
651static int lpaint_isStrikeThruText(lua_State* L) {
652    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isStrikeThruText());
653    return 1;
654}
655
656static int lpaint_isFakeBoldText(lua_State* L) {
657    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isFakeBoldText());
658    return 1;
659}
660
661static int lpaint_isLinearText(lua_State* L) {
662    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLinearText());
663    return 1;
664}
665
666static int lpaint_isSubpixelText(lua_State* L) {
667    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isSubpixelText());
668    return 1;
669}
670
671static int lpaint_isDevKernText(lua_State* L) {
672    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDevKernText());
673    return 1;
674}
675
676static int lpaint_isLCDRenderText(lua_State* L) {
677    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLCDRenderText());
678    return 1;
679}
680
681static int lpaint_isEmbeddedBitmapText(lua_State* L) {
682    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isEmbeddedBitmapText());
683    return 1;
684}
685
686static int lpaint_isAutohinted(lua_State* L) {
687    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAutohinted());
688    return 1;
689}
690
691static int lpaint_isVerticalText(lua_State* L) {
692    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isVerticalText());
693    return 1;
694}
695
696static int lpaint_getColor(lua_State* L) {
697    SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
698    return 1;
699}
700
701static int lpaint_setColor(lua_State* L) {
702    get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
703    return 0;
704}
705
706static int lpaint_getTextSize(lua_State* L) {
707    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
708    return 1;
709}
710
711static int lpaint_getTextScaleX(lua_State* L) {
712    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextScaleX());
713    return 1;
714}
715
716static int lpaint_getTextSkewX(lua_State* L) {
717    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSkewX());
718    return 1;
719}
720
721static int lpaint_setTextSize(lua_State* L) {
722    get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
723    return 0;
724}
725
726static int lpaint_getTypeface(lua_State* L) {
727    push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
728    return 1;
729}
730
731static int lpaint_setTypeface(lua_State* L) {
732    get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
733    return 0;
734}
735
736static int lpaint_getHinting(lua_State* L) {
737    SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getHinting());
738    return 1;
739}
740
741static 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
747static 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
756static 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
767static 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
782static int lpaint_getStroke(lua_State* L) {
783    lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
784    return 1;
785}
786
787static 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
799static int lpaint_getStrokeCap(lua_State* L) {
800    SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeCap());
801    return 1;
802}
803
804static int lpaint_getStrokeJoin(lua_State* L) {
805    SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeJoin());
806    return 1;
807}
808
809static int lpaint_getTextEncoding(lua_State* L) {
810    SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getTextEncoding());
811    return 1;
812}
813
814static int lpaint_getStrokeWidth(lua_State* L) {
815    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
816    return 1;
817}
818
819static int lpaint_setStrokeWidth(lua_State* L) {
820    get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
821    return 0;
822}
823
824static int lpaint_getStrokeMiter(lua_State* L) {
825    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeMiter());
826    return 1;
827}
828
829static 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
839struct 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
851static 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
865static 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
880static 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
890static 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
900static int lpaint_gc(lua_State* L) {
901    get_obj<SkPaint>(L, 1)->~SkPaint();
902    return 0;
903}
904
905static 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
950static 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
956static 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
964static int lshader_isOpaque(lua_State* L) {
965    SkShader* shader = get_ref<SkShader>(L, 1);
966    return shader && shader->isOpaque();
967}
968
969static 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
991static 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
1022static int lshader_gc(lua_State* L) {
1023    get_ref<SkShader>(L, 1)->unref();
1024    return 0;
1025}
1026
1027static 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
1037static 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
1053static int lpatheffect_gc(lua_State* L) {
1054    get_ref<SkPathEffect>(L, 1)->unref();
1055    return 0;
1056}
1057
1058static const struct luaL_Reg gSkPathEffect_Methods[] = {
1059    { "asADash",        lpatheffect_asADash },
1060    { "__gc",           lpatheffect_gc },
1061    { NULL, NULL }
1062};
1063
1064///////////////////////////////////////////////////////////////////////////////
1065
1066static 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
1077static int lmatrix_getScaleX(lua_State* L) {
1078    lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleX());
1079    return 1;
1080}
1081
1082static int lmatrix_getScaleY(lua_State* L) {
1083    lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleY());
1084    return 1;
1085}
1086
1087static int lmatrix_getTranslateX(lua_State* L) {
1088    lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateX());
1089    return 1;
1090}
1091
1092static int lmatrix_getTranslateY(lua_State* L) {
1093    lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateY());
1094    return 1;
1095}
1096
1097static 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
1108static int lpath_getBounds(lua_State* L) {
1109    SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
1110    return 1;
1111}
1112
1113static 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
1127static 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
1133static 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
1168static 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
1174static 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
1180static int lpath_isEmpty(lua_State* L) {
1181    lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
1182    return 1;
1183}
1184
1185static 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
1197static 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
1205static 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
1222static int lpath_countPoints(lua_State* L) {
1223    lua_pushinteger(L, get_obj<SkPath>(L, 1)->countPoints());
1224    return 1;
1225}
1226
1227static int lpath_reset(lua_State* L) {
1228    get_obj<SkPath>(L, 1)->reset();
1229    return 0;
1230}
1231
1232static int lpath_moveTo(lua_State* L) {
1233    get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
1234    return 0;
1235}
1236
1237static int lpath_lineTo(lua_State* L) {
1238    get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
1239    return 0;
1240}
1241
1242static 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
1248static 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
1255static int lpath_close(lua_State* L) {
1256    get_obj<SkPath>(L, 1)->close();
1257    return 0;
1258}
1259
1260static int lpath_gc(lua_State* L) {
1261    get_obj<SkPath>(L, 1)->~SkPath();
1262    return 0;
1263}
1264
1265static 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
1286static 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
1300static int lrrect_rect(lua_State* L) {
1301    SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
1302    return 1;
1303}
1304
1305static int lrrect_type(lua_State* L) {
1306    lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
1307    return 1;
1308}
1309
1310static 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
1324static int lrrect_gc(lua_State* L) {
1325    get_obj<SkRRect>(L, 1)->~SkRRect();
1326    return 0;
1327}
1328
1329static 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
1339static int limage_width(lua_State* L) {
1340    lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
1341    return 1;
1342}
1343
1344static int limage_height(lua_State* L) {
1345    lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
1346    return 1;
1347}
1348
1349static int limage_gc(lua_State* L) {
1350    get_ref<SkImage>(L, 1)->unref();
1351    return 0;
1352}
1353
1354static 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
1363static int ltypeface_gc(lua_State* L) {
1364    SkSafeUnref(get_ref<SkTypeface>(L, 1));
1365    return 0;
1366}
1367
1368static const struct luaL_Reg gSkTypeface_Methods[] = {
1369    { "__gc", ltypeface_gc },
1370    { NULL, NULL }
1371};
1372
1373///////////////////////////////////////////////////////////////////////////////
1374
1375class AutoCallLua {
1376public:
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
1395private:
1396    lua_State* fL;
1397};
1398
1399#define AUTO_LUA(verb)  AutoCallLua acl(fL, fFunc.c_str(), verb)
1400
1401///////////////////////////////////////////////////////////////////////////////
1402
1403static 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
1420static int lsk_newPaint(lua_State* L) {
1421    push_new<SkPaint>(L);
1422    return 1;
1423}
1424
1425static int lsk_newPath(lua_State* L) {
1426    push_new<SkPath>(L);
1427    return 1;
1428}
1429
1430static int lsk_newRRect(lua_State* L) {
1431    SkRRect* rr = push_new<SkRRect>(L);
1432    rr->setEmpty();
1433    return 1;
1434}
1435
1436static 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
1459static 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
1477static 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
1501void 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
1515extern "C" int luaopen_skia(lua_State* L);
1516extern "C" int luaopen_skia(lua_State* L) {
1517    SkLua::Load(L);
1518    return 0;
1519}
1520