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