blob: dff79eedb00f0ad14aac055a5ea50a95128ee2c3 [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"
10#include "SkPaint.h"
11#include "SkPath.h"
12#include "SkMatrix.h"
13#include "SkRRect.h"
14#include "SkString.h"
15
16extern "C" {
17#include "lua.h"
18#include "lauxlib.h"
19}
20
21static const char gSkCanvas_MTName[] = "SkCanvas_LuaMetaTableName";
22static const char gSkMatrix_MTName[] = "SkMatrix_LuaMetaTableName";
23static const char gSkRRect_MTName[] = "SkSkRRect_LuaMetaTableName";
24static const char gSkPath_MTName[] = "SkPath_LuaMetaTableName";
25static const char gSkPaint_MTName[] = "SkPaint_LuaMetaTableName";
26
27static const char* get_mtname(const SkCanvas&) { return gSkCanvas_MTName; }
28static const char* get_mtname(const SkMatrix&) { return gSkMatrix_MTName; }
29static const char* get_mtname(const SkRRect&) { return gSkRRect_MTName; }
30static const char* get_mtname(const SkPath&) { return gSkPath_MTName; }
31static const char* get_mtname(const SkPaint&) { return gSkPaint_MTName; }
32
33template <typename T> void push_obj(lua_State* L, const T& obj) {
34 new (lua_newuserdata(L, sizeof(T))) T(obj);
35 luaL_getmetatable(L, get_mtname(obj));
36 lua_setmetatable(L, -2);
37}
38
39template <typename T> void push_ref(lua_State* L, T* ref) {
40 *(T**)lua_newuserdata(L, sizeof(T*)) = SkRef(ref);
41 luaL_getmetatable(L, get_mtname(*ref));
42 lua_setmetatable(L, -2);
43}
44
45template <typename T> T* get_ref(lua_State* L, int index) {
46 const T* ref = NULL;
47 return *(T**)luaL_checkudata(L, index, get_mtname(*ref));
48}
49
50template <typename T> T* get_obj(lua_State* L, int index) {
51 const T* obj = NULL;
52 return (T*)luaL_checkudata(L, index, get_mtname(*obj));
53}
54
55///////////////////////////////////////////////////////////////////////////////
56
57static void setfield_string(lua_State* L, const char key[], const char value[]) {
58 lua_pushstring(L, value);
59 lua_setfield(L, -2, key);
60}
61
62static void setfield_number(lua_State* L, const char key[], double value) {
63 lua_pushnumber(L, value);
64 lua_setfield(L, -2, key);
65}
66
67SkLua::SkLua(lua_State* L) : fL(L) {
68 static bool gOnce;
69 if (!gOnce) {
70 SkLua::Load(L);
71 gOnce = true;
72 }
73}
74
75SkLua::~SkLua() {
76}
77
78#define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0)
79
80void SkLua::pushBool(bool value, const char key[]) {
81 lua_pushboolean(fL, value);
82 CHECK_SETFIELD(key);
83}
84
85void SkLua::pushString(const char str[], const char key[]) {
86 lua_pushstring(fL, str);
87 CHECK_SETFIELD(key);
88}
89
90void SkLua::pushString(const SkString& str, const char key[]) {
91 lua_pushstring(fL, str.c_str());
92 CHECK_SETFIELD(key);
93}
94
95void SkLua::pushColor(SkColor color, const char key[]) {
96 lua_newtable(fL);
97 setfield_number(fL, "a", SkColorGetA(color) / 255.0);
98 setfield_number(fL, "r", SkColorGetR(color) / 255.0);
99 setfield_number(fL, "g", SkColorGetG(color) / 255.0);
100 setfield_number(fL, "b", SkColorGetB(color) / 255.0);
101 CHECK_SETFIELD(key);
102}
103
104void SkLua::pushScalar(SkScalar value, const char key[]) {
105 lua_pushnumber(fL, SkScalarToLua(value));
106 CHECK_SETFIELD(key);
107}
108
109void SkLua::pushRect(const SkRect& r, const char key[]) {
110 lua_newtable(fL);
111 setfield_number(fL, "left", SkScalarToLua(r.fLeft));
112 setfield_number(fL, "top", SkScalarToLua(r.fTop));
113 setfield_number(fL, "right", SkScalarToLua(r.fRight));
114 setfield_number(fL, "bottom", SkScalarToLua(r.fBottom));
115 CHECK_SETFIELD(key);
116}
117
118void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
119 push_obj(fL, rr);
120 CHECK_SETFIELD(key);
121}
122
123void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
124 push_obj(fL, matrix);
125 CHECK_SETFIELD(key);
126}
127
128void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
129 push_obj(fL, paint);
130 CHECK_SETFIELD(key);
131}
132
133void SkLua::pushPath(const SkPath& path, const char key[]) {
134 push_obj(fL, path);
135 CHECK_SETFIELD(key);
136}
137
138void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
139 push_ref(fL, canvas);
140 CHECK_SETFIELD(key);
141}
142
143///////////////////////////////////////////////////////////////////////////////
144///////////////////////////////////////////////////////////////////////////////
145
146static SkScalar lua2scalar(lua_State* L, int index) {
147 SkASSERT(lua_isnumber(L, index));
148 return SkLuaToScalar(lua_tonumber(L, index));
149}
150
151static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
152 SkASSERT(lua_istable(L, index));
153 lua_pushstring(L, key);
154 lua_gettable(L, index);
155
156 SkScalar value = lua2scalar(L, -1);
157 lua_pop(L, 1);
158 return value;
159}
160
161static U8CPU unit2byte(SkScalar x) {
162 if (x <= 0) {
163 return 0;
164 } else if (x >= 1) {
165 return 255;
166 } else {
167 return SkScalarRoundToInt(x * 255);
168 }
169}
170
171static SkColor lua2color(lua_State* L, int index) {
172 return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
173 unit2byte(getfield_scalar(L, index, "r")),
174 unit2byte(getfield_scalar(L, index, "g")),
175 unit2byte(getfield_scalar(L, index, "b")));
176}
177
178static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
179 rect->set(getfield_scalar(L, index, "left"),
180 getfield_scalar(L, index, "top"),
181 getfield_scalar(L, index, "right"),
182 getfield_scalar(L, index, "bottom"));
183 return rect;
184}
185
186static int lcanvas_drawColor(lua_State* L) {
187 get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
188 return 0;
189}
190
191static int lcanvas_drawRect(lua_State* L) {
192 SkRect rect;
193 get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
194 *get_obj<SkPaint>(L, 3));
195 return 0;
196}
197
198static int lcanvas_drawOval(lua_State* L) {
199 SkRect rect;
200 get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
201 *get_obj<SkPaint>(L, 3));
202 return 0;
203}
204
205static int lcanvas_drawCircle(lua_State* L) {
206 get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
207 lua2scalar(L, 3),
208 lua2scalar(L, 4),
209 *get_obj<SkPaint>(L, 5));
210 return 0;
211}
212
213static int lcanvas_getSaveCount(lua_State* L) {
214 lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
215 return 1;
216}
217
218static int lcanvas_getTotalMatrix(lua_State* L) {
219 SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
220 return 1;
221}
222
223static int lcanvas_gc(lua_State* L) {
224 get_ref<SkCanvas>(L, 1)->unref();
225 return 0;
226}
227
228static const struct luaL_Reg gSkCanvas_Methods[] = {
229 { "drawColor", lcanvas_drawColor },
230 { "drawRect", lcanvas_drawRect },
231 { "drawOval", lcanvas_drawOval },
232 { "drawCircle", lcanvas_drawCircle },
233 { "getSaveCount", lcanvas_getSaveCount },
234 { "getTotalMatrix", lcanvas_getTotalMatrix },
235 { "__gc", lcanvas_gc },
236 { NULL, NULL }
237};
238
239///////////////////////////////////////////////////////////////////////////////
240
241static int lpaint_isAntiAlias(lua_State* L) {
242 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
243 return 1;
244}
245
246static int lpaint_setAntiAlias(lua_State* L) {
247 get_obj<SkPaint>(L, 1)->setAntiAlias(lua_toboolean(L, 2));
248 return 0;
249}
250
251static int lpaint_getColor(lua_State* L) {
252 SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
253 return 1;
254}
255
256static int lpaint_setColor(lua_State* L) {
257 get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
258 return 0;
259}
260
261static int lpaint_gc(lua_State* L) {
262 get_obj<SkPaint>(L, 1)->~SkPaint();
263 return 0;
264}
265
266static const struct luaL_Reg gSkPaint_Methods[] = {
267 { "isAntiAlias", lpaint_isAntiAlias },
268 { "setAntiAlias", lpaint_setAntiAlias },
269 { "getColor", lpaint_getColor },
270 { "setColor", lpaint_setColor },
271 { "__gc", lpaint_gc },
272 { NULL, NULL }
273};
274
275///////////////////////////////////////////////////////////////////////////////
276
277static int lpath_getBounds(lua_State* L) {
278 SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
279 return 1;
280}
281
282static int lpath_isEmpty(lua_State* L) {
283 lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
284 return 1;
285}
286
287static int lpath_isRect(lua_State* L) {
288 SkRect r;
289 bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
290 int ret_count = 1;
291 lua_pushboolean(L, pred);
292 if (pred) {
293 SkLua(L).pushRect(r);
294 ret_count += 1;
295 }
296 return ret_count;
297}
298
299static const char* dir2string(SkPath::Direction dir) {
300 static const char* gStr[] = {
301 "unknown", "cw", "ccw"
302 };
303 SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
304 return gStr[dir];
305}
306
307static int lpath_isNestedRects(lua_State* L) {
308 SkRect rects[2];
309 SkPath::Direction dirs[2];
310 bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
311 int ret_count = 1;
312 lua_pushboolean(L, pred);
313 if (pred) {
314 SkLua lua(L);
315 lua.pushRect(rects[0]);
316 lua.pushRect(rects[1]);
317 lua_pushstring(L, dir2string(dirs[0]));
318 lua_pushstring(L, dir2string(dirs[0]));
319 ret_count += 4;
320 }
321 return ret_count;
322}
323
324static int lpath_reset(lua_State* L) {
325 get_obj<SkPath>(L, 1)->reset();
326 return 0;
327}
328
329static int lpath_moveTo(lua_State* L) {
330 get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
331 return 0;
332}
333
334static int lpath_lineTo(lua_State* L) {
335 get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
336 return 0;
337}
338
339static int lpath_quadTo(lua_State* L) {
340 get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
341 lua2scalar(L, 4), lua2scalar(L, 5));
342 return 0;
343}
344
345static int lpath_cubicTo(lua_State* L) {
346 get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
347 lua2scalar(L, 4), lua2scalar(L, 5),
348 lua2scalar(L, 6), lua2scalar(L, 7));
349 return 0;
350}
351
352static int lpath_close(lua_State* L) {
353 get_obj<SkPath>(L, 1)->close();
354 return 0;
355}
356
357static int lpath_gc(lua_State* L) {
358 get_obj<SkPath>(L, 1)->~SkPath();
359 return 0;
360}
361
362static const struct luaL_Reg gSkPath_Methods[] = {
363 { "getBounds", lpath_getBounds },
364 { "isEmpty", lpath_isEmpty },
365 { "isRect", lpath_isRect },
366 { "isNestedRects", lpath_isNestedRects },
367 { "reset", lpath_reset },
368 { "moveTo", lpath_moveTo },
369 { "lineTo", lpath_lineTo },
370 { "quadTo", lpath_quadTo },
371 { "cubicTo", lpath_cubicTo },
372 { "close", lpath_close },
373 { "__gc", lpath_gc },
374 { NULL, NULL }
375};
376
377///////////////////////////////////////////////////////////////////////////////
378
379static const char* rrect_type(const SkRRect& rr) {
380 switch (rr.getType()) {
381 case SkRRect::kUnknown_Type: return "unknown";
382 case SkRRect::kEmpty_Type: return "empty";
383 case SkRRect::kRect_Type: return "rect";
384 case SkRRect::kOval_Type: return "oval";
385 case SkRRect::kSimple_Type: return "simple";
386 case SkRRect::kComplex_Type: return "complex";
387 }
388 SkASSERT(!"never get here");
389 return "";
390}
391
392static int lrrect_rect(lua_State* L) {
393 SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
394 return 1;
395}
396
397static int lrrect_type(lua_State* L) {
398 lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
399 return 1;
400}
401
402static int lrrect_radii(lua_State* L) {
403 int corner = lua_tointeger(L, 2);
404 SkVector v;
405 if (corner < 0 || corner > 3) {
406 SkDebugf("bad corner index %d", corner);
407 v.set(0, 0);
408 } else {
409 v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
410 }
411 lua_pushnumber(L, v.fX);
412 lua_pushnumber(L, v.fY);
413 return 2;
414}
415
416static int lrrect_gc(lua_State* L) {
417 get_obj<SkRRect>(L, 1)->~SkRRect();
418 return 0;
419}
420
421static const struct luaL_Reg gSkRRect_Methods[] = {
422 { "rect", lrrect_rect },
423 { "type", lrrect_type },
424 { "radii", lrrect_radii },
425 { "__gc", lrrect_gc },
426 { NULL, NULL }
427};
428
429///////////////////////////////////////////////////////////////////////////////
430
431class AutoCallLua {
432public:
433 AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
434 lua_getglobal(L, func);
435 if (!lua_isfunction(L, -1)) {
436 int t = lua_type(L, -1);
437 SkDebugf("--- expected function %d\n", t);
438 }
439
440 lua_newtable(L);
441 setfield_string(L, "verb", verb);
442 }
443
444 ~AutoCallLua() {
445 if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
446 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
447 }
448 lua_settop(fL, -1);
449 }
450
451private:
452 lua_State* fL;
453};
454
455#define AUTO_LUA(verb) AutoCallLua acl(fL, fFunc.c_str(), verb)
456
457///////////////////////////////////////////////////////////////////////////////
458
459#define REG_CLASS(L, C) \
460 do { \
461 luaL_newmetatable(L, g##C##_MTName); \
462 lua_pushvalue(L, -1); \
463 lua_setfield(L, -2, "__index"); \
464 luaL_setfuncs(L, g##C##_Methods, 0); \
465 lua_pop(L, 1); /* pop off the meta-table */ \
466 } while (0)
467
468void SkLua::Load(lua_State* L) {
469 REG_CLASS(L, SkCanvas);
470 REG_CLASS(L, SkPath);
471 REG_CLASS(L, SkPaint);
472 REG_CLASS(L, SkRRect);
473}
474