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