blob: 99b157a2bee786fd95096a4cb9e9ea331077423a [file] [log] [blame]
reed@google.com74ce6f02013-05-22 15:13:18 +00001/*
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#include "SkCanvas.h"
mike@reedtribe.orgfb858242013-06-08 16:39:44 +000010#include "SkDocument.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000011#include "SkPaint.h"
12#include "SkPath.h"
13#include "SkMatrix.h"
14#include "SkRRect.h"
15#include "SkString.h"
reed@google.come3823fd2013-05-30 18:55:14 +000016#include "SkTypeface.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000017
18extern "C" {
reed@google.com3597b732013-05-22 20:12:50 +000019 #include "lua.h"
20 #include "lualib.h"
21 #include "lauxlib.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000022}
23
reed@google.comfd345872013-05-22 20:53:42 +000024// return the metatable name for a given class
reed@google.com3597b732013-05-22 20:12:50 +000025template <typename T> const char* get_mtname();
reed@google.comfd345872013-05-22 20:53:42 +000026#define DEF_MTNAME(T) \
27 template <> const char* get_mtname<T>() { \
28 return #T "_LuaMetaTableName"; \
29 }
30
31DEF_MTNAME(SkCanvas)
mike@reedtribe.orgfb858242013-06-08 16:39:44 +000032DEF_MTNAME(SkDocument)
reed@google.comfd345872013-05-22 20:53:42 +000033DEF_MTNAME(SkMatrix)
34DEF_MTNAME(SkRRect)
35DEF_MTNAME(SkPath)
36DEF_MTNAME(SkPaint)
mike@reedtribe.orge6469f12013-06-08 03:15:47 +000037DEF_MTNAME(SkTypeface)
reed@google.com74ce6f02013-05-22 15:13:18 +000038
reed@google.com3597b732013-05-22 20:12:50 +000039template <typename T> T* push_new(lua_State* L) {
40 T* addr = (T*)lua_newuserdata(L, sizeof(T));
41 new (addr) T;
42 luaL_getmetatable(L, get_mtname<T>());
43 lua_setmetatable(L, -2);
44 return addr;
45}
reed@google.com74ce6f02013-05-22 15:13:18 +000046
47template <typename T> void push_obj(lua_State* L, const T& obj) {
48 new (lua_newuserdata(L, sizeof(T))) T(obj);
reed@google.com3597b732013-05-22 20:12:50 +000049 luaL_getmetatable(L, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000050 lua_setmetatable(L, -2);
51}
52
53template <typename T> void push_ref(lua_State* L, T* ref) {
54 *(T**)lua_newuserdata(L, sizeof(T*)) = SkRef(ref);
reed@google.com3597b732013-05-22 20:12:50 +000055 luaL_getmetatable(L, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000056 lua_setmetatable(L, -2);
57}
58
59template <typename T> T* get_ref(lua_State* L, int index) {
reed@google.com3597b732013-05-22 20:12:50 +000060 return *(T**)luaL_checkudata(L, index, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000061}
62
63template <typename T> T* get_obj(lua_State* L, int index) {
reed@google.com3597b732013-05-22 20:12:50 +000064 return (T*)luaL_checkudata(L, index, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000065}
66
reed@google.com88c9ec92013-05-22 15:43:21 +000067static bool lua2bool(lua_State* L, int index) {
68 return !!lua_toboolean(L, index);
69}
70
reed@google.com74ce6f02013-05-22 15:13:18 +000071///////////////////////////////////////////////////////////////////////////////
72
reed@google.com3597b732013-05-22 20:12:50 +000073SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) {
74 fL = luaL_newstate();
75 luaL_openlibs(fL);
76 SkLua::Load(fL);
77}
78
79SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {}
80
81SkLua::~SkLua() {
82 if (fWeOwnL) {
83 if (fTermCode.size() > 0) {
84 lua_getglobal(fL, fTermCode.c_str());
85 if (lua_pcall(fL, 0, 0, 0) != LUA_OK) {
86 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
87 }
88 }
89 lua_close(fL);
90 }
91}
92
93bool SkLua::runCode(const char code[]) {
94 int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0);
95 if (err) {
96 SkDebugf("--- lua failed\n");
97 return false;
98 }
99 return true;
100}
101
102bool SkLua::runCode(const void* code, size_t size) {
103 SkString str((const char*)code, size);
104 return this->runCode(str.c_str());
105}
106
107///////////////////////////////////////////////////////////////////////////////
108
109#define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0)
110
reed@google.com74ce6f02013-05-22 15:13:18 +0000111static void setfield_string(lua_State* L, const char key[], const char value[]) {
112 lua_pushstring(L, value);
113 lua_setfield(L, -2, key);
114}
115
116static void setfield_number(lua_State* L, const char key[], double value) {
117 lua_pushnumber(L, value);
118 lua_setfield(L, -2, key);
119}
120
reed@google.com3597b732013-05-22 20:12:50 +0000121static void setfield_function(lua_State* L,
122 const char key[], lua_CFunction value) {
123 lua_pushcfunction(L, value);
124 lua_setfield(L, -2, key);
reed@google.com74ce6f02013-05-22 15:13:18 +0000125}
126
reed@google.come3823fd2013-05-30 18:55:14 +0000127static void setarray_number(lua_State* L, int index, double value) {
128 lua_pushnumber(L, value);
129 lua_rawseti(L, -2, index);
130}
131
reed@google.com74ce6f02013-05-22 15:13:18 +0000132void SkLua::pushBool(bool value, const char key[]) {
133 lua_pushboolean(fL, value);
134 CHECK_SETFIELD(key);
135}
136
137void SkLua::pushString(const char str[], const char key[]) {
138 lua_pushstring(fL, str);
139 CHECK_SETFIELD(key);
140}
141
reed@google.come3823fd2013-05-30 18:55:14 +0000142void SkLua::pushString(const char str[], size_t length, const char key[]) {
143 // TODO: how to do this w/o making a copy?
144 SkString s(str, length);
145 lua_pushstring(fL, s.c_str());
146 CHECK_SETFIELD(key);
147}
148
reed@google.com74ce6f02013-05-22 15:13:18 +0000149void SkLua::pushString(const SkString& str, const char key[]) {
150 lua_pushstring(fL, str.c_str());
151 CHECK_SETFIELD(key);
152}
153
154void SkLua::pushColor(SkColor color, const char key[]) {
155 lua_newtable(fL);
156 setfield_number(fL, "a", SkColorGetA(color) / 255.0);
157 setfield_number(fL, "r", SkColorGetR(color) / 255.0);
158 setfield_number(fL, "g", SkColorGetG(color) / 255.0);
159 setfield_number(fL, "b", SkColorGetB(color) / 255.0);
160 CHECK_SETFIELD(key);
161}
162
reed@google.come3823fd2013-05-30 18:55:14 +0000163void SkLua::pushU32(uint32_t value, const char key[]) {
164 lua_pushnumber(fL, (double)value);
165 CHECK_SETFIELD(key);
166}
167
reed@google.com74ce6f02013-05-22 15:13:18 +0000168void SkLua::pushScalar(SkScalar value, const char key[]) {
169 lua_pushnumber(fL, SkScalarToLua(value));
170 CHECK_SETFIELD(key);
171}
172
reed@google.come3823fd2013-05-30 18:55:14 +0000173void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
174 lua_newtable(fL);
175 for (int i = 0; i < count; ++i) {
176 // make it base-1 to match lua convention
177 setarray_number(fL, i + 1, (double)array[i]);
178 }
179 CHECK_SETFIELD(key);
180}
181
reed@google.com74ce6f02013-05-22 15:13:18 +0000182void SkLua::pushRect(const SkRect& r, const char key[]) {
183 lua_newtable(fL);
184 setfield_number(fL, "left", SkScalarToLua(r.fLeft));
185 setfield_number(fL, "top", SkScalarToLua(r.fTop));
186 setfield_number(fL, "right", SkScalarToLua(r.fRight));
187 setfield_number(fL, "bottom", SkScalarToLua(r.fBottom));
188 CHECK_SETFIELD(key);
189}
190
191void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
192 push_obj(fL, rr);
193 CHECK_SETFIELD(key);
194}
195
196void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
197 push_obj(fL, matrix);
198 CHECK_SETFIELD(key);
199}
200
201void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
202 push_obj(fL, paint);
203 CHECK_SETFIELD(key);
204}
205
206void SkLua::pushPath(const SkPath& path, const char key[]) {
207 push_obj(fL, path);
208 CHECK_SETFIELD(key);
209}
210
211void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
212 push_ref(fL, canvas);
213 CHECK_SETFIELD(key);
214}
215
216///////////////////////////////////////////////////////////////////////////////
217///////////////////////////////////////////////////////////////////////////////
218
219static SkScalar lua2scalar(lua_State* L, int index) {
220 SkASSERT(lua_isnumber(L, index));
221 return SkLuaToScalar(lua_tonumber(L, index));
222}
223
224static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
225 SkASSERT(lua_istable(L, index));
226 lua_pushstring(L, key);
227 lua_gettable(L, index);
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000228
reed@google.com74ce6f02013-05-22 15:13:18 +0000229 SkScalar value = lua2scalar(L, -1);
230 lua_pop(L, 1);
231 return value;
232}
233
234static U8CPU unit2byte(SkScalar x) {
235 if (x <= 0) {
236 return 0;
237 } else if (x >= 1) {
238 return 255;
239 } else {
240 return SkScalarRoundToInt(x * 255);
241 }
242}
243
244static SkColor lua2color(lua_State* L, int index) {
245 return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
246 unit2byte(getfield_scalar(L, index, "r")),
247 unit2byte(getfield_scalar(L, index, "g")),
248 unit2byte(getfield_scalar(L, index, "b")));
249}
250
251static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
252 rect->set(getfield_scalar(L, index, "left"),
253 getfield_scalar(L, index, "top"),
254 getfield_scalar(L, index, "right"),
255 getfield_scalar(L, index, "bottom"));
256 return rect;
257}
258
259static int lcanvas_drawColor(lua_State* L) {
260 get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
261 return 0;
262}
263
264static int lcanvas_drawRect(lua_State* L) {
265 SkRect rect;
266 get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
267 *get_obj<SkPaint>(L, 3));
268 return 0;
269}
270
271static int lcanvas_drawOval(lua_State* L) {
272 SkRect rect;
273 get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
274 *get_obj<SkPaint>(L, 3));
275 return 0;
276}
277
278static int lcanvas_drawCircle(lua_State* L) {
279 get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
280 lua2scalar(L, 3),
281 lua2scalar(L, 4),
282 *get_obj<SkPaint>(L, 5));
283 return 0;
284}
285
reed@google.comfd345872013-05-22 20:53:42 +0000286static int lcanvas_drawPath(lua_State* L) {
287 get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
288 *get_obj<SkPaint>(L, 3));
289 return 0;
290}
291
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000292static int lcanvas_drawText(lua_State* L) {
293 if (lua_gettop(L) < 5) {
294 return 0;
295 }
296
297 if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
298 size_t len;
299 const char* text = lua_tolstring(L, 2, &len);
300 get_ref<SkCanvas>(L, 1)->drawText(text, len,
301 lua2scalar(L, 3), lua2scalar(L, 4),
302 *get_obj<SkPaint>(L, 5));
303 }
304 return 0;
305}
306
reed@google.com74ce6f02013-05-22 15:13:18 +0000307static int lcanvas_getSaveCount(lua_State* L) {
308 lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
309 return 1;
310}
311
312static int lcanvas_getTotalMatrix(lua_State* L) {
313 SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
314 return 1;
315}
316
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000317static int lcanvas_save(lua_State* L) {
318 lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
319 return 1;
320}
321
322static int lcanvas_restore(lua_State* L) {
323 get_ref<SkCanvas>(L, 1)->restore();
324 return 0;
325}
326
reed@google.com3597b732013-05-22 20:12:50 +0000327static int lcanvas_translate(lua_State* L) {
328 get_ref<SkCanvas>(L, 1)->translate(lua2scalar(L, 2), lua2scalar(L, 3));
329 return 0;
330}
331
reed@google.com74ce6f02013-05-22 15:13:18 +0000332static int lcanvas_gc(lua_State* L) {
333 get_ref<SkCanvas>(L, 1)->unref();
334 return 0;
335}
336
337static const struct luaL_Reg gSkCanvas_Methods[] = {
338 { "drawColor", lcanvas_drawColor },
339 { "drawRect", lcanvas_drawRect },
340 { "drawOval", lcanvas_drawOval },
341 { "drawCircle", lcanvas_drawCircle },
reed@google.comfd345872013-05-22 20:53:42 +0000342 { "drawPath", lcanvas_drawPath },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000343 { "drawText", lcanvas_drawText },
reed@google.com74ce6f02013-05-22 15:13:18 +0000344 { "getSaveCount", lcanvas_getSaveCount },
345 { "getTotalMatrix", lcanvas_getTotalMatrix },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000346 { "save", lcanvas_save },
347 { "restore", lcanvas_restore },
reed@google.com3597b732013-05-22 20:12:50 +0000348 { "translate", lcanvas_translate },
reed@google.com74ce6f02013-05-22 15:13:18 +0000349 { "__gc", lcanvas_gc },
350 { NULL, NULL }
351};
352
353///////////////////////////////////////////////////////////////////////////////
354
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000355static int ldocument_beginPage(lua_State* L) {
356 const SkRect* contentPtr = NULL;
357 push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
358 lua2scalar(L, 3),
359 contentPtr));
360 return 1;
361}
362
363static int ldocument_endPage(lua_State* L) {
364 get_ref<SkDocument>(L, 1)->endPage();
365 return 0;
366}
367
368static int ldocument_close(lua_State* L) {
369 get_ref<SkDocument>(L, 1)->close();
370 return 0;
371}
372
373static int ldocument_gc(lua_State* L) {
374 get_ref<SkDocument>(L, 1)->unref();
375 return 0;
376}
377
378static const struct luaL_Reg gSkDocument_Methods[] = {
379 { "beginPage", ldocument_beginPage },
380 { "endPage", ldocument_endPage },
381 { "close", ldocument_close },
382 { "__gc", ldocument_gc },
383 { NULL, NULL }
384};
385
386///////////////////////////////////////////////////////////////////////////////
387
reed@google.com74ce6f02013-05-22 15:13:18 +0000388static int lpaint_isAntiAlias(lua_State* L) {
389 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
390 return 1;
391}
392
393static int lpaint_setAntiAlias(lua_State* L) {
reed@google.com88c9ec92013-05-22 15:43:21 +0000394 get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
reed@google.com74ce6f02013-05-22 15:13:18 +0000395 return 0;
396}
397
398static int lpaint_getColor(lua_State* L) {
399 SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
400 return 1;
401}
402
403static int lpaint_setColor(lua_State* L) {
404 get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
405 return 0;
406}
407
reed@google.come3823fd2013-05-30 18:55:14 +0000408static int lpaint_getTextSize(lua_State* L) {
409 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
410 return 1;
411}
412
413static int lpaint_setTextSize(lua_State* L) {
414 get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
415 return 0;
416}
417
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000418static int lpaint_getTypeface(lua_State* L) {
419 push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
420 return 1;
421}
422
423static int lpaint_setTypeface(lua_State* L) {
424 get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
425 return 0;
426}
427
reed@google.come3823fd2013-05-30 18:55:14 +0000428static int lpaint_getFontID(lua_State* L) {
429 SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
430 SkLua(L).pushU32(SkTypeface::UniqueID(face));
431 return 1;
432}
433
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000434static const struct {
435 const char* fLabel;
436 SkPaint::Align fAlign;
437} gAlignRec[] = {
438 { "left", SkPaint::kLeft_Align },
439 { "center", SkPaint::kCenter_Align },
440 { "right", SkPaint::kRight_Align },
441};
442
443static int lpaint_getTextAlign(lua_State* L) {
444 SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
445 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
446 if (gAlignRec[i].fAlign == align) {
447 lua_pushstring(L, gAlignRec[i].fLabel);
448 return 1;
449 }
450 }
451 return 0;
452}
453
454static int lpaint_setTextAlign(lua_State* L) {
455 if (lua_isstring(L, 2)) {
456 size_t len;
457 const char* label = lua_tolstring(L, 2, &len);
458
459 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
460 if (!strcmp(gAlignRec[i].fLabel, label)) {
461 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
462 break;
463 }
464 }
465 }
466 return 0;
467}
468
reed@google.com74ce6f02013-05-22 15:13:18 +0000469static int lpaint_gc(lua_State* L) {
470 get_obj<SkPaint>(L, 1)->~SkPaint();
471 return 0;
472}
473
474static const struct luaL_Reg gSkPaint_Methods[] = {
475 { "isAntiAlias", lpaint_isAntiAlias },
476 { "setAntiAlias", lpaint_setAntiAlias },
477 { "getColor", lpaint_getColor },
478 { "setColor", lpaint_setColor },
reed@google.come3823fd2013-05-30 18:55:14 +0000479 { "getTextSize", lpaint_getTextSize },
480 { "setTextSize", lpaint_setTextSize },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000481 { "getTypeface", lpaint_getTypeface },
482 { "setTypeface", lpaint_setTypeface },
reed@google.come3823fd2013-05-30 18:55:14 +0000483 { "getFontID", lpaint_getFontID },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000484 { "getTextAlign", lpaint_getTextAlign },
485 { "setTextAlign", lpaint_setTextAlign },
reed@google.com74ce6f02013-05-22 15:13:18 +0000486 { "__gc", lpaint_gc },
487 { NULL, NULL }
488};
489
490///////////////////////////////////////////////////////////////////////////////
491
492static int lpath_getBounds(lua_State* L) {
493 SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
494 return 1;
495}
496
497static int lpath_isEmpty(lua_State* L) {
498 lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
499 return 1;
500}
501
502static int lpath_isRect(lua_State* L) {
503 SkRect r;
504 bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
505 int ret_count = 1;
506 lua_pushboolean(L, pred);
507 if (pred) {
508 SkLua(L).pushRect(r);
509 ret_count += 1;
510 }
511 return ret_count;
512}
513
514static const char* dir2string(SkPath::Direction dir) {
515 static const char* gStr[] = {
516 "unknown", "cw", "ccw"
517 };
518 SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
519 return gStr[dir];
520}
521
522static int lpath_isNestedRects(lua_State* L) {
523 SkRect rects[2];
524 SkPath::Direction dirs[2];
525 bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
526 int ret_count = 1;
527 lua_pushboolean(L, pred);
528 if (pred) {
529 SkLua lua(L);
530 lua.pushRect(rects[0]);
531 lua.pushRect(rects[1]);
532 lua_pushstring(L, dir2string(dirs[0]));
533 lua_pushstring(L, dir2string(dirs[0]));
534 ret_count += 4;
535 }
536 return ret_count;
537}
538
539static int lpath_reset(lua_State* L) {
540 get_obj<SkPath>(L, 1)->reset();
541 return 0;
542}
543
544static int lpath_moveTo(lua_State* L) {
545 get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
546 return 0;
547}
548
549static int lpath_lineTo(lua_State* L) {
550 get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
551 return 0;
552}
553
554static int lpath_quadTo(lua_State* L) {
555 get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
556 lua2scalar(L, 4), lua2scalar(L, 5));
557 return 0;
558}
559
560static int lpath_cubicTo(lua_State* L) {
561 get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
562 lua2scalar(L, 4), lua2scalar(L, 5),
563 lua2scalar(L, 6), lua2scalar(L, 7));
564 return 0;
565}
566
567static int lpath_close(lua_State* L) {
568 get_obj<SkPath>(L, 1)->close();
569 return 0;
570}
571
572static int lpath_gc(lua_State* L) {
573 get_obj<SkPath>(L, 1)->~SkPath();
574 return 0;
575}
576
577static const struct luaL_Reg gSkPath_Methods[] = {
578 { "getBounds", lpath_getBounds },
579 { "isEmpty", lpath_isEmpty },
580 { "isRect", lpath_isRect },
581 { "isNestedRects", lpath_isNestedRects },
582 { "reset", lpath_reset },
583 { "moveTo", lpath_moveTo },
584 { "lineTo", lpath_lineTo },
585 { "quadTo", lpath_quadTo },
586 { "cubicTo", lpath_cubicTo },
587 { "close", lpath_close },
588 { "__gc", lpath_gc },
589 { NULL, NULL }
590};
591
592///////////////////////////////////////////////////////////////////////////////
593
594static const char* rrect_type(const SkRRect& rr) {
595 switch (rr.getType()) {
596 case SkRRect::kUnknown_Type: return "unknown";
597 case SkRRect::kEmpty_Type: return "empty";
598 case SkRRect::kRect_Type: return "rect";
599 case SkRRect::kOval_Type: return "oval";
600 case SkRRect::kSimple_Type: return "simple";
601 case SkRRect::kComplex_Type: return "complex";
602 }
603 SkASSERT(!"never get here");
604 return "";
605}
606
607static int lrrect_rect(lua_State* L) {
608 SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
609 return 1;
610}
611
612static int lrrect_type(lua_State* L) {
613 lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
614 return 1;
615}
616
617static int lrrect_radii(lua_State* L) {
618 int corner = lua_tointeger(L, 2);
619 SkVector v;
620 if (corner < 0 || corner > 3) {
621 SkDebugf("bad corner index %d", corner);
622 v.set(0, 0);
623 } else {
624 v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
625 }
626 lua_pushnumber(L, v.fX);
627 lua_pushnumber(L, v.fY);
628 return 2;
629}
630
631static int lrrect_gc(lua_State* L) {
632 get_obj<SkRRect>(L, 1)->~SkRRect();
633 return 0;
634}
635
636static const struct luaL_Reg gSkRRect_Methods[] = {
637 { "rect", lrrect_rect },
638 { "type", lrrect_type },
639 { "radii", lrrect_radii },
640 { "__gc", lrrect_gc },
641 { NULL, NULL }
642};
643
644///////////////////////////////////////////////////////////////////////////////
645
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000646static int ltypeface_gc(lua_State* L) {
647 get_ref<SkTypeface>(L, 1)->unref();
648 return 0;
649}
650
651static const struct luaL_Reg gSkTypeface_Methods[] = {
652 { "__gc", ltypeface_gc },
653 { NULL, NULL }
654};
655
656///////////////////////////////////////////////////////////////////////////////
657
reed@google.com74ce6f02013-05-22 15:13:18 +0000658class AutoCallLua {
659public:
660 AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
661 lua_getglobal(L, func);
662 if (!lua_isfunction(L, -1)) {
663 int t = lua_type(L, -1);
664 SkDebugf("--- expected function %d\n", t);
665 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000666
reed@google.com74ce6f02013-05-22 15:13:18 +0000667 lua_newtable(L);
668 setfield_string(L, "verb", verb);
669 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000670
reed@google.com74ce6f02013-05-22 15:13:18 +0000671 ~AutoCallLua() {
672 if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
673 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
674 }
675 lua_settop(fL, -1);
676 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000677
reed@google.com74ce6f02013-05-22 15:13:18 +0000678private:
679 lua_State* fL;
680};
681
682#define AUTO_LUA(verb) AutoCallLua acl(fL, fFunc.c_str(), verb)
683
684///////////////////////////////////////////////////////////////////////////////
685
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000686static int lsk_newDocumentPDF(lua_State* L) {
687 const char* file = NULL;
688 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
689 file = lua_tolstring(L, 1, NULL);
690 }
691
692 SkDocument* doc = SkDocument::CreatePDF(file);
693 if (NULL == doc) {
694 // do I need to push a nil on the stack and return 1?
695 return 0;
696 } else {
697 push_ref(L, doc);
698 doc->unref();
699 return 1;
700 }
701}
702
reed@google.com3597b732013-05-22 20:12:50 +0000703static int lsk_newPaint(lua_State* L) {
704 push_new<SkPaint>(L);
705 return 1;
706}
707
708static int lsk_newPath(lua_State* L) {
709 push_new<SkPath>(L);
710 return 1;
711}
712
713static int lsk_newRRect(lua_State* L) {
714 SkRRect* rr = push_new<SkRRect>(L);
715 rr->setEmpty();
716 return 1;
717}
718
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000719static int lsk_newTypeface(lua_State* L) {
720 const char* name = NULL;
721 int style = SkTypeface::kNormal;
skia.committer@gmail.com63193672013-06-08 07:01:13 +0000722
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000723 int count = lua_gettop(L);
724 if (count > 0 && lua_isstring(L, 1)) {
725 name = lua_tolstring(L, 1, NULL);
726 if (count > 1 && lua_isnumber(L, 2)) {
727 style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
728 }
729 }
730
731 SkTypeface* face = SkTypeface::CreateFromName(name,
732 (SkTypeface::Style)style);
733// SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
734 if (NULL == face) {
735 face = SkTypeface::RefDefault();
736 }
737 push_ref(L, face);
738 face->unref();
739 return 1;
740}
reed@google.com3597b732013-05-22 20:12:50 +0000741
742static void register_Sk(lua_State* L) {
743 lua_newtable(L);
744 lua_pushvalue(L, -1);
745 lua_setglobal(L, "Sk");
746 // the Sk table is still on top
747
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000748 setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
reed@google.com3597b732013-05-22 20:12:50 +0000749 setfield_function(L, "newPaint", lsk_newPaint);
750 setfield_function(L, "newPath", lsk_newPath);
751 setfield_function(L, "newRRect", lsk_newRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000752 setfield_function(L, "newTypeface", lsk_newTypeface);
reed@google.com3597b732013-05-22 20:12:50 +0000753 lua_pop(L, 1); // pop off the Sk table
754}
755
reed@google.com74ce6f02013-05-22 15:13:18 +0000756#define REG_CLASS(L, C) \
757 do { \
reed@google.com3597b732013-05-22 20:12:50 +0000758 luaL_newmetatable(L, get_mtname<C>()); \
reed@google.com74ce6f02013-05-22 15:13:18 +0000759 lua_pushvalue(L, -1); \
760 lua_setfield(L, -2, "__index"); \
761 luaL_setfuncs(L, g##C##_Methods, 0); \
762 lua_pop(L, 1); /* pop off the meta-table */ \
763 } while (0)
764
765void SkLua::Load(lua_State* L) {
reed@google.com3597b732013-05-22 20:12:50 +0000766 register_Sk(L);
reed@google.com74ce6f02013-05-22 15:13:18 +0000767 REG_CLASS(L, SkCanvas);
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000768 REG_CLASS(L, SkDocument);
reed@google.com74ce6f02013-05-22 15:13:18 +0000769 REG_CLASS(L, SkPath);
770 REG_CLASS(L, SkPaint);
771 REG_CLASS(L, SkRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000772 REG_CLASS(L, SkTypeface);
reed@google.com74ce6f02013-05-22 15:13:18 +0000773}