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