• 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 "SkCanvas.h"
15 #include "SkData.h"
16 #include "SkDocument.h"
17 #include "SkImage.h"
18 #include "SkMatrix.h"
19 #include "SkPaint.h"
20 #include "SkPath.h"
21 #include "SkPixelRef.h"
22 #include "SkRRect.h"
23 #include "SkString.h"
24 #include "SkTypeface.h"
25 
26 extern "C" {
27     #include "lua.h"
28     #include "lualib.h"
29     #include "lauxlib.h"
30 }
31 
32 // return the metatable name for a given class
33 template <typename T> const char* get_mtname();
34 #define DEF_MTNAME(T)                           \
35     template <> const char* get_mtname<T>() {   \
36         return #T "_LuaMetaTableName";          \
37     }
38 
39 DEF_MTNAME(SkCanvas)
DEF_MTNAME(SkDocument)40 DEF_MTNAME(SkDocument)
41 DEF_MTNAME(SkImage)
42 DEF_MTNAME(SkMatrix)
43 DEF_MTNAME(SkRRect)
44 DEF_MTNAME(SkPath)
45 DEF_MTNAME(SkPaint)
46 DEF_MTNAME(SkPathEffect)
47 DEF_MTNAME(SkShader)
48 DEF_MTNAME(SkTypeface)
49 
50 template <typename T> T* push_new(lua_State* L) {
51     T* addr = (T*)lua_newuserdata(L, sizeof(T));
52     new (addr) T;
53     luaL_getmetatable(L, get_mtname<T>());
54     lua_setmetatable(L, -2);
55     return addr;
56 }
57 
push_obj(lua_State * L,const T & obj)58 template <typename T> void push_obj(lua_State* L, const T& obj) {
59     new (lua_newuserdata(L, sizeof(T))) T(obj);
60     luaL_getmetatable(L, get_mtname<T>());
61     lua_setmetatable(L, -2);
62 }
63 
push_ref(lua_State * L,T * ref)64 template <typename T> void push_ref(lua_State* L, T* ref) {
65     *(T**)lua_newuserdata(L, sizeof(T*)) = SkSafeRef(ref);
66     luaL_getmetatable(L, get_mtname<T>());
67     lua_setmetatable(L, -2);
68 }
69 
get_ref(lua_State * L,int index)70 template <typename T> T* get_ref(lua_State* L, int index) {
71     return *(T**)luaL_checkudata(L, index, get_mtname<T>());
72 }
73 
get_obj(lua_State * L,int index)74 template <typename T> T* get_obj(lua_State* L, int index) {
75     return (T*)luaL_checkudata(L, index, get_mtname<T>());
76 }
77 
lua2bool(lua_State * L,int index)78 static bool lua2bool(lua_State* L, int index) {
79     return !!lua_toboolean(L, index);
80 }
81 
82 ///////////////////////////////////////////////////////////////////////////////
83 
SkLua(const char termCode[])84 SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) {
85     fL = luaL_newstate();
86     luaL_openlibs(fL);
87     SkLua::Load(fL);
88 }
89 
SkLua(lua_State * L)90 SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {}
91 
~SkLua()92 SkLua::~SkLua() {
93     if (fWeOwnL) {
94         if (fTermCode.size() > 0) {
95             lua_getglobal(fL, fTermCode.c_str());
96             if (lua_pcall(fL, 0, 0, 0) != LUA_OK) {
97                 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
98             }
99         }
100         lua_close(fL);
101     }
102 }
103 
runCode(const char code[])104 bool SkLua::runCode(const char code[]) {
105     int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0);
106     if (err) {
107         SkDebugf("--- lua failed: %s\n", lua_tostring(fL, -1));
108         return false;
109     }
110     return true;
111 }
112 
runCode(const void * code,size_t size)113 bool SkLua::runCode(const void* code, size_t size) {
114     SkString str((const char*)code, size);
115     return this->runCode(str.c_str());
116 }
117 
118 ///////////////////////////////////////////////////////////////////////////////
119 
120 #define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0)
121 
setfield_bool_if(lua_State * L,const char key[],bool pred)122 static void setfield_bool_if(lua_State* L, const char key[], bool pred) {
123     if (pred) {
124         lua_pushboolean(L, true);
125         lua_setfield(L, -2, key);
126     }
127 }
128 
setfield_string(lua_State * L,const char key[],const char value[])129 static void setfield_string(lua_State* L, const char key[], const char value[]) {
130     lua_pushstring(L, value);
131     lua_setfield(L, -2, key);
132 }
133 
setfield_number(lua_State * L,const char key[],double value)134 static void setfield_number(lua_State* L, const char key[], double value) {
135     lua_pushnumber(L, value);
136     lua_setfield(L, -2, key);
137 }
138 
setfield_boolean(lua_State * L,const char key[],bool value)139 static void setfield_boolean(lua_State* L, const char key[], bool value) {
140     lua_pushboolean(L, value);
141     lua_setfield(L, -2, key);
142 }
143 
setfield_scalar(lua_State * L,const char key[],SkScalar value)144 static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
145     setfield_number(L, key, SkScalarToLua(value));
146 }
147 
setfield_function(lua_State * L,const char key[],lua_CFunction value)148 static void setfield_function(lua_State* L,
149                               const char key[], lua_CFunction value) {
150     lua_pushcfunction(L, value);
151     lua_setfield(L, -2, key);
152 }
153 
setarray_number(lua_State * L,int index,double value)154 static void setarray_number(lua_State* L, int index, double value) {
155     lua_pushnumber(L, value);
156     lua_rawseti(L, -2, index);
157 }
158 
setarray_scalar(lua_State * L,int index,SkScalar value)159 static void setarray_scalar(lua_State* L, int index, SkScalar value) {
160     setarray_number(L, index, SkScalarToLua(value));
161 }
162 
pushBool(bool value,const char key[])163 void SkLua::pushBool(bool value, const char key[]) {
164     lua_pushboolean(fL, value);
165     CHECK_SETFIELD(key);
166 }
167 
pushString(const char str[],const char key[])168 void SkLua::pushString(const char str[], const char key[]) {
169     lua_pushstring(fL, str);
170     CHECK_SETFIELD(key);
171 }
172 
pushString(const char str[],size_t length,const char key[])173 void SkLua::pushString(const char str[], size_t length, const char key[]) {
174     // TODO: how to do this w/o making a copy?
175     SkString s(str, length);
176     lua_pushstring(fL, s.c_str());
177     CHECK_SETFIELD(key);
178 }
179 
pushString(const SkString & str,const char key[])180 void SkLua::pushString(const SkString& str, const char key[]) {
181     lua_pushstring(fL, str.c_str());
182     CHECK_SETFIELD(key);
183 }
184 
pushColor(SkColor color,const char key[])185 void SkLua::pushColor(SkColor color, const char key[]) {
186     lua_newtable(fL);
187     setfield_number(fL, "a", SkColorGetA(color) / 255.0);
188     setfield_number(fL, "r", SkColorGetR(color) / 255.0);
189     setfield_number(fL, "g", SkColorGetG(color) / 255.0);
190     setfield_number(fL, "b", SkColorGetB(color) / 255.0);
191     CHECK_SETFIELD(key);
192 }
193 
pushU32(uint32_t value,const char key[])194 void SkLua::pushU32(uint32_t value, const char key[]) {
195     lua_pushnumber(fL, (double)value);
196     CHECK_SETFIELD(key);
197 }
198 
pushScalar(SkScalar value,const char key[])199 void SkLua::pushScalar(SkScalar value, const char key[]) {
200     lua_pushnumber(fL, SkScalarToLua(value));
201     CHECK_SETFIELD(key);
202 }
203 
pushArrayU16(const uint16_t array[],int count,const char key[])204 void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
205     lua_newtable(fL);
206     for (int i = 0; i < count; ++i) {
207         // make it base-1 to match lua convention
208         setarray_number(fL, i + 1, (double)array[i]);
209     }
210     CHECK_SETFIELD(key);
211 }
212 
pushArrayPoint(const SkPoint array[],int count,const char key[])213 void SkLua::pushArrayPoint(const SkPoint array[], int count, const char key[]) {
214     lua_newtable(fL);
215     for (int i = 0; i < count; ++i) {
216         // make it base-1 to match lua convention
217         lua_newtable(fL);
218         this->pushScalar(array[i].fX, "x");
219         this->pushScalar(array[i].fY, "y");
220         lua_rawseti(fL, -2, i + 1);
221     }
222     CHECK_SETFIELD(key);
223 }
224 
pushArrayScalar(const SkScalar array[],int count,const char key[])225 void SkLua::pushArrayScalar(const SkScalar array[], int count, const char key[]) {
226     lua_newtable(fL);
227     for (int i = 0; i < count; ++i) {
228         // make it base-1 to match lua convention
229         setarray_scalar(fL, i + 1, array[i]);
230     }
231     CHECK_SETFIELD(key);
232 }
233 
pushRect(const SkRect & r,const char key[])234 void SkLua::pushRect(const SkRect& r, const char key[]) {
235     lua_newtable(fL);
236     setfield_scalar(fL, "left", r.fLeft);
237     setfield_scalar(fL, "top", r.fTop);
238     setfield_scalar(fL, "right", r.fRight);
239     setfield_scalar(fL, "bottom", r.fBottom);
240     CHECK_SETFIELD(key);
241 }
242 
pushRRect(const SkRRect & rr,const char key[])243 void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
244     push_obj(fL, rr);
245     CHECK_SETFIELD(key);
246 }
247 
pushDash(const SkPathEffect::DashInfo & info,const char key[])248 void SkLua::pushDash(const SkPathEffect::DashInfo& info, const char key[]) {
249     lua_newtable(fL);
250     setfield_scalar(fL, "phase", info.fPhase);
251     this->pushArrayScalar(info.fIntervals, info.fCount, "intervals");
252     CHECK_SETFIELD(key);
253 }
254 
255 
pushMatrix(const SkMatrix & matrix,const char key[])256 void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
257     push_obj(fL, matrix);
258     CHECK_SETFIELD(key);
259 }
260 
pushPaint(const SkPaint & paint,const char key[])261 void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
262     push_obj(fL, paint);
263     CHECK_SETFIELD(key);
264 }
265 
pushPath(const SkPath & path,const char key[])266 void SkLua::pushPath(const SkPath& path, const char key[]) {
267     push_obj(fL, path);
268     CHECK_SETFIELD(key);
269 }
270 
pushCanvas(SkCanvas * canvas,const char key[])271 void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
272     push_ref(fL, canvas);
273     CHECK_SETFIELD(key);
274 }
275 
element_type(SkClipStack::Element::Type type)276 static const char* element_type(SkClipStack::Element::Type type) {
277     switch (type) {
278         case SkClipStack::Element::kEmpty_Type:
279             return "empty";
280         case SkClipStack::Element::kRect_Type:
281             return "rect";
282         case SkClipStack::Element::kRRect_Type:
283             return "rrect";
284         case SkClipStack::Element::kPath_Type:
285             return "path";
286     }
287     return "unknown";
288 }
289 
region_op(SkRegion::Op op)290 static const char* region_op(SkRegion::Op op) {
291     switch (op) {
292         case SkRegion::kDifference_Op:
293             return "difference";
294         case SkRegion::kIntersect_Op:
295             return "intersect";
296         case SkRegion::kUnion_Op:
297             return "union";
298         case SkRegion::kXOR_Op:
299             return "xor";
300         case SkRegion::kReverseDifference_Op:
301             return "reverse-difference";
302         case SkRegion::kReplace_Op:
303             return "replace";
304     }
305     return "unknown";
306 }
307 
pushClipStack(const SkClipStack & stack,const char * key)308 void SkLua::pushClipStack(const SkClipStack& stack, const char* key) {
309     lua_newtable(fL);
310     SkClipStack::B2TIter iter(stack);
311     const SkClipStack::Element* element;
312     int i = 0;
313     while (NULL != (element = iter.next())) {
314         this->pushClipStackElement(*element);
315         lua_rawseti(fL, -2, ++i);
316     }
317     CHECK_SETFIELD(key);
318 }
319 
pushClipStackElement(const SkClipStack::Element & element,const char * key)320 void SkLua::pushClipStackElement(const SkClipStack::Element& element, const char* key) {
321     lua_newtable(fL);
322     SkClipStack::Element::Type type = element.getType();
323     this->pushString(element_type(type), "type");
324     switch (type) {
325         case SkClipStack::Element::kEmpty_Type:
326             break;
327         case SkClipStack::Element::kRect_Type:
328             this->pushRect(element.getRect(), "rect");
329             break;
330         case SkClipStack::Element::kRRect_Type:
331             this->pushRRect(element.getRRect(), "rrect");
332             break;
333         case SkClipStack::Element::kPath_Type:
334             this->pushPath(element.getPath(), "path");
335             break;
336     }
337     this->pushString(region_op(element.getOp()), "op");
338     this->pushBool(element.isAA(), "aa");
339     CHECK_SETFIELD(key);
340 }
341 
342 
343 ///////////////////////////////////////////////////////////////////////////////
344 ///////////////////////////////////////////////////////////////////////////////
345 
lua2scalar(lua_State * L,int index)346 static SkScalar lua2scalar(lua_State* L, int index) {
347     SkASSERT(lua_isnumber(L, index));
348     return SkLuaToScalar(lua_tonumber(L, index));
349 }
350 
lua2scalar_def(lua_State * L,int index,SkScalar defaultValue)351 static SkScalar lua2scalar_def(lua_State* L, int index, SkScalar defaultValue) {
352     if (lua_isnumber(L, index)) {
353         return SkLuaToScalar(lua_tonumber(L, index));
354     } else {
355         return defaultValue;
356     }
357 }
358 
getfield_scalar(lua_State * L,int index,const char key[])359 static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
360     SkASSERT(lua_istable(L, index));
361     lua_pushstring(L, key);
362     lua_gettable(L, index);
363 
364     SkScalar value = lua2scalar(L, -1);
365     lua_pop(L, 1);
366     return value;
367 }
368 
getfield_scalar_default(lua_State * L,int index,const char key[],SkScalar def)369 static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
370     SkASSERT(lua_istable(L, index));
371     lua_pushstring(L, key);
372     lua_gettable(L, index);
373 
374     SkScalar value;
375     if (lua_isnil(L, -1)) {
376         value = def;
377     } else {
378         value = lua2scalar(L, -1);
379     }
380     lua_pop(L, 1);
381     return value;
382 }
383 
unit2byte(SkScalar x)384 static U8CPU unit2byte(SkScalar x) {
385     if (x <= 0) {
386         return 0;
387     } else if (x >= 1) {
388         return 255;
389     } else {
390         return SkScalarRoundToInt(x * 255);
391     }
392 }
393 
lua2color(lua_State * L,int index)394 static SkColor lua2color(lua_State* L, int index) {
395     return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
396                           unit2byte(getfield_scalar(L, index, "r")),
397                           unit2byte(getfield_scalar(L, index, "g")),
398                           unit2byte(getfield_scalar(L, index, "b")));
399 }
400 
lua2rect(lua_State * L,int index,SkRect * rect)401 static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
402     rect->set(getfield_scalar_default(L, index, "left", 0),
403               getfield_scalar_default(L, index, "top", 0),
404               getfield_scalar(L, index, "right"),
405               getfield_scalar(L, index, "bottom"));
406     return rect;
407 }
408 
lcanvas_drawColor(lua_State * L)409 static int lcanvas_drawColor(lua_State* L) {
410     get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
411     return 0;
412 }
413 
lcanvas_drawRect(lua_State * L)414 static int lcanvas_drawRect(lua_State* L) {
415     SkRect rect;
416     get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
417                                       *get_obj<SkPaint>(L, 3));
418     return 0;
419 }
420 
lcanvas_drawOval(lua_State * L)421 static int lcanvas_drawOval(lua_State* L) {
422     SkRect rect;
423     get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
424                                       *get_obj<SkPaint>(L, 3));
425     return 0;
426 }
427 
lcanvas_drawCircle(lua_State * L)428 static int lcanvas_drawCircle(lua_State* L) {
429     get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
430                                         lua2scalar(L, 3),
431                                         lua2scalar(L, 4),
432                                         *get_obj<SkPaint>(L, 5));
433     return 0;
434 }
435 
lcanvas_drawImage(lua_State * L)436 static int lcanvas_drawImage(lua_State* L) {
437     SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
438     SkImage* image = get_ref<SkImage>(L, 2);
439     if (NULL == image) {
440         return 0;
441     }
442     SkScalar x = lua2scalar(L, 3);
443     SkScalar y = lua2scalar(L, 4);
444 
445     SkPaint paint;
446     const SkPaint* paintPtr = NULL;
447     if (lua_isnumber(L, 5)) {
448         paint.setAlpha(SkScalarRoundToInt(lua2scalar(L, 5) * 255));
449         paintPtr = &paint;
450     }
451     image->draw(canvas, x, y, paintPtr);
452     return 0;
453 }
454 
lcanvas_drawPath(lua_State * L)455 static int lcanvas_drawPath(lua_State* L) {
456     get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
457                                       *get_obj<SkPaint>(L, 3));
458     return 0;
459 }
460 
lcanvas_drawText(lua_State * L)461 static int lcanvas_drawText(lua_State* L) {
462     if (lua_gettop(L) < 5) {
463         return 0;
464     }
465 
466     if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
467         size_t len;
468         const char* text = lua_tolstring(L, 2, &len);
469         get_ref<SkCanvas>(L, 1)->drawText(text, len,
470                                           lua2scalar(L, 3), lua2scalar(L, 4),
471                                           *get_obj<SkPaint>(L, 5));
472     }
473     return 0;
474 }
475 
lcanvas_getSaveCount(lua_State * L)476 static int lcanvas_getSaveCount(lua_State* L) {
477     lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
478     return 1;
479 }
480 
lcanvas_getTotalMatrix(lua_State * L)481 static int lcanvas_getTotalMatrix(lua_State* L) {
482     SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
483     return 1;
484 }
485 
lcanvas_getClipStack(lua_State * L)486 static int lcanvas_getClipStack(lua_State* L) {
487     SkLua(L).pushClipStack(*get_ref<SkCanvas>(L, 1)->getClipStack());
488     return 1;
489 }
490 
lcanvas_getReducedClipStack(lua_State * L)491 int SkLua::lcanvas_getReducedClipStack(lua_State* L) {
492 #if SK_SUPPORT_GPU
493     const SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
494     SkISize layerSize = canvas->getTopLayerSize();
495     SkIPoint layerOrigin = canvas->getTopLayerOrigin();
496     SkIRect queryBounds = SkIRect::MakeXYWH(layerOrigin.fX, layerOrigin.fY,
497                                             layerSize.fWidth, layerSize.fHeight);
498 
499     GrReducedClip::ElementList elements;
500     GrReducedClip::InitialState initialState;
501     int32_t genID;
502     SkIRect resultBounds;
503 
504     const SkClipStack& stack = *canvas->getClipStack();
505 
506     GrReducedClip::ReduceClipStack(stack,
507                                    queryBounds,
508                                    &elements,
509                                    &genID,
510                                    &initialState,
511                                    &resultBounds,
512                                    NULL);
513 
514     GrReducedClip::ElementList::Iter iter(elements);
515     int i = 0;
516     lua_newtable(L);
517     while(NULL != iter.get()) {
518         SkLua(L).pushClipStackElement(*iter.get());
519         iter.next();
520         lua_rawseti(L, -2, ++i);
521     }
522     // Currently this only returns the element list to lua, not the initial state or result bounds.
523     // It could return these as additional items on the lua stack.
524     return 1;
525 #else
526     return 0;
527 #endif
528 }
529 
lcanvas_save(lua_State * L)530 static int lcanvas_save(lua_State* L) {
531     lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
532     return 1;
533 }
534 
lcanvas_restore(lua_State * L)535 static int lcanvas_restore(lua_State* L) {
536     get_ref<SkCanvas>(L, 1)->restore();
537     return 0;
538 }
539 
lcanvas_scale(lua_State * L)540 static int lcanvas_scale(lua_State* L) {
541     SkScalar sx = lua2scalar_def(L, 2, 1);
542     SkScalar sy = lua2scalar_def(L, 3, sx);
543     get_ref<SkCanvas>(L, 1)->scale(sx, sy);
544     return 0;
545 }
546 
lcanvas_translate(lua_State * L)547 static int lcanvas_translate(lua_State* L) {
548     SkScalar tx = lua2scalar_def(L, 2, 0);
549     SkScalar ty = lua2scalar_def(L, 3, 0);
550     get_ref<SkCanvas>(L, 1)->translate(tx, ty);
551     return 0;
552 }
553 
lcanvas_rotate(lua_State * L)554 static int lcanvas_rotate(lua_State* L) {
555     SkScalar degrees = lua2scalar_def(L, 2, 0);
556     get_ref<SkCanvas>(L, 1)->rotate(degrees);
557     return 0;
558 }
559 
lcanvas_gc(lua_State * L)560 static int lcanvas_gc(lua_State* L) {
561     get_ref<SkCanvas>(L, 1)->unref();
562     return 0;
563 }
564 
565 const struct luaL_Reg gSkCanvas_Methods[] = {
566     { "drawColor", lcanvas_drawColor },
567     { "drawRect", lcanvas_drawRect },
568     { "drawOval", lcanvas_drawOval },
569     { "drawCircle", lcanvas_drawCircle },
570     { "drawImage", lcanvas_drawImage },
571     { "drawPath", lcanvas_drawPath },
572     { "drawText", lcanvas_drawText },
573     { "getSaveCount", lcanvas_getSaveCount },
574     { "getTotalMatrix", lcanvas_getTotalMatrix },
575     { "getClipStack", lcanvas_getClipStack },
576 #if SK_SUPPORT_GPU
577     { "getReducedClipStack", SkLua::lcanvas_getReducedClipStack },
578 #endif
579     { "save", lcanvas_save },
580     { "restore", lcanvas_restore },
581     { "scale", lcanvas_scale },
582     { "translate", lcanvas_translate },
583     { "rotate", lcanvas_rotate },
584     { "__gc", lcanvas_gc },
585     { NULL, NULL }
586 };
587 
588 ///////////////////////////////////////////////////////////////////////////////
589 
ldocument_beginPage(lua_State * L)590 static int ldocument_beginPage(lua_State* L) {
591     const SkRect* contentPtr = NULL;
592     push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
593                                                      lua2scalar(L, 3),
594                                                      contentPtr));
595     return 1;
596 }
597 
ldocument_endPage(lua_State * L)598 static int ldocument_endPage(lua_State* L) {
599     get_ref<SkDocument>(L, 1)->endPage();
600     return 0;
601 }
602 
ldocument_close(lua_State * L)603 static int ldocument_close(lua_State* L) {
604     get_ref<SkDocument>(L, 1)->close();
605     return 0;
606 }
607 
ldocument_gc(lua_State * L)608 static int ldocument_gc(lua_State* L) {
609     get_ref<SkDocument>(L, 1)->unref();
610     return 0;
611 }
612 
613 static const struct luaL_Reg gSkDocument_Methods[] = {
614     { "beginPage", ldocument_beginPage },
615     { "endPage", ldocument_endPage },
616     { "close", ldocument_close },
617     { "__gc", ldocument_gc },
618     { NULL, NULL }
619 };
620 
621 ///////////////////////////////////////////////////////////////////////////////
622 
lpaint_isAntiAlias(lua_State * L)623 static int lpaint_isAntiAlias(lua_State* L) {
624     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
625     return 1;
626 }
627 
lpaint_setAntiAlias(lua_State * L)628 static int lpaint_setAntiAlias(lua_State* L) {
629     get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
630     return 0;
631 }
632 
lpaint_isDither(lua_State * L)633 static int lpaint_isDither(lua_State* L) {
634     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDither());
635     return 1;
636 }
637 
lpaint_isUnderlineText(lua_State * L)638 static int lpaint_isUnderlineText(lua_State* L) {
639     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isUnderlineText());
640     return 1;
641 }
642 
lpaint_isStrikeThruText(lua_State * L)643 static int lpaint_isStrikeThruText(lua_State* L) {
644     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isStrikeThruText());
645     return 1;
646 }
647 
lpaint_isFakeBoldText(lua_State * L)648 static int lpaint_isFakeBoldText(lua_State* L) {
649     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isFakeBoldText());
650     return 1;
651 }
652 
lpaint_isLinearText(lua_State * L)653 static int lpaint_isLinearText(lua_State* L) {
654     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLinearText());
655     return 1;
656 }
657 
lpaint_isSubpixelText(lua_State * L)658 static int lpaint_isSubpixelText(lua_State* L) {
659     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isSubpixelText());
660     return 1;
661 }
662 
lpaint_isDevKernText(lua_State * L)663 static int lpaint_isDevKernText(lua_State* L) {
664     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDevKernText());
665     return 1;
666 }
667 
lpaint_isLCDRenderText(lua_State * L)668 static int lpaint_isLCDRenderText(lua_State* L) {
669     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLCDRenderText());
670     return 1;
671 }
672 
lpaint_isEmbeddedBitmapText(lua_State * L)673 static int lpaint_isEmbeddedBitmapText(lua_State* L) {
674     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isEmbeddedBitmapText());
675     return 1;
676 }
677 
lpaint_isAutohinted(lua_State * L)678 static int lpaint_isAutohinted(lua_State* L) {
679     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAutohinted());
680     return 1;
681 }
682 
lpaint_isVerticalText(lua_State * L)683 static int lpaint_isVerticalText(lua_State* L) {
684     lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isVerticalText());
685     return 1;
686 }
687 
lpaint_getColor(lua_State * L)688 static int lpaint_getColor(lua_State* L) {
689     SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
690     return 1;
691 }
692 
lpaint_setColor(lua_State * L)693 static int lpaint_setColor(lua_State* L) {
694     get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
695     return 0;
696 }
697 
lpaint_getTextSize(lua_State * L)698 static int lpaint_getTextSize(lua_State* L) {
699     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
700     return 1;
701 }
702 
lpaint_getTextScaleX(lua_State * L)703 static int lpaint_getTextScaleX(lua_State* L) {
704     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextScaleX());
705     return 1;
706 }
707 
lpaint_getTextSkewX(lua_State * L)708 static int lpaint_getTextSkewX(lua_State* L) {
709     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSkewX());
710     return 1;
711 }
712 
lpaint_setTextSize(lua_State * L)713 static int lpaint_setTextSize(lua_State* L) {
714     get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
715     return 0;
716 }
717 
lpaint_getTypeface(lua_State * L)718 static int lpaint_getTypeface(lua_State* L) {
719     push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
720     return 1;
721 }
722 
lpaint_setTypeface(lua_State * L)723 static int lpaint_setTypeface(lua_State* L) {
724     get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
725     return 0;
726 }
727 
lpaint_getHinting(lua_State * L)728 static int lpaint_getHinting(lua_State* L) {
729     SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getHinting());
730     return 1;
731 }
732 
lpaint_getFontID(lua_State * L)733 static int lpaint_getFontID(lua_State* L) {
734     SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
735     SkLua(L).pushU32(SkTypeface::UniqueID(face));
736     return 1;
737 }
738 
739 static const struct {
740     const char*     fLabel;
741     SkPaint::Align  fAlign;
742 } gAlignRec[] = {
743     { "left",   SkPaint::kLeft_Align },
744     { "center", SkPaint::kCenter_Align },
745     { "right",  SkPaint::kRight_Align },
746 };
747 
lpaint_getTextAlign(lua_State * L)748 static int lpaint_getTextAlign(lua_State* L) {
749     SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
750     for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
751         if (gAlignRec[i].fAlign == align) {
752             lua_pushstring(L, gAlignRec[i].fLabel);
753             return 1;
754         }
755     }
756     return 0;
757 }
758 
lpaint_setTextAlign(lua_State * L)759 static int lpaint_setTextAlign(lua_State* L) {
760     if (lua_isstring(L, 2)) {
761         size_t len;
762         const char* label = lua_tolstring(L, 2, &len);
763 
764         for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
765             if (!strcmp(gAlignRec[i].fLabel, label)) {
766                 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
767                 break;
768             }
769         }
770     }
771     return 0;
772 }
773 
lpaint_getStroke(lua_State * L)774 static int lpaint_getStroke(lua_State* L) {
775     lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
776     return 1;
777 }
778 
lpaint_setStroke(lua_State * L)779 static int lpaint_setStroke(lua_State* L) {
780     SkPaint::Style style;
781 
782     if (lua_toboolean(L, 2)) {
783         style = SkPaint::kStroke_Style;
784     } else {
785         style = SkPaint::kFill_Style;
786     }
787     get_obj<SkPaint>(L, 1)->setStyle(style);
788     return 0;
789 }
790 
lpaint_getStrokeCap(lua_State * L)791 static int lpaint_getStrokeCap(lua_State* L) {
792     SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeCap());
793     return 1;
794 }
795 
lpaint_getStrokeJoin(lua_State * L)796 static int lpaint_getStrokeJoin(lua_State* L) {
797     SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeJoin());
798     return 1;
799 }
800 
lpaint_getTextEncoding(lua_State * L)801 static int lpaint_getTextEncoding(lua_State* L) {
802     SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getTextEncoding());
803     return 1;
804 }
805 
lpaint_getStrokeWidth(lua_State * L)806 static int lpaint_getStrokeWidth(lua_State* L) {
807     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
808     return 1;
809 }
810 
lpaint_setStrokeWidth(lua_State * L)811 static int lpaint_setStrokeWidth(lua_State* L) {
812     get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
813     return 0;
814 }
815 
lpaint_getStrokeMiter(lua_State * L)816 static int lpaint_getStrokeMiter(lua_State* L) {
817     SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeMiter());
818     return 1;
819 }
820 
lpaint_measureText(lua_State * L)821 static int lpaint_measureText(lua_State* L) {
822     if (lua_isstring(L, 2)) {
823         size_t len;
824         const char* text = lua_tolstring(L, 2, &len);
825         SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
826         return 1;
827     }
828     return 0;
829 }
830 
831 struct FontMetrics {
832     SkScalar    fTop;       //!< The greatest distance above the baseline for any glyph (will be <= 0)
833     SkScalar    fAscent;    //!< The recommended distance above the baseline (will be <= 0)
834     SkScalar    fDescent;   //!< The recommended distance below the baseline (will be >= 0)
835     SkScalar    fBottom;    //!< The greatest distance below the baseline for any glyph (will be >= 0)
836     SkScalar    fLeading;   //!< The recommended distance to add between lines of text (will be >= 0)
837     SkScalar    fAvgCharWidth;  //!< the average charactor width (>= 0)
838     SkScalar    fXMin;      //!< The minimum bounding box x value for all glyphs
839     SkScalar    fXMax;      //!< The maximum bounding box x value for all glyphs
840     SkScalar    fXHeight;   //!< the height of an 'x' in px, or 0 if no 'x' in face
841 };
842 
lpaint_getFontMetrics(lua_State * L)843 static int lpaint_getFontMetrics(lua_State* L) {
844     SkPaint::FontMetrics fm;
845     SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
846 
847     lua_newtable(L);
848     setfield_scalar(L, "top", fm.fTop);
849     setfield_scalar(L, "ascent", fm.fAscent);
850     setfield_scalar(L, "descent", fm.fDescent);
851     setfield_scalar(L, "bottom", fm.fBottom);
852     setfield_scalar(L, "leading", fm.fLeading);
853     SkLua(L).pushScalar(height);
854     return 2;
855 }
856 
lpaint_getEffects(lua_State * L)857 static int lpaint_getEffects(lua_State* L) {
858     const SkPaint* paint = get_obj<SkPaint>(L, 1);
859 
860     lua_newtable(L);
861     setfield_bool_if(L, "looper", !!paint->getLooper());
862     setfield_bool_if(L, "pathEffect", !!paint->getPathEffect());
863     setfield_bool_if(L, "rasterizer", !!paint->getRasterizer());
864     setfield_bool_if(L, "maskFilter", !!paint->getMaskFilter());
865     setfield_bool_if(L, "shader", !!paint->getShader());
866     setfield_bool_if(L, "colorFilter", !!paint->getColorFilter());
867     setfield_bool_if(L, "imageFilter", !!paint->getImageFilter());
868     setfield_bool_if(L, "xfermode", !!paint->getXfermode());
869     return 1;
870 }
871 
lpaint_getShader(lua_State * L)872 static int lpaint_getShader(lua_State* L) {
873     const SkPaint* paint = get_obj<SkPaint>(L, 1);
874     SkShader* shader = paint->getShader();
875     if (shader) {
876         push_ref(L, shader);
877         return 1;
878     }
879     return 0;
880 }
881 
lpaint_getPathEffect(lua_State * L)882 static int lpaint_getPathEffect(lua_State* L) {
883     const SkPaint* paint = get_obj<SkPaint>(L, 1);
884     SkPathEffect* pe = paint->getPathEffect();
885     if (pe) {
886         push_ref(L, pe);
887         return 1;
888     }
889     return 0;
890 }
891 
lpaint_gc(lua_State * L)892 static int lpaint_gc(lua_State* L) {
893     get_obj<SkPaint>(L, 1)->~SkPaint();
894     return 0;
895 }
896 
897 static const struct luaL_Reg gSkPaint_Methods[] = {
898     { "isAntiAlias", lpaint_isAntiAlias },
899     { "setAntiAlias", lpaint_setAntiAlias },
900     { "isDither", lpaint_isDither },
901     { "isUnderlineText", lpaint_isUnderlineText },
902     { "isStrikeThruText", lpaint_isStrikeThruText },
903     { "isFakeBoldText", lpaint_isFakeBoldText },
904     { "isLinearText", lpaint_isLinearText },
905     { "isSubpixelText", lpaint_isSubpixelText },
906     { "isDevKernText", lpaint_isDevKernText },
907     { "isLCDRenderText", lpaint_isLCDRenderText },
908     { "isEmbeddedBitmapText", lpaint_isEmbeddedBitmapText },
909     { "isAutohinted", lpaint_isAutohinted },
910     { "isVerticalText", lpaint_isVerticalText },
911     { "getColor", lpaint_getColor },
912     { "setColor", lpaint_setColor },
913     { "getTextSize", lpaint_getTextSize },
914     { "setTextSize", lpaint_setTextSize },
915     { "getTextScaleX", lpaint_getTextScaleX },
916     { "getTextSkewX", lpaint_getTextSkewX },
917     { "getTypeface", lpaint_getTypeface },
918     { "setTypeface", lpaint_setTypeface },
919     { "getHinting", lpaint_getHinting },
920     { "getFontID", lpaint_getFontID },
921     { "getTextAlign", lpaint_getTextAlign },
922     { "setTextAlign", lpaint_setTextAlign },
923     { "getStroke", lpaint_getStroke },
924     { "setStroke", lpaint_setStroke },
925     { "getStrokeCap", lpaint_getStrokeCap },
926     { "getStrokeJoin", lpaint_getStrokeJoin },
927     { "getTextEncoding", lpaint_getTextEncoding },
928     { "getStrokeWidth", lpaint_getStrokeWidth },
929     { "setStrokeWidth", lpaint_setStrokeWidth },
930     { "getStrokeMiter", lpaint_getStrokeMiter },
931     { "measureText", lpaint_measureText },
932     { "getFontMetrics", lpaint_getFontMetrics },
933     { "getEffects", lpaint_getEffects },
934     { "getShader", lpaint_getShader },
935     { "getPathEffect", lpaint_getPathEffect },
936     { "__gc", lpaint_gc },
937     { NULL, NULL }
938 };
939 
940 ///////////////////////////////////////////////////////////////////////////////
941 
mode2string(SkShader::TileMode mode)942 static const char* mode2string(SkShader::TileMode mode) {
943     static const char* gNames[] = { "clamp", "repeat", "mirror" };
944     SkASSERT((unsigned)mode < SK_ARRAY_COUNT(gNames));
945     return gNames[mode];
946 }
947 
gradtype2string(SkShader::GradientType t)948 static const char* gradtype2string(SkShader::GradientType t) {
949     static const char* gNames[] = {
950         "none", "color", "linear", "radial", "radial2", "sweep", "conical"
951     };
952     SkASSERT((unsigned)t < SK_ARRAY_COUNT(gNames));
953     return gNames[t];
954 }
955 
lshader_isOpaque(lua_State * L)956 static int lshader_isOpaque(lua_State* L) {
957     SkShader* shader = get_ref<SkShader>(L, 1);
958     return shader && shader->isOpaque();
959 }
960 
lshader_asABitmap(lua_State * L)961 static int lshader_asABitmap(lua_State* L) {
962     SkShader* shader = get_ref<SkShader>(L, 1);
963     if (shader) {
964         SkBitmap bm;
965         SkMatrix matrix;
966         SkShader::TileMode modes[2];
967         switch (shader->asABitmap(&bm, &matrix, modes)) {
968             case SkShader::kDefault_BitmapType:
969                 lua_newtable(L);
970                 setfield_number(L, "genID", bm.pixelRef() ? bm.pixelRef()->getGenerationID() : 0);
971                 setfield_number(L, "width", bm.width());
972                 setfield_number(L, "height", bm.height());
973                 setfield_string(L, "tileX", mode2string(modes[0]));
974                 setfield_string(L, "tileY", mode2string(modes[1]));
975                 return 1;
976             default:
977                 break;
978         }
979     }
980     return 0;
981 }
982 
lshader_asAGradient(lua_State * L)983 static int lshader_asAGradient(lua_State* L) {
984     SkShader* shader = get_ref<SkShader>(L, 1);
985     if (shader) {
986         SkShader::GradientInfo info;
987         sk_bzero(&info, sizeof(info));
988 
989         SkColor colors[3];  // hacked in for extracting info on 3 color case.
990         SkScalar pos[3];
991 
992         info.fColorCount = 3;
993         info.fColors = &colors[0];
994         info.fColorOffsets = &pos[0];
995 
996         SkShader::GradientType t = shader->asAGradient(&info);
997 
998         if (SkShader::kNone_GradientType != t) {
999             lua_newtable(L);
1000             setfield_string(L, "type", gradtype2string(t));
1001             setfield_number(L, "colorCount", info.fColorCount);
1002             setfield_string(L, "tile", mode2string(info.fTileMode));
1003 
1004             if (info.fColorCount == 3){
1005                 setfield_number(L, "midPos", pos[1]);
1006             }
1007 
1008             return 1;
1009         }
1010     }
1011     return 0;
1012 }
1013 
lshader_gc(lua_State * L)1014 static int lshader_gc(lua_State* L) {
1015     get_ref<SkShader>(L, 1)->unref();
1016     return 0;
1017 }
1018 
1019 static const struct luaL_Reg gSkShader_Methods[] = {
1020     { "isOpaque",       lshader_isOpaque },
1021     { "asABitmap",      lshader_asABitmap },
1022     { "asAGradient",    lshader_asAGradient },
1023     { "__gc",           lshader_gc },
1024     { NULL, NULL }
1025 };
1026 
1027 ///////////////////////////////////////////////////////////////////////////////
1028 
lpatheffect_asADash(lua_State * L)1029 static int lpatheffect_asADash(lua_State* L) {
1030     SkPathEffect* pe = get_ref<SkPathEffect>(L, 1);
1031     if (pe) {
1032         SkPathEffect::DashInfo info;
1033         SkPathEffect::DashType dashType = pe->asADash(&info);
1034         if (SkPathEffect::kDash_DashType == dashType) {
1035             SkAutoTArray<SkScalar> intervals(info.fCount);
1036             info.fIntervals = intervals.get();
1037             pe->asADash(&info);
1038             SkLua(L).pushDash(info);
1039             return 1;
1040         }
1041     }
1042     return 0;
1043 }
1044 
lpatheffect_gc(lua_State * L)1045 static int lpatheffect_gc(lua_State* L) {
1046     get_ref<SkPathEffect>(L, 1)->unref();
1047     return 0;
1048 }
1049 
1050 static const struct luaL_Reg gSkPathEffect_Methods[] = {
1051     { "asADash",        lpatheffect_asADash },
1052     { "__gc",           lpatheffect_gc },
1053     { NULL, NULL }
1054 };
1055 
1056 ///////////////////////////////////////////////////////////////////////////////
1057 
lmatrix_getType(lua_State * L)1058 static int lmatrix_getType(lua_State* L) {
1059     SkMatrix::TypeMask mask = get_obj<SkMatrix>(L, 1)->getType();
1060 
1061     lua_newtable(L);
1062     setfield_boolean(L, "translate",   SkToBool(mask & SkMatrix::kTranslate_Mask));
1063     setfield_boolean(L, "scale",       SkToBool(mask & SkMatrix::kScale_Mask));
1064     setfield_boolean(L, "affine",      SkToBool(mask & SkMatrix::kAffine_Mask));
1065     setfield_boolean(L, "perspective", SkToBool(mask & SkMatrix::kPerspective_Mask));
1066     return 1;
1067 }
1068 
lmatrix_getScaleX(lua_State * L)1069 static int lmatrix_getScaleX(lua_State* L) {
1070     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleX());
1071     return 1;
1072 }
1073 
lmatrix_getScaleY(lua_State * L)1074 static int lmatrix_getScaleY(lua_State* L) {
1075     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleY());
1076     return 1;
1077 }
1078 
lmatrix_getTranslateX(lua_State * L)1079 static int lmatrix_getTranslateX(lua_State* L) {
1080     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateX());
1081     return 1;
1082 }
1083 
lmatrix_getTranslateY(lua_State * L)1084 static int lmatrix_getTranslateY(lua_State* L) {
1085     lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateY());
1086     return 1;
1087 }
1088 
1089 static const struct luaL_Reg gSkMatrix_Methods[] = {
1090     { "getType", lmatrix_getType },
1091     { "getScaleX", lmatrix_getScaleX },
1092     { "getScaleY", lmatrix_getScaleY },
1093     { "getTranslateX", lmatrix_getTranslateX },
1094     { "getTranslateY", lmatrix_getTranslateY },
1095     { NULL, NULL }
1096 };
1097 
1098 ///////////////////////////////////////////////////////////////////////////////
1099 
lpath_getBounds(lua_State * L)1100 static int lpath_getBounds(lua_State* L) {
1101     SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
1102     return 1;
1103 }
1104 
fill_type_to_str(SkPath::FillType fill)1105 static const char* fill_type_to_str(SkPath::FillType fill) {
1106     switch (fill) {
1107         case SkPath::kEvenOdd_FillType:
1108             return "even-odd";
1109         case SkPath::kWinding_FillType:
1110             return "winding";
1111         case SkPath::kInverseEvenOdd_FillType:
1112             return "inverse-even-odd";
1113         case SkPath::kInverseWinding_FillType:
1114             return "inverse-winding";
1115     }
1116     return "unknown";
1117 }
1118 
lpath_getFillType(lua_State * L)1119 static int lpath_getFillType(lua_State* L) {
1120     SkPath::FillType fill = get_obj<SkPath>(L, 1)->getFillType();
1121     SkLua(L).pushString(fill_type_to_str(fill));
1122     return 1;
1123 }
1124 
segment_masks_to_str(uint32_t segmentMasks)1125 static SkString segment_masks_to_str(uint32_t segmentMasks) {
1126     SkString result;
1127     bool first = true;
1128     if (SkPath::kLine_SegmentMask & segmentMasks) {
1129         result.append("line");
1130         first = false;
1131         SkDEBUGCODE(segmentMasks &= ~SkPath::kLine_SegmentMask;)
1132     }
1133     if (SkPath::kQuad_SegmentMask & segmentMasks) {
1134         if (!first) {
1135             result.append(" ");
1136         }
1137         result.append("quad");
1138         first = false;
1139         SkDEBUGCODE(segmentMasks &= ~SkPath::kQuad_SegmentMask;)
1140     }
1141     if (SkPath::kConic_SegmentMask & segmentMasks) {
1142         if (!first) {
1143             result.append(" ");
1144         }
1145         result.append("conic");
1146         first = false;
1147         SkDEBUGCODE(segmentMasks &= ~SkPath::kConic_SegmentMask;)
1148     }
1149     if (SkPath::kCubic_SegmentMask & segmentMasks) {
1150         if (!first) {
1151             result.append(" ");
1152         }
1153         result.append("cubic");
1154         SkDEBUGCODE(segmentMasks &= ~SkPath::kCubic_SegmentMask;)
1155     }
1156     SkASSERT(0 == segmentMasks);
1157     return result;
1158 }
1159 
lpath_getSegementTypes(lua_State * L)1160 static int lpath_getSegementTypes(lua_State* L) {
1161     uint32_t segMasks = get_obj<SkPath>(L, 1)->getSegmentMasks();
1162     SkLua(L).pushString(segment_masks_to_str(segMasks));
1163     return 1;
1164 }
1165 
lpath_isConvex(lua_State * L)1166 static int lpath_isConvex(lua_State* L) {
1167     bool isConvex = SkPath::kConvex_Convexity == get_obj<SkPath>(L, 1)->getConvexity();
1168     SkLua(L).pushBool(isConvex);
1169     return 1;
1170 }
1171 
lpath_isEmpty(lua_State * L)1172 static int lpath_isEmpty(lua_State* L) {
1173     lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
1174     return 1;
1175 }
1176 
lpath_isRect(lua_State * L)1177 static int lpath_isRect(lua_State* L) {
1178     SkRect r;
1179     bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
1180     int ret_count = 1;
1181     lua_pushboolean(L, pred);
1182     if (pred) {
1183         SkLua(L).pushRect(r);
1184         ret_count += 1;
1185     }
1186     return ret_count;
1187 }
1188 
dir2string(SkPath::Direction dir)1189 static const char* dir2string(SkPath::Direction dir) {
1190     static const char* gStr[] = {
1191         "unknown", "cw", "ccw"
1192     };
1193     SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
1194     return gStr[dir];
1195 }
1196 
lpath_isNestedRects(lua_State * L)1197 static int lpath_isNestedRects(lua_State* L) {
1198     SkRect rects[2];
1199     SkPath::Direction dirs[2];
1200     bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
1201     int ret_count = 1;
1202     lua_pushboolean(L, pred);
1203     if (pred) {
1204         SkLua lua(L);
1205         lua.pushRect(rects[0]);
1206         lua.pushRect(rects[1]);
1207         lua_pushstring(L, dir2string(dirs[0]));
1208         lua_pushstring(L, dir2string(dirs[0]));
1209         ret_count += 4;
1210     }
1211     return ret_count;
1212 }
1213 
lpath_countPoints(lua_State * L)1214 static int lpath_countPoints(lua_State* L) {
1215     lua_pushinteger(L, get_obj<SkPath>(L, 1)->countPoints());
1216     return 1;
1217 }
1218 
lpath_reset(lua_State * L)1219 static int lpath_reset(lua_State* L) {
1220     get_obj<SkPath>(L, 1)->reset();
1221     return 0;
1222 }
1223 
lpath_moveTo(lua_State * L)1224 static int lpath_moveTo(lua_State* L) {
1225     get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
1226     return 0;
1227 }
1228 
lpath_lineTo(lua_State * L)1229 static int lpath_lineTo(lua_State* L) {
1230     get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
1231     return 0;
1232 }
1233 
lpath_quadTo(lua_State * L)1234 static int lpath_quadTo(lua_State* L) {
1235     get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
1236                                   lua2scalar(L, 4), lua2scalar(L, 5));
1237     return 0;
1238 }
1239 
lpath_cubicTo(lua_State * L)1240 static int lpath_cubicTo(lua_State* L) {
1241     get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
1242                                    lua2scalar(L, 4), lua2scalar(L, 5),
1243                                    lua2scalar(L, 6), lua2scalar(L, 7));
1244     return 0;
1245 }
1246 
lpath_close(lua_State * L)1247 static int lpath_close(lua_State* L) {
1248     get_obj<SkPath>(L, 1)->close();
1249     return 0;
1250 }
1251 
lpath_gc(lua_State * L)1252 static int lpath_gc(lua_State* L) {
1253     get_obj<SkPath>(L, 1)->~SkPath();
1254     return 0;
1255 }
1256 
1257 static const struct luaL_Reg gSkPath_Methods[] = {
1258     { "getBounds", lpath_getBounds },
1259     { "getFillType", lpath_getFillType },
1260     { "getSegmentTypes", lpath_getSegementTypes },
1261     { "isConvex", lpath_isConvex },
1262     { "isEmpty", lpath_isEmpty },
1263     { "isRect", lpath_isRect },
1264     { "isNestedRects", lpath_isNestedRects },
1265     { "countPoints", lpath_countPoints },
1266     { "reset", lpath_reset },
1267     { "moveTo", lpath_moveTo },
1268     { "lineTo", lpath_lineTo },
1269     { "quadTo", lpath_quadTo },
1270     { "cubicTo", lpath_cubicTo },
1271     { "close", lpath_close },
1272     { "__gc", lpath_gc },
1273     { NULL, NULL }
1274 };
1275 
1276 ///////////////////////////////////////////////////////////////////////////////
1277 
rrect_type(const SkRRect & rr)1278 static const char* rrect_type(const SkRRect& rr) {
1279     switch (rr.getType()) {
1280         case SkRRect::kUnknown_Type: return "unknown";
1281         case SkRRect::kEmpty_Type: return "empty";
1282         case SkRRect::kRect_Type: return "rect";
1283         case SkRRect::kOval_Type: return "oval";
1284         case SkRRect::kSimple_Type: return "simple";
1285         case SkRRect::kNinePatch_Type: return "nine-patch";
1286         case SkRRect::kComplex_Type: return "complex";
1287     }
1288     SkDEBUGFAIL("never get here");
1289     return "";
1290 }
1291 
lrrect_rect(lua_State * L)1292 static int lrrect_rect(lua_State* L) {
1293     SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
1294     return 1;
1295 }
1296 
lrrect_type(lua_State * L)1297 static int lrrect_type(lua_State* L) {
1298     lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
1299     return 1;
1300 }
1301 
lrrect_radii(lua_State * L)1302 static int lrrect_radii(lua_State* L) {
1303     int corner = SkToInt(lua_tointeger(L, 2));
1304     SkVector v;
1305     if (corner < 0 || corner > 3) {
1306         SkDebugf("bad corner index %d", corner);
1307         v.set(0, 0);
1308     } else {
1309         v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
1310     }
1311     lua_pushnumber(L, v.fX);
1312     lua_pushnumber(L, v.fY);
1313     return 2;
1314 }
1315 
lrrect_gc(lua_State * L)1316 static int lrrect_gc(lua_State* L) {
1317     get_obj<SkRRect>(L, 1)->~SkRRect();
1318     return 0;
1319 }
1320 
1321 static const struct luaL_Reg gSkRRect_Methods[] = {
1322     { "rect", lrrect_rect },
1323     { "type", lrrect_type },
1324     { "radii", lrrect_radii },
1325     { "__gc", lrrect_gc },
1326     { NULL, NULL }
1327 };
1328 
1329 ///////////////////////////////////////////////////////////////////////////////
1330 
limage_width(lua_State * L)1331 static int limage_width(lua_State* L) {
1332     lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
1333     return 1;
1334 }
1335 
limage_height(lua_State * L)1336 static int limage_height(lua_State* L) {
1337     lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
1338     return 1;
1339 }
1340 
limage_gc(lua_State * L)1341 static int limage_gc(lua_State* L) {
1342     get_ref<SkImage>(L, 1)->unref();
1343     return 0;
1344 }
1345 
1346 static const struct luaL_Reg gSkImage_Methods[] = {
1347     { "width", limage_width },
1348     { "height", limage_height },
1349     { "__gc", limage_gc },
1350     { NULL, NULL }
1351 };
1352 
1353 ///////////////////////////////////////////////////////////////////////////////
1354 
ltypeface_gc(lua_State * L)1355 static int ltypeface_gc(lua_State* L) {
1356     SkSafeUnref(get_ref<SkTypeface>(L, 1));
1357     return 0;
1358 }
1359 
1360 static const struct luaL_Reg gSkTypeface_Methods[] = {
1361     { "__gc", ltypeface_gc },
1362     { NULL, NULL }
1363 };
1364 
1365 ///////////////////////////////////////////////////////////////////////////////
1366 
1367 class AutoCallLua {
1368 public:
AutoCallLua(lua_State * L,const char func[],const char verb[])1369     AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
1370         lua_getglobal(L, func);
1371         if (!lua_isfunction(L, -1)) {
1372             int t = lua_type(L, -1);
1373             SkDebugf("--- expected function %d\n", t);
1374         }
1375 
1376         lua_newtable(L);
1377         setfield_string(L, "verb", verb);
1378     }
1379 
~AutoCallLua()1380     ~AutoCallLua() {
1381         if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
1382             SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
1383         }
1384         lua_settop(fL, -1);
1385     }
1386 
1387 private:
1388     lua_State* fL;
1389 };
1390 
1391 #define AUTO_LUA(verb)  AutoCallLua acl(fL, fFunc.c_str(), verb)
1392 
1393 ///////////////////////////////////////////////////////////////////////////////
1394 
lsk_newDocumentPDF(lua_State * L)1395 static int lsk_newDocumentPDF(lua_State* L) {
1396     const char* file = NULL;
1397     if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
1398         file = lua_tolstring(L, 1, NULL);
1399     }
1400 
1401     SkDocument* doc = SkDocument::CreatePDF(file);
1402     if (NULL == doc) {
1403         // do I need to push a nil on the stack and return 1?
1404         return 0;
1405     } else {
1406         push_ref(L, doc);
1407         doc->unref();
1408         return 1;
1409     }
1410 }
1411 
lsk_newPaint(lua_State * L)1412 static int lsk_newPaint(lua_State* L) {
1413     push_new<SkPaint>(L);
1414     return 1;
1415 }
1416 
lsk_newPath(lua_State * L)1417 static int lsk_newPath(lua_State* L) {
1418     push_new<SkPath>(L);
1419     return 1;
1420 }
1421 
lsk_newRRect(lua_State * L)1422 static int lsk_newRRect(lua_State* L) {
1423     SkRRect* rr = push_new<SkRRect>(L);
1424     rr->setEmpty();
1425     return 1;
1426 }
1427 
lsk_newTypeface(lua_State * L)1428 static int lsk_newTypeface(lua_State* L) {
1429     const char* name = NULL;
1430     int style = SkTypeface::kNormal;
1431 
1432     int count = lua_gettop(L);
1433     if (count > 0 && lua_isstring(L, 1)) {
1434         name = lua_tolstring(L, 1, NULL);
1435         if (count > 1 && lua_isnumber(L, 2)) {
1436             style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
1437         }
1438     }
1439 
1440     SkTypeface* face = SkTypeface::CreateFromName(name,
1441                                                   (SkTypeface::Style)style);
1442 //    SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
1443     if (NULL == face) {
1444         face = SkTypeface::RefDefault();
1445     }
1446     push_ref(L, face);
1447     face->unref();
1448     return 1;
1449 }
1450 
lsk_loadImage(lua_State * L)1451 static int lsk_loadImage(lua_State* L) {
1452     if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
1453         const char* name = lua_tolstring(L, 1, NULL);
1454         SkAutoDataUnref data(SkData::NewFromFileName(name));
1455         if (data.get()) {
1456             SkImage* image = SkImage::NewEncodedData(data.get());
1457             if (image) {
1458                 push_ref(L, image);
1459                 image->unref();
1460                 return 1;
1461             }
1462         }
1463     }
1464     return 0;
1465 }
1466 
register_Sk(lua_State * L)1467 static void register_Sk(lua_State* L) {
1468     lua_newtable(L);
1469     lua_pushvalue(L, -1);
1470     lua_setglobal(L, "Sk");
1471     // the Sk table is still on top
1472 
1473     setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
1474     setfield_function(L, "loadImage", lsk_loadImage);
1475     setfield_function(L, "newPaint", lsk_newPaint);
1476     setfield_function(L, "newPath", lsk_newPath);
1477     setfield_function(L, "newRRect", lsk_newRRect);
1478     setfield_function(L, "newTypeface", lsk_newTypeface);
1479     lua_pop(L, 1);  // pop off the Sk table
1480 }
1481 
1482 #define REG_CLASS(L, C)                             \
1483     do {                                            \
1484         luaL_newmetatable(L, get_mtname<C>());      \
1485         lua_pushvalue(L, -1);                       \
1486         lua_setfield(L, -2, "__index");             \
1487         luaL_setfuncs(L, g##C##_Methods, 0);        \
1488         lua_pop(L, 1); /* pop off the meta-table */ \
1489     } while (0)
1490 
Load(lua_State * L)1491 void SkLua::Load(lua_State* L) {
1492     register_Sk(L);
1493     REG_CLASS(L, SkCanvas);
1494     REG_CLASS(L, SkDocument);
1495     REG_CLASS(L, SkImage);
1496     REG_CLASS(L, SkPaint);
1497     REG_CLASS(L, SkPath);
1498     REG_CLASS(L, SkPathEffect);
1499     REG_CLASS(L, SkRRect);
1500     REG_CLASS(L, SkShader);
1501     REG_CLASS(L, SkTypeface);
1502     REG_CLASS(L, SkMatrix);
1503 }
1504 
1505 extern "C" int luaopen_skia(lua_State* L);
luaopen_skia(lua_State * L)1506 extern "C" int luaopen_skia(lua_State* L) {
1507     SkLua::Load(L);
1508     return 0;
1509 }
1510