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