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