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