blob: 04dfbb1ecc6ca638d3c45f704849dd7f09c1d401 [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.org792bbd12013-06-11 02:20:28 +000010#include "SkData.h"
mike@reedtribe.orgfb858242013-06-08 16:39:44 +000011#include "SkDocument.h"
mike@reedtribe.org792bbd12013-06-11 02:20:28 +000012#include "SkImage.h"
13#include "SkMatrix.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000014#include "SkPaint.h"
15#include "SkPath.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000016#include "SkRRect.h"
17#include "SkString.h"
reed@google.come3823fd2013-05-30 18:55:14 +000018#include "SkTypeface.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000019
20extern "C" {
reed@google.com3597b732013-05-22 20:12:50 +000021 #include "lua.h"
22 #include "lualib.h"
23 #include "lauxlib.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000024}
25
reed@google.comfd345872013-05-22 20:53:42 +000026// return the metatable name for a given class
reed@google.com3597b732013-05-22 20:12:50 +000027template <typename T> const char* get_mtname();
reed@google.comfd345872013-05-22 20:53:42 +000028#define DEF_MTNAME(T) \
29 template <> const char* get_mtname<T>() { \
30 return #T "_LuaMetaTableName"; \
31 }
32
33DEF_MTNAME(SkCanvas)
mike@reedtribe.orgfb858242013-06-08 16:39:44 +000034DEF_MTNAME(SkDocument)
mike@reedtribe.org792bbd12013-06-11 02:20:28 +000035DEF_MTNAME(SkImage)
reed@google.comfd345872013-05-22 20:53:42 +000036DEF_MTNAME(SkMatrix)
37DEF_MTNAME(SkRRect)
38DEF_MTNAME(SkPath)
39DEF_MTNAME(SkPaint)
mike@reedtribe.orge6469f12013-06-08 03:15:47 +000040DEF_MTNAME(SkTypeface)
reed@google.com74ce6f02013-05-22 15:13:18 +000041
reed@google.com3597b732013-05-22 20:12:50 +000042template <typename T> T* push_new(lua_State* L) {
43 T* addr = (T*)lua_newuserdata(L, sizeof(T));
44 new (addr) T;
45 luaL_getmetatable(L, get_mtname<T>());
46 lua_setmetatable(L, -2);
47 return addr;
48}
reed@google.com74ce6f02013-05-22 15:13:18 +000049
50template <typename T> void push_obj(lua_State* L, const T& obj) {
51 new (lua_newuserdata(L, sizeof(T))) T(obj);
reed@google.com3597b732013-05-22 20:12:50 +000052 luaL_getmetatable(L, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000053 lua_setmetatable(L, -2);
54}
55
56template <typename T> void push_ref(lua_State* L, T* ref) {
57 *(T**)lua_newuserdata(L, sizeof(T*)) = SkRef(ref);
reed@google.com3597b732013-05-22 20:12:50 +000058 luaL_getmetatable(L, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000059 lua_setmetatable(L, -2);
60}
61
62template <typename T> T* get_ref(lua_State* L, int index) {
reed@google.com3597b732013-05-22 20:12:50 +000063 return *(T**)luaL_checkudata(L, index, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000064}
65
66template <typename T> T* get_obj(lua_State* L, int index) {
reed@google.com3597b732013-05-22 20:12:50 +000067 return (T*)luaL_checkudata(L, index, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000068}
69
reed@google.com88c9ec92013-05-22 15:43:21 +000070static bool lua2bool(lua_State* L, int index) {
71 return !!lua_toboolean(L, index);
72}
73
reed@google.com74ce6f02013-05-22 15:13:18 +000074///////////////////////////////////////////////////////////////////////////////
75
reed@google.com3597b732013-05-22 20:12:50 +000076SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) {
77 fL = luaL_newstate();
78 luaL_openlibs(fL);
79 SkLua::Load(fL);
80}
81
82SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {}
83
84SkLua::~SkLua() {
85 if (fWeOwnL) {
86 if (fTermCode.size() > 0) {
87 lua_getglobal(fL, fTermCode.c_str());
88 if (lua_pcall(fL, 0, 0, 0) != LUA_OK) {
89 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
90 }
91 }
92 lua_close(fL);
93 }
94}
95
96bool SkLua::runCode(const char code[]) {
97 int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0);
98 if (err) {
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +000099 SkDebugf("--- lua failed: %s\n", lua_tostring(fL, -1));
reed@google.com3597b732013-05-22 20:12:50 +0000100 return false;
101 }
102 return true;
103}
104
105bool SkLua::runCode(const void* code, size_t size) {
106 SkString str((const char*)code, size);
107 return this->runCode(str.c_str());
108}
109
110///////////////////////////////////////////////////////////////////////////////
111
112#define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0)
113
reed@google.com29563872013-07-10 21:23:49 +0000114static void setfield_bool_if(lua_State* L, const char key[], bool pred) {
115 if (pred) {
116 lua_pushboolean(L, true);
117 lua_setfield(L, -2, key);
118 }
119}
120
reed@google.com74ce6f02013-05-22 15:13:18 +0000121static void setfield_string(lua_State* L, const char key[], const char value[]) {
122 lua_pushstring(L, value);
123 lua_setfield(L, -2, key);
124}
125
126static void setfield_number(lua_State* L, const char key[], double value) {
127 lua_pushnumber(L, value);
128 lua_setfield(L, -2, key);
129}
130
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000131static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
132 setfield_number(L, key, SkScalarToLua(value));
133}
134
reed@google.com3597b732013-05-22 20:12:50 +0000135static void setfield_function(lua_State* L,
136 const char key[], lua_CFunction value) {
137 lua_pushcfunction(L, value);
138 lua_setfield(L, -2, key);
reed@google.com74ce6f02013-05-22 15:13:18 +0000139}
140
reed@google.come3823fd2013-05-30 18:55:14 +0000141static void setarray_number(lua_State* L, int index, double value) {
142 lua_pushnumber(L, value);
143 lua_rawseti(L, -2, index);
144}
145
reed@google.com74ce6f02013-05-22 15:13:18 +0000146void SkLua::pushBool(bool value, const char key[]) {
147 lua_pushboolean(fL, value);
148 CHECK_SETFIELD(key);
149}
150
151void SkLua::pushString(const char str[], const char key[]) {
152 lua_pushstring(fL, str);
153 CHECK_SETFIELD(key);
154}
155
reed@google.come3823fd2013-05-30 18:55:14 +0000156void SkLua::pushString(const char str[], size_t length, const char key[]) {
157 // TODO: how to do this w/o making a copy?
158 SkString s(str, length);
159 lua_pushstring(fL, s.c_str());
160 CHECK_SETFIELD(key);
161}
162
reed@google.com74ce6f02013-05-22 15:13:18 +0000163void SkLua::pushString(const SkString& str, const char key[]) {
164 lua_pushstring(fL, str.c_str());
165 CHECK_SETFIELD(key);
166}
167
168void SkLua::pushColor(SkColor color, const char key[]) {
169 lua_newtable(fL);
170 setfield_number(fL, "a", SkColorGetA(color) / 255.0);
171 setfield_number(fL, "r", SkColorGetR(color) / 255.0);
172 setfield_number(fL, "g", SkColorGetG(color) / 255.0);
173 setfield_number(fL, "b", SkColorGetB(color) / 255.0);
174 CHECK_SETFIELD(key);
175}
176
reed@google.come3823fd2013-05-30 18:55:14 +0000177void SkLua::pushU32(uint32_t value, const char key[]) {
178 lua_pushnumber(fL, (double)value);
179 CHECK_SETFIELD(key);
180}
181
reed@google.com74ce6f02013-05-22 15:13:18 +0000182void SkLua::pushScalar(SkScalar value, const char key[]) {
183 lua_pushnumber(fL, SkScalarToLua(value));
184 CHECK_SETFIELD(key);
185}
186
reed@google.come3823fd2013-05-30 18:55:14 +0000187void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
188 lua_newtable(fL);
189 for (int i = 0; i < count; ++i) {
190 // make it base-1 to match lua convention
191 setarray_number(fL, i + 1, (double)array[i]);
192 }
193 CHECK_SETFIELD(key);
194}
195
reed@google.com74ce6f02013-05-22 15:13:18 +0000196void SkLua::pushRect(const SkRect& r, const char key[]) {
197 lua_newtable(fL);
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000198 setfield_scalar(fL, "left", r.fLeft);
199 setfield_scalar(fL, "top", r.fTop);
200 setfield_scalar(fL, "right", r.fRight);
201 setfield_scalar(fL, "bottom", r.fBottom);
reed@google.com74ce6f02013-05-22 15:13:18 +0000202 CHECK_SETFIELD(key);
203}
204
205void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
206 push_obj(fL, rr);
207 CHECK_SETFIELD(key);
208}
209
210void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
211 push_obj(fL, matrix);
212 CHECK_SETFIELD(key);
213}
214
215void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
216 push_obj(fL, paint);
217 CHECK_SETFIELD(key);
218}
219
220void SkLua::pushPath(const SkPath& path, const char key[]) {
221 push_obj(fL, path);
222 CHECK_SETFIELD(key);
223}
224
225void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
226 push_ref(fL, canvas);
227 CHECK_SETFIELD(key);
228}
229
230///////////////////////////////////////////////////////////////////////////////
231///////////////////////////////////////////////////////////////////////////////
232
233static SkScalar lua2scalar(lua_State* L, int index) {
234 SkASSERT(lua_isnumber(L, index));
235 return SkLuaToScalar(lua_tonumber(L, index));
236}
237
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000238static SkScalar lua2scalar_def(lua_State* L, int index, SkScalar defaultValue) {
239 if (lua_isnumber(L, index)) {
240 return SkLuaToScalar(lua_tonumber(L, index));
241 } else {
242 return defaultValue;
243 }
244}
245
reed@google.com74ce6f02013-05-22 15:13:18 +0000246static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
247 SkASSERT(lua_istable(L, index));
248 lua_pushstring(L, key);
249 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000250
reed@google.com74ce6f02013-05-22 15:13:18 +0000251 SkScalar value = lua2scalar(L, -1);
252 lua_pop(L, 1);
253 return value;
254}
255
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000256static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
257 SkASSERT(lua_istable(L, index));
258 lua_pushstring(L, key);
259 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000260
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000261 SkScalar value;
262 if (lua_isnil(L, -1)) {
263 value = def;
264 } else {
265 value = lua2scalar(L, -1);
266 }
267 lua_pop(L, 1);
268 return value;
269}
270
reed@google.com74ce6f02013-05-22 15:13:18 +0000271static U8CPU unit2byte(SkScalar x) {
272 if (x <= 0) {
273 return 0;
274 } else if (x >= 1) {
275 return 255;
276 } else {
277 return SkScalarRoundToInt(x * 255);
278 }
279}
280
281static SkColor lua2color(lua_State* L, int index) {
282 return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
283 unit2byte(getfield_scalar(L, index, "r")),
284 unit2byte(getfield_scalar(L, index, "g")),
285 unit2byte(getfield_scalar(L, index, "b")));
286}
287
288static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000289 rect->set(getfield_scalar_default(L, index, "left", 0),
290 getfield_scalar_default(L, index, "top", 0),
reed@google.com74ce6f02013-05-22 15:13:18 +0000291 getfield_scalar(L, index, "right"),
292 getfield_scalar(L, index, "bottom"));
293 return rect;
294}
295
296static int lcanvas_drawColor(lua_State* L) {
297 get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
298 return 0;
299}
300
301static int lcanvas_drawRect(lua_State* L) {
302 SkRect rect;
303 get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
304 *get_obj<SkPaint>(L, 3));
305 return 0;
306}
307
308static int lcanvas_drawOval(lua_State* L) {
309 SkRect rect;
310 get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
311 *get_obj<SkPaint>(L, 3));
312 return 0;
313}
314
315static int lcanvas_drawCircle(lua_State* L) {
316 get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
317 lua2scalar(L, 3),
318 lua2scalar(L, 4),
319 *get_obj<SkPaint>(L, 5));
320 return 0;
321}
322
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000323static int lcanvas_drawImage(lua_State* L) {
324 SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
325 SkImage* image = get_ref<SkImage>(L, 2);
326 if (NULL == image) {
327 return 0;
328 }
329 SkScalar x = lua2scalar(L, 3);
330 SkScalar y = lua2scalar(L, 4);
331
332 SkPaint paint;
333 const SkPaint* paintPtr = NULL;
334 if (lua_isnumber(L, 5)) {
335 paint.setAlpha(SkScalarRoundToInt(lua2scalar(L, 5) * 255));
336 paintPtr = &paint;
337 }
338 image->draw(canvas, x, y, paintPtr);
339 return 0;
340}
341
reed@google.comfd345872013-05-22 20:53:42 +0000342static int lcanvas_drawPath(lua_State* L) {
343 get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
344 *get_obj<SkPaint>(L, 3));
345 return 0;
346}
347
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000348static int lcanvas_drawText(lua_State* L) {
349 if (lua_gettop(L) < 5) {
350 return 0;
351 }
352
353 if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
354 size_t len;
355 const char* text = lua_tolstring(L, 2, &len);
356 get_ref<SkCanvas>(L, 1)->drawText(text, len,
357 lua2scalar(L, 3), lua2scalar(L, 4),
358 *get_obj<SkPaint>(L, 5));
359 }
360 return 0;
361}
362
reed@google.com74ce6f02013-05-22 15:13:18 +0000363static int lcanvas_getSaveCount(lua_State* L) {
364 lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
365 return 1;
366}
367
368static int lcanvas_getTotalMatrix(lua_State* L) {
369 SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
370 return 1;
371}
372
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000373static int lcanvas_save(lua_State* L) {
374 lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
375 return 1;
376}
377
378static int lcanvas_restore(lua_State* L) {
379 get_ref<SkCanvas>(L, 1)->restore();
380 return 0;
381}
382
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000383static int lcanvas_scale(lua_State* L) {
384 SkScalar sx = lua2scalar_def(L, 2, 1);
385 SkScalar sy = lua2scalar_def(L, 3, sx);
386 get_ref<SkCanvas>(L, 1)->scale(sx, sy);
387 return 0;
388}
389
reed@google.com3597b732013-05-22 20:12:50 +0000390static int lcanvas_translate(lua_State* L) {
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000391 SkScalar tx = lua2scalar_def(L, 2, 0);
392 SkScalar ty = lua2scalar_def(L, 3, 0);
393 get_ref<SkCanvas>(L, 1)->translate(tx, ty);
394 return 0;
395}
396
397static int lcanvas_rotate(lua_State* L) {
398 SkScalar degrees = lua2scalar_def(L, 2, 0);
399 get_ref<SkCanvas>(L, 1)->rotate(degrees);
reed@google.com3597b732013-05-22 20:12:50 +0000400 return 0;
401}
402
reed@google.com74ce6f02013-05-22 15:13:18 +0000403static int lcanvas_gc(lua_State* L) {
404 get_ref<SkCanvas>(L, 1)->unref();
405 return 0;
406}
407
408static const struct luaL_Reg gSkCanvas_Methods[] = {
409 { "drawColor", lcanvas_drawColor },
410 { "drawRect", lcanvas_drawRect },
411 { "drawOval", lcanvas_drawOval },
412 { "drawCircle", lcanvas_drawCircle },
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000413 { "drawImage", lcanvas_drawImage },
reed@google.comfd345872013-05-22 20:53:42 +0000414 { "drawPath", lcanvas_drawPath },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000415 { "drawText", lcanvas_drawText },
reed@google.com74ce6f02013-05-22 15:13:18 +0000416 { "getSaveCount", lcanvas_getSaveCount },
417 { "getTotalMatrix", lcanvas_getTotalMatrix },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000418 { "save", lcanvas_save },
419 { "restore", lcanvas_restore },
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000420 { "scale", lcanvas_scale },
reed@google.com3597b732013-05-22 20:12:50 +0000421 { "translate", lcanvas_translate },
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000422 { "rotate", lcanvas_rotate },
reed@google.com74ce6f02013-05-22 15:13:18 +0000423 { "__gc", lcanvas_gc },
424 { NULL, NULL }
425};
426
427///////////////////////////////////////////////////////////////////////////////
428
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000429static int ldocument_beginPage(lua_State* L) {
430 const SkRect* contentPtr = NULL;
431 push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
432 lua2scalar(L, 3),
433 contentPtr));
434 return 1;
435}
436
437static int ldocument_endPage(lua_State* L) {
438 get_ref<SkDocument>(L, 1)->endPage();
439 return 0;
440}
441
442static int ldocument_close(lua_State* L) {
443 get_ref<SkDocument>(L, 1)->close();
444 return 0;
445}
446
447static int ldocument_gc(lua_State* L) {
448 get_ref<SkDocument>(L, 1)->unref();
449 return 0;
450}
451
452static const struct luaL_Reg gSkDocument_Methods[] = {
453 { "beginPage", ldocument_beginPage },
454 { "endPage", ldocument_endPage },
455 { "close", ldocument_close },
456 { "__gc", ldocument_gc },
457 { NULL, NULL }
458};
459
460///////////////////////////////////////////////////////////////////////////////
461
reed@google.com74ce6f02013-05-22 15:13:18 +0000462static int lpaint_isAntiAlias(lua_State* L) {
463 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
464 return 1;
465}
466
467static int lpaint_setAntiAlias(lua_State* L) {
reed@google.com88c9ec92013-05-22 15:43:21 +0000468 get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
reed@google.com74ce6f02013-05-22 15:13:18 +0000469 return 0;
470}
471
472static int lpaint_getColor(lua_State* L) {
473 SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
474 return 1;
475}
476
477static int lpaint_setColor(lua_State* L) {
478 get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
479 return 0;
480}
481
reed@google.come3823fd2013-05-30 18:55:14 +0000482static int lpaint_getTextSize(lua_State* L) {
483 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
484 return 1;
485}
486
487static int lpaint_setTextSize(lua_State* L) {
488 get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
489 return 0;
490}
491
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000492static int lpaint_getTypeface(lua_State* L) {
493 push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
494 return 1;
495}
496
497static int lpaint_setTypeface(lua_State* L) {
498 get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
499 return 0;
500}
501
reed@google.come3823fd2013-05-30 18:55:14 +0000502static int lpaint_getFontID(lua_State* L) {
503 SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
504 SkLua(L).pushU32(SkTypeface::UniqueID(face));
505 return 1;
506}
507
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000508static const struct {
509 const char* fLabel;
510 SkPaint::Align fAlign;
511} gAlignRec[] = {
512 { "left", SkPaint::kLeft_Align },
513 { "center", SkPaint::kCenter_Align },
514 { "right", SkPaint::kRight_Align },
515};
516
517static int lpaint_getTextAlign(lua_State* L) {
518 SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
519 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
520 if (gAlignRec[i].fAlign == align) {
521 lua_pushstring(L, gAlignRec[i].fLabel);
522 return 1;
523 }
524 }
525 return 0;
526}
527
528static int lpaint_setTextAlign(lua_State* L) {
529 if (lua_isstring(L, 2)) {
530 size_t len;
531 const char* label = lua_tolstring(L, 2, &len);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000532
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000533 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
534 if (!strcmp(gAlignRec[i].fLabel, label)) {
535 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
536 break;
537 }
538 }
539 }
540 return 0;
541}
542
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000543static int lpaint_getStroke(lua_State* L) {
544 lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
545 return 1;
546}
547
548static int lpaint_setStroke(lua_State* L) {
549 SkPaint::Style style;
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000550
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000551 if (lua_toboolean(L, 2)) {
552 style = SkPaint::kStroke_Style;
553 } else {
554 style = SkPaint::kFill_Style;
555 }
556 get_obj<SkPaint>(L, 1)->setStyle(style);
557 return 0;
558}
559
560static int lpaint_getStrokeWidth(lua_State* L) {
561 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
562 return 1;
563}
564
565static int lpaint_setStrokeWidth(lua_State* L) {
566 get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
567 return 0;
568}
569
570static int lpaint_measureText(lua_State* L) {
571 if (lua_isstring(L, 2)) {
572 size_t len;
573 const char* text = lua_tolstring(L, 2, &len);
574 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
575 return 1;
576 }
577 return 0;
578}
579
580struct FontMetrics {
581 SkScalar fTop; //!< The greatest distance above the baseline for any glyph (will be <= 0)
582 SkScalar fAscent; //!< The recommended distance above the baseline (will be <= 0)
583 SkScalar fDescent; //!< The recommended distance below the baseline (will be >= 0)
584 SkScalar fBottom; //!< The greatest distance below the baseline for any glyph (will be >= 0)
585 SkScalar fLeading; //!< The recommended distance to add between lines of text (will be >= 0)
586 SkScalar fAvgCharWidth; //!< the average charactor width (>= 0)
587 SkScalar fXMin; //!< The minimum bounding box x value for all glyphs
588 SkScalar fXMax; //!< The maximum bounding box x value for all glyphs
589 SkScalar fXHeight; //!< the height of an 'x' in px, or 0 if no 'x' in face
590};
591
592static int lpaint_getFontMetrics(lua_State* L) {
593 SkPaint::FontMetrics fm;
594 SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000595
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000596 lua_newtable(L);
597 setfield_scalar(L, "top", fm.fTop);
598 setfield_scalar(L, "ascent", fm.fAscent);
599 setfield_scalar(L, "descent", fm.fDescent);
600 setfield_scalar(L, "bottom", fm.fBottom);
601 setfield_scalar(L, "leading", fm.fLeading);
602 SkLua(L).pushScalar(height);
603 return 2;
604}
605
reed@google.com29563872013-07-10 21:23:49 +0000606static int lpaint_getEffects(lua_State* L) {
607 const SkPaint* paint = get_obj<SkPaint>(L, 1);
608
609 lua_newtable(L);
610 setfield_bool_if(L, "looper", !!paint->getLooper());
611 setfield_bool_if(L, "pathEffect", !!paint->getPathEffect());
612 setfield_bool_if(L, "rasterizer", !!paint->getRasterizer());
613 setfield_bool_if(L, "maskFilter", !!paint->getMaskFilter());
614 setfield_bool_if(L, "shader", !!paint->getShader());
615 setfield_bool_if(L, "colorFilter", !!paint->getColorFilter());
616 setfield_bool_if(L, "imageFilter", !!paint->getImageFilter());
617 setfield_bool_if(L, "xfermode", !!paint->getXfermode());
618 return 1;
619}
620
reed@google.com74ce6f02013-05-22 15:13:18 +0000621static int lpaint_gc(lua_State* L) {
622 get_obj<SkPaint>(L, 1)->~SkPaint();
623 return 0;
624}
625
626static const struct luaL_Reg gSkPaint_Methods[] = {
627 { "isAntiAlias", lpaint_isAntiAlias },
628 { "setAntiAlias", lpaint_setAntiAlias },
629 { "getColor", lpaint_getColor },
630 { "setColor", lpaint_setColor },
reed@google.come3823fd2013-05-30 18:55:14 +0000631 { "getTextSize", lpaint_getTextSize },
632 { "setTextSize", lpaint_setTextSize },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000633 { "getTypeface", lpaint_getTypeface },
634 { "setTypeface", lpaint_setTypeface },
reed@google.come3823fd2013-05-30 18:55:14 +0000635 { "getFontID", lpaint_getFontID },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000636 { "getTextAlign", lpaint_getTextAlign },
637 { "setTextAlign", lpaint_setTextAlign },
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000638 { "getStroke", lpaint_getStroke },
639 { "setStroke", lpaint_setStroke },
640 { "getStrokeWidth", lpaint_getStrokeWidth },
641 { "setStrokeWidth", lpaint_setStrokeWidth },
642 { "measureText", lpaint_measureText },
643 { "getFontMetrics", lpaint_getFontMetrics },
reed@google.com29563872013-07-10 21:23:49 +0000644 { "getEffects", lpaint_getEffects },
reed@google.com74ce6f02013-05-22 15:13:18 +0000645 { "__gc", lpaint_gc },
646 { NULL, NULL }
647};
648
649///////////////////////////////////////////////////////////////////////////////
650
651static int lpath_getBounds(lua_State* L) {
652 SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
653 return 1;
654}
655
656static int lpath_isEmpty(lua_State* L) {
657 lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
658 return 1;
659}
660
661static int lpath_isRect(lua_State* L) {
662 SkRect r;
663 bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
664 int ret_count = 1;
665 lua_pushboolean(L, pred);
666 if (pred) {
667 SkLua(L).pushRect(r);
668 ret_count += 1;
669 }
670 return ret_count;
671}
672
673static const char* dir2string(SkPath::Direction dir) {
674 static const char* gStr[] = {
675 "unknown", "cw", "ccw"
676 };
677 SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
678 return gStr[dir];
679}
680
681static int lpath_isNestedRects(lua_State* L) {
682 SkRect rects[2];
683 SkPath::Direction dirs[2];
684 bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
685 int ret_count = 1;
686 lua_pushboolean(L, pred);
687 if (pred) {
688 SkLua lua(L);
689 lua.pushRect(rects[0]);
690 lua.pushRect(rects[1]);
691 lua_pushstring(L, dir2string(dirs[0]));
692 lua_pushstring(L, dir2string(dirs[0]));
693 ret_count += 4;
694 }
695 return ret_count;
696}
697
698static int lpath_reset(lua_State* L) {
699 get_obj<SkPath>(L, 1)->reset();
700 return 0;
701}
702
703static int lpath_moveTo(lua_State* L) {
704 get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
705 return 0;
706}
707
708static int lpath_lineTo(lua_State* L) {
709 get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
710 return 0;
711}
712
713static int lpath_quadTo(lua_State* L) {
714 get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
715 lua2scalar(L, 4), lua2scalar(L, 5));
716 return 0;
717}
718
719static int lpath_cubicTo(lua_State* L) {
720 get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
721 lua2scalar(L, 4), lua2scalar(L, 5),
722 lua2scalar(L, 6), lua2scalar(L, 7));
723 return 0;
724}
725
726static int lpath_close(lua_State* L) {
727 get_obj<SkPath>(L, 1)->close();
728 return 0;
729}
730
731static int lpath_gc(lua_State* L) {
732 get_obj<SkPath>(L, 1)->~SkPath();
733 return 0;
734}
735
736static const struct luaL_Reg gSkPath_Methods[] = {
737 { "getBounds", lpath_getBounds },
738 { "isEmpty", lpath_isEmpty },
739 { "isRect", lpath_isRect },
740 { "isNestedRects", lpath_isNestedRects },
741 { "reset", lpath_reset },
742 { "moveTo", lpath_moveTo },
743 { "lineTo", lpath_lineTo },
744 { "quadTo", lpath_quadTo },
745 { "cubicTo", lpath_cubicTo },
746 { "close", lpath_close },
747 { "__gc", lpath_gc },
748 { NULL, NULL }
749};
750
751///////////////////////////////////////////////////////////////////////////////
752
753static const char* rrect_type(const SkRRect& rr) {
754 switch (rr.getType()) {
755 case SkRRect::kUnknown_Type: return "unknown";
756 case SkRRect::kEmpty_Type: return "empty";
757 case SkRRect::kRect_Type: return "rect";
758 case SkRRect::kOval_Type: return "oval";
759 case SkRRect::kSimple_Type: return "simple";
760 case SkRRect::kComplex_Type: return "complex";
761 }
762 SkASSERT(!"never get here");
763 return "";
764}
765
766static int lrrect_rect(lua_State* L) {
767 SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
768 return 1;
769}
770
771static int lrrect_type(lua_State* L) {
772 lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
773 return 1;
774}
775
776static int lrrect_radii(lua_State* L) {
777 int corner = lua_tointeger(L, 2);
778 SkVector v;
779 if (corner < 0 || corner > 3) {
780 SkDebugf("bad corner index %d", corner);
781 v.set(0, 0);
782 } else {
783 v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
784 }
785 lua_pushnumber(L, v.fX);
786 lua_pushnumber(L, v.fY);
787 return 2;
788}
789
790static int lrrect_gc(lua_State* L) {
791 get_obj<SkRRect>(L, 1)->~SkRRect();
792 return 0;
793}
794
795static const struct luaL_Reg gSkRRect_Methods[] = {
796 { "rect", lrrect_rect },
797 { "type", lrrect_type },
798 { "radii", lrrect_radii },
799 { "__gc", lrrect_gc },
800 { NULL, NULL }
801};
802
803///////////////////////////////////////////////////////////////////////////////
804
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000805static int limage_width(lua_State* L) {
806 lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
807 return 1;
808}
809
810static int limage_height(lua_State* L) {
811 lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
812 return 1;
813}
814
815static int limage_gc(lua_State* L) {
816 get_ref<SkImage>(L, 1)->unref();
817 return 0;
818}
819
820static const struct luaL_Reg gSkImage_Methods[] = {
821 { "width", limage_width },
822 { "height", limage_height },
823 { "__gc", limage_gc },
824 { NULL, NULL }
825};
826
827///////////////////////////////////////////////////////////////////////////////
828
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000829static int ltypeface_gc(lua_State* L) {
830 get_ref<SkTypeface>(L, 1)->unref();
831 return 0;
832}
833
834static const struct luaL_Reg gSkTypeface_Methods[] = {
835 { "__gc", ltypeface_gc },
836 { NULL, NULL }
837};
838
839///////////////////////////////////////////////////////////////////////////////
840
reed@google.com74ce6f02013-05-22 15:13:18 +0000841class AutoCallLua {
842public:
843 AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
844 lua_getglobal(L, func);
845 if (!lua_isfunction(L, -1)) {
846 int t = lua_type(L, -1);
847 SkDebugf("--- expected function %d\n", t);
848 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000849
reed@google.com74ce6f02013-05-22 15:13:18 +0000850 lua_newtable(L);
851 setfield_string(L, "verb", verb);
852 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000853
reed@google.com74ce6f02013-05-22 15:13:18 +0000854 ~AutoCallLua() {
855 if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
856 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
857 }
858 lua_settop(fL, -1);
859 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000860
reed@google.com74ce6f02013-05-22 15:13:18 +0000861private:
862 lua_State* fL;
863};
864
865#define AUTO_LUA(verb) AutoCallLua acl(fL, fFunc.c_str(), verb)
866
867///////////////////////////////////////////////////////////////////////////////
868
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000869static int lsk_newDocumentPDF(lua_State* L) {
870 const char* file = NULL;
871 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
872 file = lua_tolstring(L, 1, NULL);
873 }
874
875 SkDocument* doc = SkDocument::CreatePDF(file);
876 if (NULL == doc) {
877 // do I need to push a nil on the stack and return 1?
878 return 0;
879 } else {
880 push_ref(L, doc);
881 doc->unref();
882 return 1;
883 }
884}
885
reed@google.com3597b732013-05-22 20:12:50 +0000886static int lsk_newPaint(lua_State* L) {
887 push_new<SkPaint>(L);
888 return 1;
889}
890
891static int lsk_newPath(lua_State* L) {
892 push_new<SkPath>(L);
893 return 1;
894}
895
896static int lsk_newRRect(lua_State* L) {
897 SkRRect* rr = push_new<SkRRect>(L);
898 rr->setEmpty();
899 return 1;
900}
901
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000902static int lsk_newTypeface(lua_State* L) {
903 const char* name = NULL;
904 int style = SkTypeface::kNormal;
skia.committer@gmail.com63193672013-06-08 07:01:13 +0000905
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000906 int count = lua_gettop(L);
907 if (count > 0 && lua_isstring(L, 1)) {
908 name = lua_tolstring(L, 1, NULL);
909 if (count > 1 && lua_isnumber(L, 2)) {
910 style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
911 }
912 }
913
914 SkTypeface* face = SkTypeface::CreateFromName(name,
915 (SkTypeface::Style)style);
916// SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
917 if (NULL == face) {
918 face = SkTypeface::RefDefault();
919 }
920 push_ref(L, face);
921 face->unref();
922 return 1;
923}
reed@google.com3597b732013-05-22 20:12:50 +0000924
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000925static int lsk_loadImage(lua_State* L) {
926 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
927 const char* name = lua_tolstring(L, 1, NULL);
928 SkAutoDataUnref data(SkData::NewFromFileName(name));
929 if (data.get()) {
930 SkImage* image = SkImage::NewEncodedData(data.get());
931 if (image) {
932 push_ref(L, image);
933 image->unref();
934 return 1;
935 }
936 }
937 }
938 return 0;
939}
940
reed@google.com3597b732013-05-22 20:12:50 +0000941static void register_Sk(lua_State* L) {
942 lua_newtable(L);
943 lua_pushvalue(L, -1);
944 lua_setglobal(L, "Sk");
945 // the Sk table is still on top
946
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000947 setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000948 setfield_function(L, "loadImage", lsk_loadImage);
reed@google.com3597b732013-05-22 20:12:50 +0000949 setfield_function(L, "newPaint", lsk_newPaint);
950 setfield_function(L, "newPath", lsk_newPath);
951 setfield_function(L, "newRRect", lsk_newRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000952 setfield_function(L, "newTypeface", lsk_newTypeface);
reed@google.com3597b732013-05-22 20:12:50 +0000953 lua_pop(L, 1); // pop off the Sk table
954}
955
reed@google.com74ce6f02013-05-22 15:13:18 +0000956#define REG_CLASS(L, C) \
957 do { \
reed@google.com3597b732013-05-22 20:12:50 +0000958 luaL_newmetatable(L, get_mtname<C>()); \
reed@google.com74ce6f02013-05-22 15:13:18 +0000959 lua_pushvalue(L, -1); \
960 lua_setfield(L, -2, "__index"); \
961 luaL_setfuncs(L, g##C##_Methods, 0); \
962 lua_pop(L, 1); /* pop off the meta-table */ \
963 } while (0)
964
965void SkLua::Load(lua_State* L) {
reed@google.com3597b732013-05-22 20:12:50 +0000966 register_Sk(L);
reed@google.com74ce6f02013-05-22 15:13:18 +0000967 REG_CLASS(L, SkCanvas);
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000968 REG_CLASS(L, SkDocument);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000969 REG_CLASS(L, SkImage);
reed@google.com74ce6f02013-05-22 15:13:18 +0000970 REG_CLASS(L, SkPath);
971 REG_CLASS(L, SkPaint);
972 REG_CLASS(L, SkRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000973 REG_CLASS(L, SkTypeface);
reed@google.com74ce6f02013-05-22 15:13:18 +0000974}
zachr@google.com28c27c82013-06-20 17:15:05 +0000975
reed@google.com7bce9982013-06-20 17:40:21 +0000976extern "C" int luaopen_skia(lua_State* L);
zachr@google.com28c27c82013-06-20 17:15:05 +0000977extern "C" int luaopen_skia(lua_State* L) {
978 SkLua::Load(L);
979 return 0;
980}