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