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 "SkBlurImageFilter.h"
15#include "SkCanvas.h"
16#include "SkColorFilter.h"
17#include "SkData.h"
18#include "SkDocument.h"
19#include "SkGradientShader.h"
20#include "SkImage.h"
21#include "SkMatrix.h"
22#include "SkPaint.h"
23#include "SkPath.h"
24#include "SkPictureRecorder.h"
25#include "SkPixelRef.h"
26#include "SkRRect.h"
27#include "SkString.h"
28#include "SkSurface.h"
29#include "SkTextBlob.h"
30#include "SkTypeface.h"
31#include "SkXfermode.h"
32
33extern "C" {
34    #include "lua.h"
35    #include "lualib.h"
36    #include "lauxlib.h"
37}
38
39// return the metatable name for a given class
40template <typename T> const char* get_mtname();
41#define DEF_MTNAME(T)                           \
42    template <> const char* get_mtname<T>() {   \
43        return #T "_LuaMetaTableName";          \
44    }
45
46DEF_MTNAME(SkCanvas)
47DEF_MTNAME(SkColorFilter)
48DEF_MTNAME(SkDocument)
49DEF_MTNAME(SkImage)
50DEF_MTNAME(SkImageFilter)
51DEF_MTNAME(SkMatrix)
52DEF_MTNAME(SkRRect)
53DEF_MTNAME(SkPath)
54DEF_MTNAME(SkPaint)
55DEF_MTNAME(SkPathEffect)
56DEF_MTNAME(SkPicture)
57DEF_MTNAME(SkPictureRecorder)
58DEF_MTNAME(SkShader)
59DEF_MTNAME(SkSurface)
60DEF_MTNAME(SkTextBlob)
61DEF_MTNAME(SkTypeface)
62DEF_MTNAME(SkXfermode)
63
64template <typename T> T* push_new(lua_State* L) {
65    T* addr = (T*)lua_newuserdata(L, sizeof(T));
66    new (addr) T;
67    luaL_getmetatable(L, get_mtname<T>());
68    lua_setmetatable(L, -2);
69    return addr;
70}
71
72template <typename T> void push_obj(lua_State* L, const T& obj) {
73    new (lua_newuserdata(L, sizeof(T))) T(obj);
74    luaL_getmetatable(L, get_mtname<T>());
75    lua_setmetatable(L, -2);
76}
77
78template <typename T> T* push_ref(lua_State* L, T* ref) {
79    *(T**)lua_newuserdata(L, sizeof(T*)) = SkSafeRef(ref);
80    luaL_getmetatable(L, get_mtname<T>());
81    lua_setmetatable(L, -2);
82    return ref;
83}
84
85template <typename T> T* get_ref(lua_State* L, int index) {
86    return *(T**)luaL_checkudata(L, index, get_mtname<T>());
87}
88
89template <typename T> T* get_obj(lua_State* L, int index) {
90    return (T*)luaL_checkudata(L, index, get_mtname<T>());
91}
92
93static bool lua2bool(lua_State* L, int index) {
94    return !!lua_toboolean(L, index);
95}
96
97///////////////////////////////////////////////////////////////////////////////
98
99SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) {
100    fL = luaL_newstate();
101    luaL_openlibs(fL);
102    SkLua::Load(fL);
103}
104
105SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {}
106
107SkLua::~SkLua() {
108    if (fWeOwnL) {
109        if (fTermCode.size() > 0) {
110            lua_getglobal(fL, fTermCode.c_str());
111            if (lua_pcall(fL, 0, 0, 0) != LUA_OK) {
112                SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
113            }
114        }
115        lua_close(fL);
116    }
117}
118
119bool SkLua::runCode(const char code[]) {
120    int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0);
121    if (err) {
122        SkDebugf("--- lua failed: %s\n", lua_tostring(fL, -1));
123        return false;
124    }
125    return true;
126}
127
128bool SkLua::runCode(const void* code, size_t size) {
129    SkString str((const char*)code, size);
130    return this->runCode(str.c_str());
131}
132
133///////////////////////////////////////////////////////////////////////////////
134
135#define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0)
136
137static void setfield_bool_if(lua_State* L, const char key[], bool pred) {
138    if (pred) {
139        lua_pushboolean(L, true);
140        lua_setfield(L, -2, key);
141    }
142}
143
144static void setfield_string(lua_State* L, const char key[], const char value[]) {
145    lua_pushstring(L, value);
146    lua_setfield(L, -2, key);
147}
148
149static void setfield_number(lua_State* L, const char key[], double value) {
150    lua_pushnumber(L, value);
151    lua_setfield(L, -2, key);
152}
153
154static void setfield_boolean(lua_State* L, const char key[], bool value) {
155    lua_pushboolean(L, value);
156    lua_setfield(L, -2, key);
157}
158
159static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
160    setfield_number(L, key, SkScalarToLua(value));
161}
162
163static void setfield_function(lua_State* L,
164                              const char key[], lua_CFunction value) {
165    lua_pushcfunction(L, value);
166    lua_setfield(L, -2, key);
167}
168
169static int lua2int_def(lua_State* L, int index, int defaultValue) {
170    if (lua_isnumber(L, index)) {
171        return (int)lua_tonumber(L, index);
172    } else {
173        return defaultValue;
174    }
175}
176
177static SkScalar lua2scalar(lua_State* L, int index) {
178    SkASSERT(lua_isnumber(L, index));
179    return SkLuaToScalar(lua_tonumber(L, index));
180}
181
182static SkScalar lua2scalar_def(lua_State* L, int index, SkScalar defaultValue) {
183    if (lua_isnumber(L, index)) {
184        return SkLuaToScalar(lua_tonumber(L, index));
185    } else {
186        return defaultValue;
187    }
188}
189
190static SkScalar getarray_scalar(lua_State* L, int stackIndex, int arrayIndex) {
191    SkASSERT(lua_istable(L, stackIndex));
192    lua_rawgeti(L, stackIndex, arrayIndex);
193
194    SkScalar value = lua2scalar(L, -1);
195    lua_pop(L, 1);
196    return value;
197}
198
199static void getarray_scalars(lua_State* L, int stackIndex, SkScalar dst[], int count) {
200    for (int i = 0; i < count; ++i) {
201        dst[i] = getarray_scalar(L, stackIndex, i + 1);
202    }
203}
204
205static void getarray_points(lua_State* L, int stackIndex, SkPoint pts[], int count) {
206    getarray_scalars(L, stackIndex, &pts[0].fX, count * 2);
207}
208
209static void setarray_number(lua_State* L, int index, double value) {
210    lua_pushnumber(L, value);
211    lua_rawseti(L, -2, index);
212}
213
214static void setarray_scalar(lua_State* L, int index, SkScalar value) {
215    setarray_number(L, index, SkScalarToLua(value));
216}
217
218void SkLua::pushBool(bool value, const char key[]) {
219    lua_pushboolean(fL, value);
220    CHECK_SETFIELD(key);
221}
222
223void SkLua::pushString(const char str[], const char key[]) {
224    lua_pushstring(fL, str);
225    CHECK_SETFIELD(key);
226}
227
228void SkLua::pushString(const char str[], size_t length, const char key[]) {
229    // TODO: how to do this w/o making a copy?
230    SkString s(str, length);
231    lua_pushstring(fL, s.c_str());
232    CHECK_SETFIELD(key);
233}
234
235void SkLua::pushString(const SkString& str, const char key[]) {
236    lua_pushstring(fL, str.c_str());
237    CHECK_SETFIELD(key);
238}
239
240void SkLua::pushColor(SkColor color, const char key[]) {
241    lua_newtable(fL);
242    setfield_number(fL, "a", SkColorGetA(color) / 255.0);
243    setfield_number(fL, "r", SkColorGetR(color) / 255.0);
244    setfield_number(fL, "g", SkColorGetG(color) / 255.0);
245    setfield_number(fL, "b", SkColorGetB(color) / 255.0);
246    CHECK_SETFIELD(key);
247}
248
249void SkLua::pushU32(uint32_t value, const char key[]) {
250    lua_pushnumber(fL, (double)value);
251    CHECK_SETFIELD(key);
252}
253
254void SkLua::pushScalar(SkScalar value, const char key[]) {
255    lua_pushnumber(fL, SkScalarToLua(value));
256    CHECK_SETFIELD(key);
257}
258
259void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
260    lua_newtable(fL);
261    for (int i = 0; i < count; ++i) {
262        // make it base-1 to match lua convention
263        setarray_number(fL, i + 1, (double)array[i]);
264    }
265    CHECK_SETFIELD(key);
266}
267
268void SkLua::pushArrayPoint(const SkPoint array[], int count, const char key[]) {
269    lua_newtable(fL);
270    for (int i = 0; i < count; ++i) {
271        // make it base-1 to match lua convention
272        lua_newtable(fL);
273        this->pushScalar(array[i].fX, "x");
274        this->pushScalar(array[i].fY, "y");
275        lua_rawseti(fL, -2, i + 1);
276    }
277    CHECK_SETFIELD(key);
278}
279
280void SkLua::pushArrayScalar(const SkScalar array[], int count, const char key[]) {
281    lua_newtable(fL);
282    for (int i = 0; i < count; ++i) {
283        // make it base-1 to match lua convention
284        setarray_scalar(fL, i + 1, array[i]);
285    }
286    CHECK_SETFIELD(key);
287}
288
289void SkLua::pushRect(const SkRect& r, const char key[]) {
290    lua_newtable(fL);
291    setfield_scalar(fL, "left", r.fLeft);
292    setfield_scalar(fL, "top", r.fTop);
293    setfield_scalar(fL, "right", r.fRight);
294    setfield_scalar(fL, "bottom", r.fBottom);
295    CHECK_SETFIELD(key);
296}
297
298void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
299    push_obj(fL, rr);
300    CHECK_SETFIELD(key);
301}
302
303void SkLua::pushDash(const SkPathEffect::DashInfo& info, const char key[]) {
304    lua_newtable(fL);
305    setfield_scalar(fL, "phase", info.fPhase);
306    this->pushArrayScalar(info.fIntervals, info.fCount, "intervals");
307    CHECK_SETFIELD(key);
308}
309
310
311void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
312    push_obj(fL, matrix);
313    CHECK_SETFIELD(key);
314}
315
316void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
317    push_obj(fL, paint);
318    CHECK_SETFIELD(key);
319}
320
321void SkLua::pushPath(const SkPath& path, const char key[]) {
322    push_obj(fL, path);
323    CHECK_SETFIELD(key);
324}
325
326void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
327    push_ref(fL, canvas);
328    CHECK_SETFIELD(key);
329}
330
331void SkLua::pushTextBlob(const SkTextBlob* blob, const char key[]) {
332    push_ref(fL, const_cast<SkTextBlob*>(blob));
333    CHECK_SETFIELD(key);
334}
335
336static const char* element_type(SkClipStack::Element::Type type) {
337    switch (type) {
338        case SkClipStack::Element::kEmpty_Type:
339            return "empty";
340        case SkClipStack::Element::kRect_Type:
341            return "rect";
342        case SkClipStack::Element::kRRect_Type:
343            return "rrect";
344        case SkClipStack::Element::kPath_Type:
345            return "path";
346    }
347    return "unknown";
348}
349
350static const char* region_op(SkRegion::Op op) {
351    switch (op) {
352        case SkRegion::kDifference_Op:
353            return "difference";
354        case SkRegion::kIntersect_Op:
355            return "intersect";
356        case SkRegion::kUnion_Op:
357            return "union";
358        case SkRegion::kXOR_Op:
359            return "xor";
360        case SkRegion::kReverseDifference_Op:
361            return "reverse-difference";
362        case SkRegion::kReplace_Op:
363            return "replace";
364    }
365    return "unknown";
366}
367
368void SkLua::pushClipStack(const SkClipStack& stack, const char* key) {
369    lua_newtable(fL);
370    SkClipStack::B2TIter iter(stack);
371    const SkClipStack::Element* element;
372    int i = 0;
373    while ((element = iter.next())) {
374        this->pushClipStackElement(*element);
375        lua_rawseti(fL, -2, ++i);
376    }
377    CHECK_SETFIELD(key);
378}
379
380void SkLua::pushClipStackElement(const SkClipStack::Element& element, const char* key) {
381    lua_newtable(fL);
382    SkClipStack::Element::Type type = element.getType();
383    this->pushString(element_type(type), "type");
384    switch (type) {
385        case SkClipStack::Element::kEmpty_Type:
386            break;
387        case SkClipStack::Element::kRect_Type:
388            this->pushRect(element.getRect(), "rect");
389            break;
390        case SkClipStack::Element::kRRect_Type:
391            this->pushRRect(element.getRRect(), "rrect");
392            break;
393        case SkClipStack::Element::kPath_Type:
394            this->pushPath(element.getPath(), "path");
395            break;
396    }
397    this->pushString(region_op(element.getOp()), "op");
398    this->pushBool(element.isAA(), "aa");
399    CHECK_SETFIELD(key);
400}
401
402
403///////////////////////////////////////////////////////////////////////////////
404///////////////////////////////////////////////////////////////////////////////
405
406static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
407    SkASSERT(lua_istable(L, index));
408    lua_pushstring(L, key);
409    lua_gettable(L, index);
410
411    SkScalar value = lua2scalar(L, -1);
412    lua_pop(L, 1);
413    return value;
414}
415
416static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
417    SkASSERT(lua_istable(L, index));
418    lua_pushstring(L, key);
419    lua_gettable(L, index);
420
421    SkScalar value;
422    if (lua_isnil(L, -1)) {
423        value = def;
424    } else {
425        value = lua2scalar(L, -1);
426    }
427    lua_pop(L, 1);
428    return value;
429}
430
431static SkScalar byte2unit(U8CPU byte) {
432    return byte / 255.0f;
433}
434
435static U8CPU unit2byte(SkScalar x) {
436    if (x <= 0) {
437        return 0;
438    } else if (x >= 1) {
439        return 255;
440    } else {
441        return SkScalarRoundToInt(x * 255);
442    }
443}
444
445static SkColor lua2color(lua_State* L, int index) {
446    return SkColorSetARGB(unit2byte(getfield_scalar_default(L, index, "a", 1)),
447                          unit2byte(getfield_scalar_default(L, index, "r", 0)),
448                          unit2byte(getfield_scalar_default(L, index, "g", 0)),
449                          unit2byte(getfield_scalar_default(L, index, "b", 0)));
450}
451
452static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
453    rect->set(getfield_scalar_default(L, index, "left", 0),
454              getfield_scalar_default(L, index, "top", 0),
455              getfield_scalar(L, index, "right"),
456              getfield_scalar(L, index, "bottom"));
457    return rect;
458}
459
460static int lcanvas_clear(lua_State* L) {
461    get_ref<SkCanvas>(L, 1)->clear(0);
462    return 0;
463}
464
465static int lcanvas_drawColor(lua_State* L) {
466    get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
467    return 0;
468}
469
470static int lcanvas_drawPaint(lua_State* L) {
471    get_ref<SkCanvas>(L, 1)->drawPaint(*get_obj<SkPaint>(L, 2));
472    return 0;
473}
474
475static int lcanvas_drawRect(lua_State* L) {
476    SkRect rect;
477    lua2rect(L, 2, &rect);
478    const SkPaint* paint = get_obj<SkPaint>(L, 3);
479    get_ref<SkCanvas>(L, 1)->drawRect(rect, *paint);
480    return 0;
481}
482
483static int lcanvas_drawOval(lua_State* L) {
484    SkRect rect;
485    get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
486                                      *get_obj<SkPaint>(L, 3));
487    return 0;
488}
489
490static int lcanvas_drawCircle(lua_State* L) {
491    get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
492                                        lua2scalar(L, 3),
493                                        lua2scalar(L, 4),
494                                        *get_obj<SkPaint>(L, 5));
495    return 0;
496}
497
498static SkPaint* lua2OptionalPaint(lua_State* L, int index, SkPaint* paint) {
499    if (lua_isnumber(L, index)) {
500        paint->setAlpha(SkScalarRoundToInt(lua2scalar(L, index) * 255));
501        return paint;
502    } else if (lua_isuserdata(L, index)) {
503        const SkPaint* ptr = get_obj<SkPaint>(L, index);
504        if (ptr) {
505            *paint = *ptr;
506            return paint;
507        }
508    }
509    return nullptr;
510}
511
512static int lcanvas_drawImage(lua_State* L) {
513    SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
514    SkImage* image = get_ref<SkImage>(L, 2);
515    if (nullptr == image) {
516        return 0;
517    }
518    SkScalar x = lua2scalar(L, 3);
519    SkScalar y = lua2scalar(L, 4);
520
521    SkPaint paint;
522    canvas->drawImage(image, x, y, lua2OptionalPaint(L, 5, &paint));
523    return 0;
524}
525
526static int lcanvas_drawImageRect(lua_State* L) {
527    SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
528    SkImage* image = get_ref<SkImage>(L, 2);
529    if (nullptr == image) {
530        return 0;
531    }
532
533    SkRect srcR, dstR;
534    SkRect* srcRPtr = nullptr;
535    if (!lua_isnil(L, 3)) {
536        srcRPtr = lua2rect(L, 3, &srcR);
537    }
538    lua2rect(L, 4, &dstR);
539
540    SkPaint paint;
541    canvas->legacy_drawImageRect(image, srcRPtr, dstR, lua2OptionalPaint(L, 5, &paint));
542    return 0;
543}
544
545static int lcanvas_drawPatch(lua_State* L) {
546    SkPoint cubics[12];
547    SkColor colorStorage[4];
548    SkPoint texStorage[4];
549
550    const SkColor* colors = nullptr;
551    const SkPoint* texs = nullptr;
552
553    getarray_points(L, 2, cubics, 12);
554
555    colorStorage[0] = SK_ColorRED;
556    colorStorage[1] = SK_ColorGREEN;
557    colorStorage[2] = SK_ColorBLUE;
558    colorStorage[3] = SK_ColorGRAY;
559
560    if (lua_isnil(L, 4)) {
561        colors = colorStorage;
562    } else {
563        getarray_points(L, 4, texStorage, 4);
564        texs = texStorage;
565    }
566
567    get_ref<SkCanvas>(L, 1)->drawPatch(cubics, colors, texs, nullptr, *get_obj<SkPaint>(L, 5));
568    return 0;
569}
570
571static int lcanvas_drawPath(lua_State* L) {
572    get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
573                                      *get_obj<SkPaint>(L, 3));
574    return 0;
575}
576
577// drawPicture(pic, x, y, paint)
578static int lcanvas_drawPicture(lua_State* L) {
579    SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
580    SkPicture* picture = get_ref<SkPicture>(L, 2);
581    SkScalar x = lua2scalar_def(L, 3, 0);
582    SkScalar y = lua2scalar_def(L, 4, 0);
583    SkMatrix matrix, *matrixPtr = nullptr;
584    if (x || y) {
585        matrix.setTranslate(x, y);
586        matrixPtr = &matrix;
587    }
588    SkPaint paint;
589    canvas->drawPicture(picture, matrixPtr, lua2OptionalPaint(L, 5, &paint));
590    return 0;
591}
592
593static int lcanvas_drawText(lua_State* L) {
594    if (lua_gettop(L) < 5) {
595        return 0;
596    }
597
598    if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
599        size_t len;
600        const char* text = lua_tolstring(L, 2, &len);
601        get_ref<SkCanvas>(L, 1)->drawText(text, len,
602                                          lua2scalar(L, 3), lua2scalar(L, 4),
603                                          *get_obj<SkPaint>(L, 5));
604    }
605    return 0;
606}
607
608static int lcanvas_drawTextBlob(lua_State* L) {
609    const SkTextBlob* blob = get_ref<SkTextBlob>(L, 2);
610    SkScalar x = lua2scalar(L, 3);
611    SkScalar y = lua2scalar(L, 4);
612    const SkPaint& paint = *get_obj<SkPaint>(L, 5);
613    get_ref<SkCanvas>(L, 1)->drawTextBlob(blob, x, y, paint);
614    return 0;
615}
616
617static int lcanvas_getSaveCount(lua_State* L) {
618    lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
619    return 1;
620}
621
622static int lcanvas_getTotalMatrix(lua_State* L) {
623    SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
624    return 1;
625}
626
627static int lcanvas_getClipStack(lua_State* L) {
628    SkLua(L).pushClipStack(*get_ref<SkCanvas>(L, 1)->getClipStack());
629    return 1;
630}
631
632int SkLua::lcanvas_getReducedClipStack(lua_State* L) {
633#if SK_SUPPORT_GPU
634    const SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
635    SkIRect queryBounds = canvas->getTopLayerBounds();
636
637    GrReducedClip::ElementList elements;
638    GrReducedClip::InitialState initialState;
639    int32_t genID;
640    SkIRect resultBounds;
641
642    const SkClipStack& stack = *canvas->getClipStack();
643
644    GrReducedClip::ReduceClipStack(stack,
645                                   queryBounds,
646                                   &elements,
647                                   &genID,
648                                   &initialState,
649                                   &resultBounds,
650                                   nullptr);
651
652    GrReducedClip::ElementList::Iter iter(elements);
653    int i = 0;
654    lua_newtable(L);
655    while(iter.get()) {
656        SkLua(L).pushClipStackElement(*iter.get());
657        iter.next();
658        lua_rawseti(L, -2, ++i);
659    }
660    // Currently this only returns the element list to lua, not the initial state or result bounds.
661    // It could return these as additional items on the lua stack.
662    return 1;
663#else
664    return 0;
665#endif
666}
667
668static int lcanvas_save(lua_State* L) {
669    lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
670    return 1;
671}
672
673static int lcanvas_saveLayer(lua_State* L) {
674    SkPaint paint;
675    lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->saveLayer(nullptr, lua2OptionalPaint(L, 2, &paint)));
676    return 1;
677}
678
679static int lcanvas_restore(lua_State* L) {
680    get_ref<SkCanvas>(L, 1)->restore();
681    return 0;
682}
683
684static int lcanvas_scale(lua_State* L) {
685    SkScalar sx = lua2scalar_def(L, 2, 1);
686    SkScalar sy = lua2scalar_def(L, 3, sx);
687    get_ref<SkCanvas>(L, 1)->scale(sx, sy);
688    return 0;
689}
690
691static int lcanvas_translate(lua_State* L) {
692    SkScalar tx = lua2scalar_def(L, 2, 0);
693    SkScalar ty = lua2scalar_def(L, 3, 0);
694    get_ref<SkCanvas>(L, 1)->translate(tx, ty);
695    return 0;
696}
697
698static int lcanvas_rotate(lua_State* L) {
699    SkScalar degrees = lua2scalar_def(L, 2, 0);
700    get_ref<SkCanvas>(L, 1)->rotate(degrees);
701    return 0;
702}
703
704static int lcanvas_concat(lua_State* L) {
705    get_ref<SkCanvas>(L, 1)->concat(*get_obj<SkMatrix>(L, 2));
706    return 0;
707}
708
709static int lcanvas_newSurface(lua_State* L) {
710    int width = lua2int_def(L, 2, 0);
711    int height = lua2int_def(L, 3, 0);
712    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
713    SkSurface* surface = get_ref<SkCanvas>(L, 1)->newSurface(info);
714    if (nullptr == surface) {
715        lua_pushnil(L);
716    } else {
717        push_ref(L, surface)->unref();
718    }
719    return 1;
720}
721
722static int lcanvas_gc(lua_State* L) {
723    get_ref<SkCanvas>(L, 1)->unref();
724    return 0;
725}
726
727const struct luaL_Reg gSkCanvas_Methods[] = {
728    { "clear", lcanvas_clear },
729    { "drawColor", lcanvas_drawColor },
730    { "drawPaint", lcanvas_drawPaint },
731    { "drawRect", lcanvas_drawRect },
732    { "drawOval", lcanvas_drawOval },
733    { "drawCircle", lcanvas_drawCircle },
734    { "drawImage", lcanvas_drawImage },
735    { "drawImageRect", lcanvas_drawImageRect },
736    { "drawPatch", lcanvas_drawPatch },
737    { "drawPath", lcanvas_drawPath },
738    { "drawPicture", lcanvas_drawPicture },
739    { "drawText", lcanvas_drawText },
740    { "drawTextBlob", lcanvas_drawTextBlob },
741    { "getSaveCount", lcanvas_getSaveCount },
742    { "getTotalMatrix", lcanvas_getTotalMatrix },
743    { "getClipStack", lcanvas_getClipStack },
744#if SK_SUPPORT_GPU
745    { "getReducedClipStack", SkLua::lcanvas_getReducedClipStack },
746#endif
747    { "save", lcanvas_save },
748    { "saveLayer", lcanvas_saveLayer },
749    { "restore", lcanvas_restore },
750    { "scale", lcanvas_scale },
751    { "translate", lcanvas_translate },
752    { "rotate", lcanvas_rotate },
753    { "concat", lcanvas_concat },
754
755    { "newSurface", lcanvas_newSurface },
756
757    { "__gc", lcanvas_gc },
758    { nullptr, nullptr }
759};
760
761///////////////////////////////////////////////////////////////////////////////
762
763static int ldocument_beginPage(lua_State* L) {
764    const SkRect* contentPtr = nullptr;
765    push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
766                                                     lua2scalar(L, 3),
767                                                     contentPtr));
768    return 1;
769}
770
771static int ldocument_endPage(lua_State* L) {
772    get_ref<SkDocument>(L, 1)->endPage();
773    return 0;
774}
775
776static int ldocument_close(lua_State* L) {
777    get_ref<SkDocument>(L, 1)->close();
778    return 0;
779}
780
781static int ldocument_gc(lua_State* L) {
782    get_ref<SkDocument>(L, 1)->unref();
783    return 0;
784}
785
786static const struct luaL_Reg gSkDocument_Methods[] = {
787    { "beginPage", ldocument_beginPage },
788    { "endPage", ldocument_endPage },
789    { "close", ldocument_close },
790    { "__gc", ldocument_gc },
791    { nullptr, nullptr }
792};
793
794///////////////////////////////////////////////////////////////////////////////
795
796static int lpaint_isAntiAlias(lua_State* L) {
797    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
798    return 1;
799}
800
801static int lpaint_setAntiAlias(lua_State* L) {
802    get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
803    return 0;
804}
805
806static int lpaint_isDither(lua_State* L) {
807    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDither());
808    return 1;
809}
810
811static int lpaint_setDither(lua_State* L) {
812    get_obj<SkPaint>(L, 1)->setDither(lua2bool(L, 2));
813    return 0;
814}
815
816static int lpaint_isUnderlineText(lua_State* L) {
817    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isUnderlineText());
818    return 1;
819}
820
821static int lpaint_isStrikeThruText(lua_State* L) {
822    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isStrikeThruText());
823    return 1;
824}
825
826static int lpaint_isFakeBoldText(lua_State* L) {
827    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isFakeBoldText());
828    return 1;
829}
830
831static int lpaint_isLinearText(lua_State* L) {
832    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLinearText());
833    return 1;
834}
835
836static int lpaint_isSubpixelText(lua_State* L) {
837    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isSubpixelText());
838    return 1;
839}
840
841static int lpaint_setSubpixelText(lua_State* L) {
842    get_obj<SkPaint>(L, 1)->setSubpixelText(lua2bool(L, 2));
843    return 1;
844}
845
846static int lpaint_isDevKernText(lua_State* L) {
847    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDevKernText());
848    return 1;
849}
850
851static int lpaint_isLCDRenderText(lua_State* L) {
852    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLCDRenderText());
853    return 1;
854}
855
856static int lpaint_setLCDRenderText(lua_State* L) {
857    get_obj<SkPaint>(L, 1)->setLCDRenderText(lua2bool(L, 2));
858    return 1;
859}
860
861static int lpaint_isEmbeddedBitmapText(lua_State* L) {
862    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isEmbeddedBitmapText());
863    return 1;
864}
865
866static int lpaint_isAutohinted(lua_State* L) {
867    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAutohinted());
868    return 1;
869}
870
871static int lpaint_isVerticalText(lua_State* L) {
872    lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isVerticalText());
873    return 1;
874}
875
876static int lpaint_getAlpha(lua_State* L) {
877    SkLua(L).pushScalar(byte2unit(get_obj<SkPaint>(L, 1)->getAlpha()));
878    return 1;
879}
880
881static int lpaint_setAlpha(lua_State* L) {
882    get_obj<SkPaint>(L, 1)->setAlpha(unit2byte(lua2scalar(L, 2)));
883    return 0;
884}
885
886static int lpaint_getColor(lua_State* L) {
887    SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
888    return 1;
889}
890
891static int lpaint_setColor(lua_State* L) {
892    get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
893    return 0;
894}
895
896static int lpaint_getTextSize(lua_State* L) {
897    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
898    return 1;
899}
900
901static int lpaint_getTextScaleX(lua_State* L) {
902    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextScaleX());
903    return 1;
904}
905
906static int lpaint_getTextSkewX(lua_State* L) {
907    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSkewX());
908    return 1;
909}
910
911static int lpaint_setTextSize(lua_State* L) {
912    get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
913    return 0;
914}
915
916static int lpaint_getTypeface(lua_State* L) {
917    push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
918    return 1;
919}
920
921static int lpaint_setTypeface(lua_State* L) {
922    get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
923    return 0;
924}
925
926static int lpaint_getHinting(lua_State* L) {
927    SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getHinting());
928    return 1;
929}
930
931static int lpaint_getFilterQuality(lua_State* L) {
932    SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getFilterQuality());
933    return 1;
934}
935
936static int lpaint_setFilterQuality(lua_State* L) {
937    int level = lua2int_def(L, 2, -1);
938    if (level >= 0 && level <= 3) {
939        get_obj<SkPaint>(L, 1)->setFilterQuality((SkFilterQuality)level);
940    }
941    return 0;
942}
943
944static int lpaint_getFontID(lua_State* L) {
945    SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
946    SkLua(L).pushU32(SkTypeface::UniqueID(face));
947    return 1;
948}
949
950static const struct {
951    const char*     fLabel;
952    SkPaint::Align  fAlign;
953} gAlignRec[] = {
954    { "left",   SkPaint::kLeft_Align },
955    { "center", SkPaint::kCenter_Align },
956    { "right",  SkPaint::kRight_Align },
957};
958
959static int lpaint_getTextAlign(lua_State* L) {
960    SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
961    for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
962        if (gAlignRec[i].fAlign == align) {
963            lua_pushstring(L, gAlignRec[i].fLabel);
964            return 1;
965        }
966    }
967    return 0;
968}
969
970static int lpaint_setTextAlign(lua_State* L) {
971    if (lua_isstring(L, 2)) {
972        size_t len;
973        const char* label = lua_tolstring(L, 2, &len);
974
975        for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
976            if (!strcmp(gAlignRec[i].fLabel, label)) {
977                get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
978                break;
979            }
980        }
981    }
982    return 0;
983}
984
985static int lpaint_getStroke(lua_State* L) {
986    lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
987    return 1;
988}
989
990static int lpaint_setStroke(lua_State* L) {
991    SkPaint::Style style;
992
993    if (lua_toboolean(L, 2)) {
994        style = SkPaint::kStroke_Style;
995    } else {
996        style = SkPaint::kFill_Style;
997    }
998    get_obj<SkPaint>(L, 1)->setStyle(style);
999    return 0;
1000}
1001
1002static int lpaint_getStrokeCap(lua_State* L) {
1003    SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeCap());
1004    return 1;
1005}
1006
1007static int lpaint_getStrokeJoin(lua_State* L) {
1008    SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeJoin());
1009    return 1;
1010}
1011
1012static int lpaint_getTextEncoding(lua_State* L) {
1013    SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getTextEncoding());
1014    return 1;
1015}
1016
1017static int lpaint_getStrokeWidth(lua_State* L) {
1018    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
1019    return 1;
1020}
1021
1022static int lpaint_setStrokeWidth(lua_State* L) {
1023    get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
1024    return 0;
1025}
1026
1027static int lpaint_getStrokeMiter(lua_State* L) {
1028    SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeMiter());
1029    return 1;
1030}
1031
1032static int lpaint_measureText(lua_State* L) {
1033    if (lua_isstring(L, 2)) {
1034        size_t len;
1035        const char* text = lua_tolstring(L, 2, &len);
1036        SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
1037        return 1;
1038    }
1039    return 0;
1040}
1041
1042struct FontMetrics {
1043    SkScalar    fTop;       //!< The greatest distance above the baseline for any glyph (will be <= 0)
1044    SkScalar    fAscent;    //!< The recommended distance above the baseline (will be <= 0)
1045    SkScalar    fDescent;   //!< The recommended distance below the baseline (will be >= 0)
1046    SkScalar    fBottom;    //!< The greatest distance below the baseline for any glyph (will be >= 0)
1047    SkScalar    fLeading;   //!< The recommended distance to add between lines of text (will be >= 0)
1048    SkScalar    fAvgCharWidth;  //!< the average charactor width (>= 0)
1049    SkScalar    fXMin;      //!< The minimum bounding box x value for all glyphs
1050    SkScalar    fXMax;      //!< The maximum bounding box x value for all glyphs
1051    SkScalar    fXHeight;   //!< the height of an 'x' in px, or 0 if no 'x' in face
1052};
1053
1054static int lpaint_getFontMetrics(lua_State* L) {
1055    SkPaint::FontMetrics fm;
1056    SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
1057
1058    lua_newtable(L);
1059    setfield_scalar(L, "top", fm.fTop);
1060    setfield_scalar(L, "ascent", fm.fAscent);
1061    setfield_scalar(L, "descent", fm.fDescent);
1062    setfield_scalar(L, "bottom", fm.fBottom);
1063    setfield_scalar(L, "leading", fm.fLeading);
1064    SkLua(L).pushScalar(height);
1065    return 2;
1066}
1067
1068static int lpaint_getEffects(lua_State* L) {
1069    const SkPaint* paint = get_obj<SkPaint>(L, 1);
1070
1071    lua_newtable(L);
1072    setfield_bool_if(L, "looper",      !!paint->getLooper());
1073    setfield_bool_if(L, "pathEffect",  !!paint->getPathEffect());
1074    setfield_bool_if(L, "rasterizer",  !!paint->getRasterizer());
1075    setfield_bool_if(L, "maskFilter",  !!paint->getMaskFilter());
1076    setfield_bool_if(L, "shader",      !!paint->getShader());
1077    setfield_bool_if(L, "colorFilter", !!paint->getColorFilter());
1078    setfield_bool_if(L, "imageFilter", !!paint->getImageFilter());
1079    setfield_bool_if(L, "xfermode",    !!paint->getXfermode());
1080    return 1;
1081}
1082
1083static int lpaint_getXfermode(lua_State* L) {
1084    const SkPaint* paint = get_obj<SkPaint>(L, 1);
1085    SkXfermode* xfermode = paint->getXfermode();
1086    if (xfermode) {
1087        push_ref(L, xfermode);
1088        return 1;
1089    }
1090    return 0;
1091}
1092
1093static int lpaint_setXfermode(lua_State* L) {
1094    SkPaint* paint = get_obj<SkPaint>(L, 1);
1095    paint->setXfermode(get_ref<SkXfermode>(L, 2));
1096    return 0;
1097}
1098
1099static int lpaint_getColorFilter(lua_State* L) {
1100    const SkPaint* paint = get_obj<SkPaint>(L, 1);
1101    SkColorFilter* cf = paint->getColorFilter();
1102    if (cf) {
1103        push_ref(L, cf);
1104        return 1;
1105    }
1106    return 0;
1107}
1108
1109static int lpaint_setColorFilter(lua_State* L) {
1110    SkPaint* paint = get_obj<SkPaint>(L, 1);
1111    paint->setColorFilter(get_ref<SkColorFilter>(L, 2));
1112    return 0;
1113}
1114
1115static int lpaint_getImageFilter(lua_State* L) {
1116    const SkPaint* paint = get_obj<SkPaint>(L, 1);
1117    SkImageFilter* imf = paint->getImageFilter();
1118    if (imf) {
1119        push_ref(L, imf);
1120        return 1;
1121    }
1122    return 0;
1123}
1124
1125static int lpaint_setImageFilter(lua_State* L) {
1126    SkPaint* paint = get_obj<SkPaint>(L, 1);
1127    paint->setImageFilter(get_ref<SkImageFilter>(L, 2));
1128    return 0;
1129}
1130
1131static int lpaint_getShader(lua_State* L) {
1132    const SkPaint* paint = get_obj<SkPaint>(L, 1);
1133    SkShader* shader = paint->getShader();
1134    if (shader) {
1135        push_ref(L, shader);
1136        return 1;
1137    }
1138    return 0;
1139}
1140
1141static int lpaint_setShader(lua_State* L) {
1142    SkPaint* paint = get_obj<SkPaint>(L, 1);
1143    paint->setShader(get_ref<SkShader>(L, 2));
1144    return 0;
1145}
1146
1147static int lpaint_getPathEffect(lua_State* L) {
1148    const SkPaint* paint = get_obj<SkPaint>(L, 1);
1149    SkPathEffect* pe = paint->getPathEffect();
1150    if (pe) {
1151        push_ref(L, pe);
1152        return 1;
1153    }
1154    return 0;
1155}
1156
1157static int lpaint_gc(lua_State* L) {
1158    get_obj<SkPaint>(L, 1)->~SkPaint();
1159    return 0;
1160}
1161
1162static const struct luaL_Reg gSkPaint_Methods[] = {
1163    { "isAntiAlias", lpaint_isAntiAlias },
1164    { "setAntiAlias", lpaint_setAntiAlias },
1165    { "isDither", lpaint_isDither },
1166    { "setDither", lpaint_setDither },
1167    { "getFilterQuality", lpaint_getFilterQuality },
1168    { "setFilterQuality", lpaint_setFilterQuality },
1169    { "isUnderlineText", lpaint_isUnderlineText },
1170    { "isStrikeThruText", lpaint_isStrikeThruText },
1171    { "isFakeBoldText", lpaint_isFakeBoldText },
1172    { "isLinearText", lpaint_isLinearText },
1173    { "isSubpixelText", lpaint_isSubpixelText },
1174    { "setSubpixelText", lpaint_setSubpixelText },
1175    { "isDevKernText", lpaint_isDevKernText },
1176    { "isLCDRenderText", lpaint_isLCDRenderText },
1177    { "setLCDRenderText", lpaint_setLCDRenderText },
1178    { "isEmbeddedBitmapText", lpaint_isEmbeddedBitmapText },
1179    { "isAutohinted", lpaint_isAutohinted },
1180    { "isVerticalText", lpaint_isVerticalText },
1181    { "getAlpha", lpaint_getAlpha },
1182    { "setAlpha", lpaint_setAlpha },
1183    { "getColor", lpaint_getColor },
1184    { "setColor", lpaint_setColor },
1185    { "getTextSize", lpaint_getTextSize },
1186    { "setTextSize", lpaint_setTextSize },
1187    { "getTextScaleX", lpaint_getTextScaleX },
1188    { "getTextSkewX", lpaint_getTextSkewX },
1189    { "getTypeface", lpaint_getTypeface },
1190    { "setTypeface", lpaint_setTypeface },
1191    { "getHinting", lpaint_getHinting },
1192    { "getFontID", lpaint_getFontID },
1193    { "getTextAlign", lpaint_getTextAlign },
1194    { "setTextAlign", lpaint_setTextAlign },
1195    { "getStroke", lpaint_getStroke },
1196    { "setStroke", lpaint_setStroke },
1197    { "getStrokeCap", lpaint_getStrokeCap },
1198    { "getStrokeJoin", lpaint_getStrokeJoin },
1199    { "getTextEncoding", lpaint_getTextEncoding },
1200    { "getStrokeWidth", lpaint_getStrokeWidth },
1201    { "setStrokeWidth", lpaint_setStrokeWidth },
1202    { "getStrokeMiter", lpaint_getStrokeMiter },
1203    { "measureText", lpaint_measureText },
1204    { "getFontMetrics", lpaint_getFontMetrics },
1205    { "getEffects", lpaint_getEffects },
1206    { "getColorFilter", lpaint_getColorFilter },
1207    { "setColorFilter", lpaint_setColorFilter },
1208    { "getImageFilter", lpaint_getImageFilter },
1209    { "setImageFilter", lpaint_setImageFilter },
1210    { "getXfermode", lpaint_getXfermode },
1211    { "setXfermode", lpaint_setXfermode },
1212    { "getShader", lpaint_getShader },
1213    { "setShader", lpaint_setShader },
1214    { "getPathEffect", lpaint_getPathEffect },
1215    { "__gc", lpaint_gc },
1216    { nullptr, nullptr }
1217};
1218
1219///////////////////////////////////////////////////////////////////////////////
1220
1221static const char* mode2string(SkShader::TileMode mode) {
1222    static const char* gNames[] = { "clamp", "repeat", "mirror" };
1223    SkASSERT((unsigned)mode < SK_ARRAY_COUNT(gNames));
1224    return gNames[mode];
1225}
1226
1227static const char* gradtype2string(SkShader::GradientType t) {
1228    static const char* gNames[] = {
1229        "none", "color", "linear", "radial", "radial2", "sweep", "conical"
1230    };
1231    SkASSERT((unsigned)t < SK_ARRAY_COUNT(gNames));
1232    return gNames[t];
1233}
1234
1235static int lshader_isOpaque(lua_State* L) {
1236    SkShader* shader = get_ref<SkShader>(L, 1);
1237    return shader && shader->isOpaque();
1238}
1239
1240static int lshader_isABitmap(lua_State* L) {
1241    SkShader* shader = get_ref<SkShader>(L, 1);
1242    if (shader) {
1243        SkBitmap bm;
1244        SkMatrix matrix;
1245        SkShader::TileMode modes[2];
1246        if (shader->isABitmap(&bm, &matrix, modes)) {
1247            lua_newtable(L);
1248            setfield_number(L, "genID", bm.pixelRef() ? bm.pixelRef()->getGenerationID() : 0);
1249            setfield_number(L, "width", bm.width());
1250            setfield_number(L, "height", bm.height());
1251            setfield_string(L, "tileX", mode2string(modes[0]));
1252            setfield_string(L, "tileY", mode2string(modes[1]));
1253            return 1;
1254        }
1255    }
1256    return 0;
1257}
1258
1259static int lshader_asAGradient(lua_State* L) {
1260    SkShader* shader = get_ref<SkShader>(L, 1);
1261    if (shader) {
1262        SkShader::GradientInfo info;
1263        sk_bzero(&info, sizeof(info));
1264
1265        SkColor colors[3];  // hacked in for extracting info on 3 color case.
1266        SkScalar pos[3];
1267
1268        info.fColorCount = 3;
1269        info.fColors = &colors[0];
1270        info.fColorOffsets = &pos[0];
1271
1272        SkShader::GradientType t = shader->asAGradient(&info);
1273
1274        if (SkShader::kNone_GradientType != t) {
1275            lua_newtable(L);
1276            setfield_string(L, "type", gradtype2string(t));
1277            setfield_number(L, "colorCount", info.fColorCount);
1278            setfield_string(L, "tile", mode2string(info.fTileMode));
1279
1280            if (info.fColorCount == 3){
1281                setfield_number(L, "midPos", pos[1]);
1282            }
1283
1284            return 1;
1285        }
1286    }
1287    return 0;
1288}
1289
1290static int lshader_gc(lua_State* L) {
1291    get_ref<SkShader>(L, 1)->unref();
1292    return 0;
1293}
1294
1295static const struct luaL_Reg gSkShader_Methods[] = {
1296    { "isOpaque",       lshader_isOpaque },
1297    { "isABitmap",      lshader_isABitmap },
1298    { "asAGradient",    lshader_asAGradient },
1299    { "__gc",           lshader_gc },
1300    { nullptr, nullptr }
1301};
1302
1303///////////////////////////////////////////////////////////////////////////////
1304
1305static int lpatheffect_asADash(lua_State* L) {
1306    SkPathEffect* pe = get_ref<SkPathEffect>(L, 1);
1307    if (pe) {
1308        SkPathEffect::DashInfo info;
1309        SkPathEffect::DashType dashType = pe->asADash(&info);
1310        if (SkPathEffect::kDash_DashType == dashType) {
1311            SkAutoTArray<SkScalar> intervals(info.fCount);
1312            info.fIntervals = intervals.get();
1313            pe->asADash(&info);
1314            SkLua(L).pushDash(info);
1315            return 1;
1316        }
1317    }
1318    return 0;
1319}
1320
1321static int lpatheffect_gc(lua_State* L) {
1322    get_ref<SkPathEffect>(L, 1)->unref();
1323    return 0;
1324}
1325
1326static const struct luaL_Reg gSkPathEffect_Methods[] = {
1327    { "asADash",        lpatheffect_asADash },
1328    { "__gc",           lpatheffect_gc },
1329    { nullptr, nullptr }
1330};
1331
1332///////////////////////////////////////////////////////////////////////////////
1333
1334static int lpxfermode_getTypeName(lua_State* L) {
1335    lua_pushstring(L, get_ref<SkXfermode>(L, 1)->getTypeName());
1336    return 1;
1337}
1338
1339static int lpxfermode_gc(lua_State* L) {
1340    get_ref<SkXfermode>(L, 1)->unref();
1341    return 0;
1342}
1343
1344static const struct luaL_Reg gSkXfermode_Methods[] = {
1345    { "getTypeName",    lpxfermode_getTypeName },
1346    { "__gc",           lpxfermode_gc },
1347    { nullptr, nullptr }
1348};
1349
1350///////////////////////////////////////////////////////////////////////////////
1351
1352static int lpcolorfilter_gc(lua_State* L) {
1353    get_ref<SkColorFilter>(L, 1)->unref();
1354    return 0;
1355}
1356
1357static const struct luaL_Reg gSkColorFilter_Methods[] = {
1358    { "__gc",       lpcolorfilter_gc },
1359    { nullptr, nullptr }
1360};
1361
1362///////////////////////////////////////////////////////////////////////////////
1363
1364static int lpimagefilter_gc(lua_State* L) {
1365    get_ref<SkImageFilter>(L, 1)->unref();
1366    return 0;
1367}
1368
1369static const struct luaL_Reg gSkImageFilter_Methods[] = {
1370    { "__gc",       lpimagefilter_gc },
1371    { nullptr, nullptr }
1372};
1373
1374///////////////////////////////////////////////////////////////////////////////
1375
1376static int lmatrix_getType(lua_State* L) {
1377    SkMatrix::TypeMask mask = get_obj<SkMatrix>(L, 1)->getType();
1378
1379    lua_newtable(L);
1380    setfield_boolean(L, "translate",   SkToBool(mask & SkMatrix::kTranslate_Mask));
1381    setfield_boolean(L, "scale",       SkToBool(mask & SkMatrix::kScale_Mask));
1382    setfield_boolean(L, "affine",      SkToBool(mask & SkMatrix::kAffine_Mask));
1383    setfield_boolean(L, "perspective", SkToBool(mask & SkMatrix::kPerspective_Mask));
1384    return 1;
1385}
1386
1387static int lmatrix_getScaleX(lua_State* L) {
1388    lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleX());
1389    return 1;
1390}
1391
1392static int lmatrix_getScaleY(lua_State* L) {
1393    lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleY());
1394    return 1;
1395}
1396
1397static int lmatrix_getTranslateX(lua_State* L) {
1398    lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateX());
1399    return 1;
1400}
1401
1402static int lmatrix_getTranslateY(lua_State* L) {
1403    lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateY());
1404    return 1;
1405}
1406
1407static int lmatrix_invert(lua_State* L) {
1408    lua_pushboolean(L, get_obj<SkMatrix>(L, 1)->invert(get_obj<SkMatrix>(L, 2)));
1409    return 1;
1410}
1411
1412static int lmatrix_mapXY(lua_State* L) {
1413    SkPoint pt = { lua2scalar(L, 2), lua2scalar(L, 3) };
1414    get_obj<SkMatrix>(L, 1)->mapPoints(&pt, &pt, 1);
1415    lua_pushnumber(L, pt.x());
1416    lua_pushnumber(L, pt.y());
1417    return 2;
1418}
1419
1420static int lmatrix_setRectToRect(lua_State* L) {
1421    SkMatrix* matrix = get_obj<SkMatrix>(L, 1);
1422    SkRect srcR, dstR;
1423    lua2rect(L, 2, &srcR);
1424    lua2rect(L, 3, &dstR);
1425    const char* scaleToFitStr = lua_tostring(L, 4);
1426    SkMatrix::ScaleToFit scaleToFit = SkMatrix::kFill_ScaleToFit;
1427
1428    if (scaleToFitStr) {
1429        const struct {
1430            const char* fName;
1431            SkMatrix::ScaleToFit fScaleToFit;
1432        } rec[] = {
1433            { "fill",   SkMatrix::kFill_ScaleToFit },
1434            { "start",  SkMatrix::kStart_ScaleToFit },
1435            { "center", SkMatrix::kCenter_ScaleToFit },
1436            { "end",    SkMatrix::kEnd_ScaleToFit },
1437        };
1438
1439        for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) {
1440            if (strcmp(rec[i].fName, scaleToFitStr) == 0) {
1441                scaleToFit = rec[i].fScaleToFit;
1442                break;
1443            }
1444        }
1445    }
1446
1447    matrix->setRectToRect(srcR, dstR, scaleToFit);
1448    return 0;
1449}
1450
1451static const struct luaL_Reg gSkMatrix_Methods[] = {
1452    { "getType", lmatrix_getType },
1453    { "getScaleX", lmatrix_getScaleX },
1454    { "getScaleY", lmatrix_getScaleY },
1455    { "getTranslateX", lmatrix_getTranslateX },
1456    { "getTranslateY", lmatrix_getTranslateY },
1457    { "setRectToRect", lmatrix_setRectToRect },
1458    { "invert", lmatrix_invert },
1459    { "mapXY", lmatrix_mapXY },
1460    { nullptr, nullptr }
1461};
1462
1463///////////////////////////////////////////////////////////////////////////////
1464
1465static int lpath_getBounds(lua_State* L) {
1466    SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
1467    return 1;
1468}
1469
1470static const char* fill_type_to_str(SkPath::FillType fill) {
1471    switch (fill) {
1472        case SkPath::kEvenOdd_FillType:
1473            return "even-odd";
1474        case SkPath::kWinding_FillType:
1475            return "winding";
1476        case SkPath::kInverseEvenOdd_FillType:
1477            return "inverse-even-odd";
1478        case SkPath::kInverseWinding_FillType:
1479            return "inverse-winding";
1480    }
1481    return "unknown";
1482}
1483
1484static int lpath_getFillType(lua_State* L) {
1485    SkPath::FillType fill = get_obj<SkPath>(L, 1)->getFillType();
1486    SkLua(L).pushString(fill_type_to_str(fill));
1487    return 1;
1488}
1489
1490static SkString segment_masks_to_str(uint32_t segmentMasks) {
1491    SkString result;
1492    bool first = true;
1493    if (SkPath::kLine_SegmentMask & segmentMasks) {
1494        result.append("line");
1495        first = false;
1496        SkDEBUGCODE(segmentMasks &= ~SkPath::kLine_SegmentMask;)
1497    }
1498    if (SkPath::kQuad_SegmentMask & segmentMasks) {
1499        if (!first) {
1500            result.append(" ");
1501        }
1502        result.append("quad");
1503        first = false;
1504        SkDEBUGCODE(segmentMasks &= ~SkPath::kQuad_SegmentMask;)
1505    }
1506    if (SkPath::kConic_SegmentMask & segmentMasks) {
1507        if (!first) {
1508            result.append(" ");
1509        }
1510        result.append("conic");
1511        first = false;
1512        SkDEBUGCODE(segmentMasks &= ~SkPath::kConic_SegmentMask;)
1513    }
1514    if (SkPath::kCubic_SegmentMask & segmentMasks) {
1515        if (!first) {
1516            result.append(" ");
1517        }
1518        result.append("cubic");
1519        SkDEBUGCODE(segmentMasks &= ~SkPath::kCubic_SegmentMask;)
1520    }
1521    SkASSERT(0 == segmentMasks);
1522    return result;
1523}
1524
1525static int lpath_getSegmentTypes(lua_State* L) {
1526    uint32_t segMasks = get_obj<SkPath>(L, 1)->getSegmentMasks();
1527    SkLua(L).pushString(segment_masks_to_str(segMasks));
1528    return 1;
1529}
1530
1531static int lpath_isConvex(lua_State* L) {
1532    bool isConvex = SkPath::kConvex_Convexity == get_obj<SkPath>(L, 1)->getConvexity();
1533    SkLua(L).pushBool(isConvex);
1534    return 1;
1535}
1536
1537static int lpath_isEmpty(lua_State* L) {
1538    lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
1539    return 1;
1540}
1541
1542static int lpath_isRect(lua_State* L) {
1543    SkRect r;
1544    bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
1545    int ret_count = 1;
1546    lua_pushboolean(L, pred);
1547    if (pred) {
1548        SkLua(L).pushRect(r);
1549        ret_count += 1;
1550    }
1551    return ret_count;
1552}
1553
1554static const char* dir2string(SkPath::Direction dir) {
1555    static const char* gStr[] = {
1556        "unknown", "cw", "ccw"
1557    };
1558    SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
1559    return gStr[dir];
1560}
1561
1562static int lpath_isNestedFillRects(lua_State* L) {
1563    SkRect rects[2];
1564    SkPath::Direction dirs[2];
1565    bool pred = get_obj<SkPath>(L, 1)->isNestedFillRects(rects, dirs);
1566    int ret_count = 1;
1567    lua_pushboolean(L, pred);
1568    if (pred) {
1569        SkLua lua(L);
1570        lua.pushRect(rects[0]);
1571        lua.pushRect(rects[1]);
1572        lua_pushstring(L, dir2string(dirs[0]));
1573        lua_pushstring(L, dir2string(dirs[0]));
1574        ret_count += 4;
1575    }
1576    return ret_count;
1577}
1578
1579static int lpath_countPoints(lua_State* L) {
1580    lua_pushinteger(L, get_obj<SkPath>(L, 1)->countPoints());
1581    return 1;
1582}
1583
1584static int lpath_reset(lua_State* L) {
1585    get_obj<SkPath>(L, 1)->reset();
1586    return 0;
1587}
1588
1589static int lpath_moveTo(lua_State* L) {
1590    get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
1591    return 0;
1592}
1593
1594static int lpath_lineTo(lua_State* L) {
1595    get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
1596    return 0;
1597}
1598
1599static int lpath_quadTo(lua_State* L) {
1600    get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
1601                                  lua2scalar(L, 4), lua2scalar(L, 5));
1602    return 0;
1603}
1604
1605static int lpath_cubicTo(lua_State* L) {
1606    get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
1607                                   lua2scalar(L, 4), lua2scalar(L, 5),
1608                                   lua2scalar(L, 6), lua2scalar(L, 7));
1609    return 0;
1610}
1611
1612static int lpath_close(lua_State* L) {
1613    get_obj<SkPath>(L, 1)->close();
1614    return 0;
1615}
1616
1617static int lpath_gc(lua_State* L) {
1618    get_obj<SkPath>(L, 1)->~SkPath();
1619    return 0;
1620}
1621
1622static const struct luaL_Reg gSkPath_Methods[] = {
1623    { "getBounds", lpath_getBounds },
1624    { "getFillType", lpath_getFillType },
1625    { "getSegmentTypes", lpath_getSegmentTypes },
1626    { "isConvex", lpath_isConvex },
1627    { "isEmpty", lpath_isEmpty },
1628    { "isRect", lpath_isRect },
1629    { "isNestedFillRects", lpath_isNestedFillRects },
1630    { "countPoints", lpath_countPoints },
1631    { "reset", lpath_reset },
1632    { "moveTo", lpath_moveTo },
1633    { "lineTo", lpath_lineTo },
1634    { "quadTo", lpath_quadTo },
1635    { "cubicTo", lpath_cubicTo },
1636    { "close", lpath_close },
1637    { "__gc", lpath_gc },
1638    { nullptr, nullptr }
1639};
1640
1641///////////////////////////////////////////////////////////////////////////////
1642
1643static const char* rrect_type(const SkRRect& rr) {
1644    switch (rr.getType()) {
1645        case SkRRect::kEmpty_Type: return "empty";
1646        case SkRRect::kRect_Type: return "rect";
1647        case SkRRect::kOval_Type: return "oval";
1648        case SkRRect::kSimple_Type: return "simple";
1649        case SkRRect::kNinePatch_Type: return "nine-patch";
1650        case SkRRect::kComplex_Type: return "complex";
1651    }
1652    SkDEBUGFAIL("never get here");
1653    return "";
1654}
1655
1656static int lrrect_rect(lua_State* L) {
1657    SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
1658    return 1;
1659}
1660
1661static int lrrect_type(lua_State* L) {
1662    lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
1663    return 1;
1664}
1665
1666static int lrrect_radii(lua_State* L) {
1667    int corner = SkToInt(lua_tointeger(L, 2));
1668    SkVector v;
1669    if (corner < 0 || corner > 3) {
1670        SkDebugf("bad corner index %d", corner);
1671        v.set(0, 0);
1672    } else {
1673        v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
1674    }
1675    lua_pushnumber(L, v.fX);
1676    lua_pushnumber(L, v.fY);
1677    return 2;
1678}
1679
1680static int lrrect_gc(lua_State* L) {
1681    get_obj<SkRRect>(L, 1)->~SkRRect();
1682    return 0;
1683}
1684
1685static const struct luaL_Reg gSkRRect_Methods[] = {
1686    { "rect", lrrect_rect },
1687    { "type", lrrect_type },
1688    { "radii", lrrect_radii },
1689    { "__gc", lrrect_gc },
1690    { nullptr, nullptr }
1691};
1692
1693///////////////////////////////////////////////////////////////////////////////
1694
1695static int limage_width(lua_State* L) {
1696    lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
1697    return 1;
1698}
1699
1700static int limage_height(lua_State* L) {
1701    lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
1702    return 1;
1703}
1704
1705static int limage_newShader(lua_State* L) {
1706    SkShader::TileMode tmode = SkShader::kClamp_TileMode;
1707    const SkMatrix* localM = nullptr;
1708    SkAutoTUnref<SkShader> shader(get_ref<SkImage>(L, 1)->newShader(tmode, tmode, localM));
1709    push_ref(L, shader.get());
1710    return 1;
1711}
1712
1713static int limage_gc(lua_State* L) {
1714    get_ref<SkImage>(L, 1)->unref();
1715    return 0;
1716}
1717
1718static const struct luaL_Reg gSkImage_Methods[] = {
1719    { "width", limage_width },
1720    { "height", limage_height },
1721    { "newShader", limage_newShader },
1722    { "__gc", limage_gc },
1723    { nullptr, nullptr }
1724};
1725
1726///////////////////////////////////////////////////////////////////////////////
1727
1728static int lsurface_width(lua_State* L) {
1729    lua_pushinteger(L, get_ref<SkSurface>(L, 1)->width());
1730    return 1;
1731}
1732
1733static int lsurface_height(lua_State* L) {
1734    lua_pushinteger(L, get_ref<SkSurface>(L, 1)->height());
1735    return 1;
1736}
1737
1738static int lsurface_getCanvas(lua_State* L) {
1739    SkCanvas* canvas = get_ref<SkSurface>(L, 1)->getCanvas();
1740    if (nullptr == canvas) {
1741        lua_pushnil(L);
1742    } else {
1743        push_ref(L, canvas);
1744        // note: we don't unref canvas, since getCanvas did not ref it.
1745        // warning: this is weird: now Lua owns a ref on this canvas, but what if they let
1746        // the real owner (the surface) go away, but still hold onto the canvas?
1747        // *really* we want to sort of ref the surface again, but have the native object
1748        // know that it is supposed to be treated as a canvas...
1749    }
1750    return 1;
1751}
1752
1753static int lsurface_newImageSnapshot(lua_State* L) {
1754    SkImage* image = get_ref<SkSurface>(L, 1)->newImageSnapshot();
1755    if (nullptr == image) {
1756        lua_pushnil(L);
1757    } else {
1758        push_ref(L, image)->unref();
1759    }
1760    return 1;
1761}
1762
1763static int lsurface_newSurface(lua_State* L) {
1764    int width = lua2int_def(L, 2, 0);
1765    int height = lua2int_def(L, 3, 0);
1766    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
1767    SkSurface* surface = get_ref<SkSurface>(L, 1)->newSurface(info);
1768    if (nullptr == surface) {
1769        lua_pushnil(L);
1770    } else {
1771        push_ref(L, surface)->unref();
1772    }
1773    return 1;
1774}
1775
1776static int lsurface_gc(lua_State* L) {
1777    get_ref<SkSurface>(L, 1)->unref();
1778    return 0;
1779}
1780
1781static const struct luaL_Reg gSkSurface_Methods[] = {
1782    { "width", lsurface_width },
1783    { "height", lsurface_height },
1784    { "getCanvas", lsurface_getCanvas },
1785    { "newImageSnapshot", lsurface_newImageSnapshot },
1786    { "newSurface", lsurface_newSurface },
1787    { "__gc", lsurface_gc },
1788    { nullptr, nullptr }
1789};
1790
1791///////////////////////////////////////////////////////////////////////////////
1792
1793static int lpicturerecorder_beginRecording(lua_State* L) {
1794    const SkScalar w = lua2scalar_def(L, 2, -1);
1795    const SkScalar h = lua2scalar_def(L, 3, -1);
1796    if (w <= 0 || h <= 0) {
1797        lua_pushnil(L);
1798        return 1;
1799    }
1800
1801    SkCanvas* canvas = get_obj<SkPictureRecorder>(L, 1)->beginRecording(w, h);
1802    if (nullptr == canvas) {
1803        lua_pushnil(L);
1804        return 1;
1805    }
1806
1807    push_ref(L, canvas);
1808    return 1;
1809}
1810
1811static int lpicturerecorder_getCanvas(lua_State* L) {
1812    SkCanvas* canvas = get_obj<SkPictureRecorder>(L, 1)->getRecordingCanvas();
1813    if (nullptr == canvas) {
1814        lua_pushnil(L);
1815        return 1;
1816    }
1817    push_ref(L, canvas);
1818    return 1;
1819}
1820
1821static int lpicturerecorder_endRecording(lua_State* L) {
1822    SkPicture* pic = get_obj<SkPictureRecorder>(L, 1)->endRecording();
1823    if (nullptr == pic) {
1824        lua_pushnil(L);
1825        return 1;
1826    }
1827    push_ref(L, pic)->unref();
1828    return 1;
1829}
1830
1831static int lpicturerecorder_gc(lua_State* L) {
1832    get_obj<SkPictureRecorder>(L, 1)->~SkPictureRecorder();
1833    return 0;
1834}
1835
1836static const struct luaL_Reg gSkPictureRecorder_Methods[] = {
1837    { "beginRecording", lpicturerecorder_beginRecording },
1838    { "getCanvas", lpicturerecorder_getCanvas },
1839    { "endRecording", lpicturerecorder_endRecording },
1840    { "__gc", lpicturerecorder_gc },
1841    { nullptr, nullptr }
1842};
1843
1844///////////////////////////////////////////////////////////////////////////////
1845
1846static int lpicture_width(lua_State* L) {
1847    lua_pushnumber(L, get_ref<SkPicture>(L, 1)->cullRect().width());
1848    return 1;
1849}
1850
1851static int lpicture_height(lua_State* L) {
1852    lua_pushnumber(L, get_ref<SkPicture>(L, 1)->cullRect().height());
1853    return 1;
1854}
1855
1856static int lpicture_gc(lua_State* L) {
1857    get_ref<SkPicture>(L, 1)->unref();
1858    return 0;
1859}
1860
1861static const struct luaL_Reg gSkPicture_Methods[] = {
1862    { "width", lpicture_width },
1863    { "height", lpicture_height },
1864    { "__gc", lpicture_gc },
1865    { nullptr, nullptr }
1866};
1867
1868///////////////////////////////////////////////////////////////////////////////
1869
1870static int ltextblob_bounds(lua_State* L) {
1871    SkLua(L).pushRect(get_ref<SkTextBlob>(L, 1)->bounds());
1872    return 1;
1873}
1874
1875static int ltextblob_gc(lua_State* L) {
1876    SkSafeUnref(get_ref<SkTextBlob>(L, 1));
1877    return 0;
1878}
1879
1880static const struct luaL_Reg gSkTextBlob_Methods[] = {
1881    { "bounds", ltextblob_bounds },
1882    { "__gc", ltextblob_gc },
1883    { nullptr, nullptr }
1884};
1885
1886///////////////////////////////////////////////////////////////////////////////
1887
1888static int ltypeface_getFamilyName(lua_State* L) {
1889    SkString str;
1890    get_ref<SkTypeface>(L, 1)->getFamilyName(&str);
1891    lua_pushstring(L, str.c_str());
1892    return 1;
1893}
1894
1895static int ltypeface_getStyle(lua_State* L) {
1896    lua_pushnumber(L, (double)get_ref<SkTypeface>(L, 1)->style());
1897    return 1;
1898}
1899
1900static int ltypeface_gc(lua_State* L) {
1901    SkSafeUnref(get_ref<SkTypeface>(L, 1));
1902    return 0;
1903}
1904
1905static const struct luaL_Reg gSkTypeface_Methods[] = {
1906    { "getFamilyName", ltypeface_getFamilyName },
1907    { "getStyle", ltypeface_getStyle },
1908    { "__gc", ltypeface_gc },
1909    { nullptr, nullptr }
1910};
1911
1912///////////////////////////////////////////////////////////////////////////////
1913
1914class AutoCallLua {
1915public:
1916    AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
1917        lua_getglobal(L, func);
1918        if (!lua_isfunction(L, -1)) {
1919            int t = lua_type(L, -1);
1920            SkDebugf("--- expected function %d\n", t);
1921        }
1922
1923        lua_newtable(L);
1924        setfield_string(L, "verb", verb);
1925    }
1926
1927    ~AutoCallLua() {
1928        if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
1929            SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
1930        }
1931        lua_settop(fL, -1);
1932    }
1933
1934private:
1935    lua_State* fL;
1936};
1937
1938#define AUTO_LUA(verb)  AutoCallLua acl(fL, fFunc.c_str(), verb)
1939
1940///////////////////////////////////////////////////////////////////////////////
1941
1942static int lsk_newDocumentPDF(lua_State* L) {
1943    const char* file = nullptr;
1944    if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
1945        file = lua_tolstring(L, 1, nullptr);
1946    }
1947
1948    SkDocument* doc = SkDocument::CreatePDF(file);
1949    if (nullptr == doc) {
1950        // do I need to push a nil on the stack and return 1?
1951        return 0;
1952    } else {
1953        push_ref(L, doc)->unref();
1954        return 1;
1955    }
1956}
1957
1958static int lsk_newBlurImageFilter(lua_State* L) {
1959    SkScalar sigmaX = lua2scalar_def(L, 1, 0);
1960    SkScalar sigmaY = lua2scalar_def(L, 2, 0);
1961    SkImageFilter* imf = SkBlurImageFilter::Create(sigmaX, sigmaY);
1962    if (nullptr == imf) {
1963        lua_pushnil(L);
1964    } else {
1965        push_ref(L, imf)->unref();
1966    }
1967    return 1;
1968}
1969
1970static int lsk_newLinearGradient(lua_State* L) {
1971    SkScalar x0 = lua2scalar_def(L, 1, 0);
1972    SkScalar y0 = lua2scalar_def(L, 2, 0);
1973    SkColor  c0 = lua2color(L, 3);
1974    SkScalar x1 = lua2scalar_def(L, 4, 0);
1975    SkScalar y1 = lua2scalar_def(L, 5, 0);
1976    SkColor  c1 = lua2color(L, 6);
1977
1978    SkPoint pts[] = { { x0, y0 }, { x1, y1 } };
1979    SkColor colors[] = { c0, c1 };
1980    SkShader* s = SkGradientShader::CreateLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
1981    if (nullptr == s) {
1982        lua_pushnil(L);
1983    } else {
1984        push_ref(L, s)->unref();
1985    }
1986    return 1;
1987}
1988
1989static int lsk_newMatrix(lua_State* L) {
1990    push_new<SkMatrix>(L)->reset();
1991    return 1;
1992}
1993
1994static int lsk_newPaint(lua_State* L) {
1995    push_new<SkPaint>(L);
1996    return 1;
1997}
1998
1999static int lsk_newPath(lua_State* L) {
2000    push_new<SkPath>(L);
2001    return 1;
2002}
2003
2004static int lsk_newPictureRecorder(lua_State* L) {
2005    push_new<SkPictureRecorder>(L);
2006    return 1;
2007}
2008
2009static int lsk_newRRect(lua_State* L) {
2010    push_new<SkRRect>(L)->setEmpty();
2011    return 1;
2012}
2013
2014#include "SkTextBox.h"
2015// Sk.newTextBlob(text, rect, paint)
2016static int lsk_newTextBlob(lua_State* L) {
2017    const char* text = lua_tolstring(L, 1, nullptr);
2018    SkRect bounds;
2019    lua2rect(L, 2, &bounds);
2020    const SkPaint& paint = *get_obj<SkPaint>(L, 3);
2021
2022    SkTextBox box;
2023    box.setMode(SkTextBox::kLineBreak_Mode);
2024    box.setBox(bounds);
2025    box.setText(text, strlen(text), paint);
2026
2027    SkScalar newBottom;
2028    SkAutoTUnref<SkTextBlob> blob(box.snapshotTextBlob(&newBottom));
2029    push_ref<SkTextBlob>(L, blob);
2030    SkLua(L).pushScalar(newBottom);
2031    return 2;
2032}
2033
2034static int lsk_newTypeface(lua_State* L) {
2035    const char* name = nullptr;
2036    int style = SkTypeface::kNormal;
2037
2038    int count = lua_gettop(L);
2039    if (count > 0 && lua_isstring(L, 1)) {
2040        name = lua_tolstring(L, 1, nullptr);
2041        if (count > 1 && lua_isnumber(L, 2)) {
2042            style = lua_tointegerx(L, 2, nullptr) & SkTypeface::kBoldItalic;
2043        }
2044    }
2045
2046    SkTypeface* face = SkTypeface::CreateFromName(name,
2047                                                  (SkTypeface::Style)style);
2048//    SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
2049    if (nullptr == face) {
2050        face = SkTypeface::RefDefault();
2051    }
2052    push_ref(L, face)->unref();
2053    return 1;
2054}
2055
2056static int lsk_newRasterSurface(lua_State* L) {
2057    int width = lua2int_def(L, 1, 0);
2058    int height = lua2int_def(L, 2, 0);
2059    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
2060    SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
2061    SkSurface* surface = SkSurface::NewRaster(info, &props);
2062    if (nullptr == surface) {
2063        lua_pushnil(L);
2064    } else {
2065        push_ref(L, surface)->unref();
2066    }
2067    return 1;
2068}
2069
2070static int lsk_loadImage(lua_State* L) {
2071    if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
2072        const char* name = lua_tolstring(L, 1, nullptr);
2073        SkAutoDataUnref data(SkData::NewFromFileName(name));
2074        if (data.get()) {
2075            SkImage* image = SkImage::NewFromEncoded(data);
2076            if (image) {
2077                push_ref(L, image)->unref();
2078                return 1;
2079            }
2080        }
2081    }
2082    return 0;
2083}
2084
2085static void register_Sk(lua_State* L) {
2086    lua_newtable(L);
2087    lua_pushvalue(L, -1);
2088    lua_setglobal(L, "Sk");
2089    // the Sk table is still on top
2090
2091    setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
2092    setfield_function(L, "loadImage", lsk_loadImage);
2093    setfield_function(L, "newBlurImageFilter", lsk_newBlurImageFilter);
2094    setfield_function(L, "newLinearGradient", lsk_newLinearGradient);
2095    setfield_function(L, "newMatrix", lsk_newMatrix);
2096    setfield_function(L, "newPaint", lsk_newPaint);
2097    setfield_function(L, "newPath", lsk_newPath);
2098    setfield_function(L, "newPictureRecorder", lsk_newPictureRecorder);
2099    setfield_function(L, "newRRect", lsk_newRRect);
2100    setfield_function(L, "newRasterSurface", lsk_newRasterSurface);
2101    setfield_function(L, "newTextBlob", lsk_newTextBlob);
2102    setfield_function(L, "newTypeface", lsk_newTypeface);
2103    lua_pop(L, 1);  // pop off the Sk table
2104}
2105
2106#define REG_CLASS(L, C)                             \
2107    do {                                            \
2108        luaL_newmetatable(L, get_mtname<C>());      \
2109        lua_pushvalue(L, -1);                       \
2110        lua_setfield(L, -2, "__index");             \
2111        luaL_setfuncs(L, g##C##_Methods, 0);        \
2112        lua_pop(L, 1); /* pop off the meta-table */ \
2113    } while (0)
2114
2115void SkLua::Load(lua_State* L) {
2116    register_Sk(L);
2117    REG_CLASS(L, SkCanvas);
2118    REG_CLASS(L, SkColorFilter);
2119    REG_CLASS(L, SkDocument);
2120    REG_CLASS(L, SkImage);
2121    REG_CLASS(L, SkImageFilter);
2122    REG_CLASS(L, SkMatrix);
2123    REG_CLASS(L, SkPaint);
2124    REG_CLASS(L, SkPath);
2125    REG_CLASS(L, SkPathEffect);
2126    REG_CLASS(L, SkPicture);
2127    REG_CLASS(L, SkPictureRecorder);
2128    REG_CLASS(L, SkRRect);
2129    REG_CLASS(L, SkShader);
2130    REG_CLASS(L, SkSurface);
2131    REG_CLASS(L, SkTextBlob);
2132    REG_CLASS(L, SkTypeface);
2133    REG_CLASS(L, SkXfermode);
2134}
2135
2136extern "C" int luaopen_skia(lua_State* L);
2137extern "C" int luaopen_skia(lua_State* L) {
2138    SkLua::Load(L);
2139    return 0;
2140}
2141