blob: 658b43ba5a3fcfd62fd54a0be2fcd4aefb14b44e [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
humper@google.com2815c192013-07-10 22:42:30 +0000131static void setfield_boolean(lua_State* L, const char key[], bool value) {
132 lua_pushboolean(L, value);
133 lua_setfield(L, -2, key);
134}
135
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000136static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
137 setfield_number(L, key, SkScalarToLua(value));
138}
139
reed@google.com3597b732013-05-22 20:12:50 +0000140static void setfield_function(lua_State* L,
141 const char key[], lua_CFunction value) {
142 lua_pushcfunction(L, value);
143 lua_setfield(L, -2, key);
reed@google.com74ce6f02013-05-22 15:13:18 +0000144}
145
reed@google.come3823fd2013-05-30 18:55:14 +0000146static void setarray_number(lua_State* L, int index, double value) {
147 lua_pushnumber(L, value);
148 lua_rawseti(L, -2, index);
149}
150
reed@google.com74ce6f02013-05-22 15:13:18 +0000151void SkLua::pushBool(bool value, const char key[]) {
152 lua_pushboolean(fL, value);
153 CHECK_SETFIELD(key);
154}
155
156void SkLua::pushString(const char str[], const char key[]) {
157 lua_pushstring(fL, str);
158 CHECK_SETFIELD(key);
159}
160
reed@google.come3823fd2013-05-30 18:55:14 +0000161void SkLua::pushString(const char str[], size_t length, const char key[]) {
162 // TODO: how to do this w/o making a copy?
163 SkString s(str, length);
164 lua_pushstring(fL, s.c_str());
165 CHECK_SETFIELD(key);
166}
167
reed@google.com74ce6f02013-05-22 15:13:18 +0000168void SkLua::pushString(const SkString& str, const char key[]) {
169 lua_pushstring(fL, str.c_str());
170 CHECK_SETFIELD(key);
171}
172
173void SkLua::pushColor(SkColor color, const char key[]) {
174 lua_newtable(fL);
175 setfield_number(fL, "a", SkColorGetA(color) / 255.0);
176 setfield_number(fL, "r", SkColorGetR(color) / 255.0);
177 setfield_number(fL, "g", SkColorGetG(color) / 255.0);
178 setfield_number(fL, "b", SkColorGetB(color) / 255.0);
179 CHECK_SETFIELD(key);
180}
181
reed@google.come3823fd2013-05-30 18:55:14 +0000182void SkLua::pushU32(uint32_t value, const char key[]) {
183 lua_pushnumber(fL, (double)value);
184 CHECK_SETFIELD(key);
185}
186
reed@google.com74ce6f02013-05-22 15:13:18 +0000187void SkLua::pushScalar(SkScalar value, const char key[]) {
188 lua_pushnumber(fL, SkScalarToLua(value));
189 CHECK_SETFIELD(key);
190}
191
reed@google.come3823fd2013-05-30 18:55:14 +0000192void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
193 lua_newtable(fL);
194 for (int i = 0; i < count; ++i) {
195 // make it base-1 to match lua convention
196 setarray_number(fL, i + 1, (double)array[i]);
197 }
198 CHECK_SETFIELD(key);
199}
200
reed@google.com74ce6f02013-05-22 15:13:18 +0000201void SkLua::pushRect(const SkRect& r, const char key[]) {
202 lua_newtable(fL);
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000203 setfield_scalar(fL, "left", r.fLeft);
204 setfield_scalar(fL, "top", r.fTop);
205 setfield_scalar(fL, "right", r.fRight);
206 setfield_scalar(fL, "bottom", r.fBottom);
reed@google.com74ce6f02013-05-22 15:13:18 +0000207 CHECK_SETFIELD(key);
208}
209
210void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
211 push_obj(fL, rr);
212 CHECK_SETFIELD(key);
213}
214
215void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
216 push_obj(fL, matrix);
217 CHECK_SETFIELD(key);
218}
219
220void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
221 push_obj(fL, paint);
222 CHECK_SETFIELD(key);
223}
224
225void SkLua::pushPath(const SkPath& path, const char key[]) {
226 push_obj(fL, path);
227 CHECK_SETFIELD(key);
228}
229
230void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
231 push_ref(fL, canvas);
232 CHECK_SETFIELD(key);
233}
234
235///////////////////////////////////////////////////////////////////////////////
236///////////////////////////////////////////////////////////////////////////////
237
238static SkScalar lua2scalar(lua_State* L, int index) {
239 SkASSERT(lua_isnumber(L, index));
240 return SkLuaToScalar(lua_tonumber(L, index));
241}
242
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000243static SkScalar lua2scalar_def(lua_State* L, int index, SkScalar defaultValue) {
244 if (lua_isnumber(L, index)) {
245 return SkLuaToScalar(lua_tonumber(L, index));
246 } else {
247 return defaultValue;
248 }
249}
250
reed@google.com74ce6f02013-05-22 15:13:18 +0000251static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
252 SkASSERT(lua_istable(L, index));
253 lua_pushstring(L, key);
254 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000255
reed@google.com74ce6f02013-05-22 15:13:18 +0000256 SkScalar value = lua2scalar(L, -1);
257 lua_pop(L, 1);
258 return value;
259}
260
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000261static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
262 SkASSERT(lua_istable(L, index));
263 lua_pushstring(L, key);
264 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000265
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000266 SkScalar value;
267 if (lua_isnil(L, -1)) {
268 value = def;
269 } else {
270 value = lua2scalar(L, -1);
271 }
272 lua_pop(L, 1);
273 return value;
274}
275
reed@google.com74ce6f02013-05-22 15:13:18 +0000276static U8CPU unit2byte(SkScalar x) {
277 if (x <= 0) {
278 return 0;
279 } else if (x >= 1) {
280 return 255;
281 } else {
282 return SkScalarRoundToInt(x * 255);
283 }
284}
285
286static SkColor lua2color(lua_State* L, int index) {
287 return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
288 unit2byte(getfield_scalar(L, index, "r")),
289 unit2byte(getfield_scalar(L, index, "g")),
290 unit2byte(getfield_scalar(L, index, "b")));
291}
292
293static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000294 rect->set(getfield_scalar_default(L, index, "left", 0),
295 getfield_scalar_default(L, index, "top", 0),
reed@google.com74ce6f02013-05-22 15:13:18 +0000296 getfield_scalar(L, index, "right"),
297 getfield_scalar(L, index, "bottom"));
298 return rect;
299}
300
301static int lcanvas_drawColor(lua_State* L) {
302 get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
303 return 0;
304}
305
306static int lcanvas_drawRect(lua_State* L) {
307 SkRect rect;
308 get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
309 *get_obj<SkPaint>(L, 3));
310 return 0;
311}
312
313static int lcanvas_drawOval(lua_State* L) {
314 SkRect rect;
315 get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
316 *get_obj<SkPaint>(L, 3));
317 return 0;
318}
319
320static int lcanvas_drawCircle(lua_State* L) {
321 get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
322 lua2scalar(L, 3),
323 lua2scalar(L, 4),
324 *get_obj<SkPaint>(L, 5));
325 return 0;
326}
327
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000328static int lcanvas_drawImage(lua_State* L) {
329 SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
330 SkImage* image = get_ref<SkImage>(L, 2);
331 if (NULL == image) {
332 return 0;
333 }
334 SkScalar x = lua2scalar(L, 3);
335 SkScalar y = lua2scalar(L, 4);
336
337 SkPaint paint;
338 const SkPaint* paintPtr = NULL;
339 if (lua_isnumber(L, 5)) {
340 paint.setAlpha(SkScalarRoundToInt(lua2scalar(L, 5) * 255));
341 paintPtr = &paint;
342 }
343 image->draw(canvas, x, y, paintPtr);
344 return 0;
345}
346
reed@google.comfd345872013-05-22 20:53:42 +0000347static int lcanvas_drawPath(lua_State* L) {
348 get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
349 *get_obj<SkPaint>(L, 3));
350 return 0;
351}
352
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000353static int lcanvas_drawText(lua_State* L) {
354 if (lua_gettop(L) < 5) {
355 return 0;
356 }
357
358 if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
359 size_t len;
360 const char* text = lua_tolstring(L, 2, &len);
361 get_ref<SkCanvas>(L, 1)->drawText(text, len,
362 lua2scalar(L, 3), lua2scalar(L, 4),
363 *get_obj<SkPaint>(L, 5));
364 }
365 return 0;
366}
367
reed@google.com74ce6f02013-05-22 15:13:18 +0000368static int lcanvas_getSaveCount(lua_State* L) {
369 lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
370 return 1;
371}
372
373static int lcanvas_getTotalMatrix(lua_State* L) {
374 SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
375 return 1;
376}
377
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000378static int lcanvas_save(lua_State* L) {
379 lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
380 return 1;
381}
382
383static int lcanvas_restore(lua_State* L) {
384 get_ref<SkCanvas>(L, 1)->restore();
385 return 0;
386}
387
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000388static int lcanvas_scale(lua_State* L) {
389 SkScalar sx = lua2scalar_def(L, 2, 1);
390 SkScalar sy = lua2scalar_def(L, 3, sx);
391 get_ref<SkCanvas>(L, 1)->scale(sx, sy);
392 return 0;
393}
394
reed@google.com3597b732013-05-22 20:12:50 +0000395static int lcanvas_translate(lua_State* L) {
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000396 SkScalar tx = lua2scalar_def(L, 2, 0);
397 SkScalar ty = lua2scalar_def(L, 3, 0);
398 get_ref<SkCanvas>(L, 1)->translate(tx, ty);
399 return 0;
400}
401
402static int lcanvas_rotate(lua_State* L) {
403 SkScalar degrees = lua2scalar_def(L, 2, 0);
404 get_ref<SkCanvas>(L, 1)->rotate(degrees);
reed@google.com3597b732013-05-22 20:12:50 +0000405 return 0;
406}
407
reed@google.com74ce6f02013-05-22 15:13:18 +0000408static int lcanvas_gc(lua_State* L) {
409 get_ref<SkCanvas>(L, 1)->unref();
410 return 0;
411}
412
413static const struct luaL_Reg gSkCanvas_Methods[] = {
414 { "drawColor", lcanvas_drawColor },
415 { "drawRect", lcanvas_drawRect },
416 { "drawOval", lcanvas_drawOval },
417 { "drawCircle", lcanvas_drawCircle },
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000418 { "drawImage", lcanvas_drawImage },
reed@google.comfd345872013-05-22 20:53:42 +0000419 { "drawPath", lcanvas_drawPath },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000420 { "drawText", lcanvas_drawText },
reed@google.com74ce6f02013-05-22 15:13:18 +0000421 { "getSaveCount", lcanvas_getSaveCount },
422 { "getTotalMatrix", lcanvas_getTotalMatrix },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000423 { "save", lcanvas_save },
424 { "restore", lcanvas_restore },
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000425 { "scale", lcanvas_scale },
reed@google.com3597b732013-05-22 20:12:50 +0000426 { "translate", lcanvas_translate },
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000427 { "rotate", lcanvas_rotate },
reed@google.com74ce6f02013-05-22 15:13:18 +0000428 { "__gc", lcanvas_gc },
429 { NULL, NULL }
430};
431
432///////////////////////////////////////////////////////////////////////////////
433
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000434static int ldocument_beginPage(lua_State* L) {
435 const SkRect* contentPtr = NULL;
436 push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
437 lua2scalar(L, 3),
438 contentPtr));
439 return 1;
440}
441
442static int ldocument_endPage(lua_State* L) {
443 get_ref<SkDocument>(L, 1)->endPage();
444 return 0;
445}
446
447static int ldocument_close(lua_State* L) {
448 get_ref<SkDocument>(L, 1)->close();
449 return 0;
450}
451
452static int ldocument_gc(lua_State* L) {
453 get_ref<SkDocument>(L, 1)->unref();
454 return 0;
455}
456
457static const struct luaL_Reg gSkDocument_Methods[] = {
458 { "beginPage", ldocument_beginPage },
459 { "endPage", ldocument_endPage },
460 { "close", ldocument_close },
461 { "__gc", ldocument_gc },
462 { NULL, NULL }
463};
464
465///////////////////////////////////////////////////////////////////////////////
466
reed@google.com74ce6f02013-05-22 15:13:18 +0000467static int lpaint_isAntiAlias(lua_State* L) {
468 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
469 return 1;
470}
471
472static int lpaint_setAntiAlias(lua_State* L) {
reed@google.com88c9ec92013-05-22 15:43:21 +0000473 get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
reed@google.com74ce6f02013-05-22 15:13:18 +0000474 return 0;
475}
476
477static int lpaint_getColor(lua_State* L) {
478 SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
479 return 1;
480}
481
482static int lpaint_setColor(lua_State* L) {
483 get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
484 return 0;
485}
486
reed@google.come3823fd2013-05-30 18:55:14 +0000487static int lpaint_getTextSize(lua_State* L) {
488 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
489 return 1;
490}
491
492static int lpaint_setTextSize(lua_State* L) {
493 get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
494 return 0;
495}
496
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000497static int lpaint_getTypeface(lua_State* L) {
498 push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
499 return 1;
500}
501
502static int lpaint_setTypeface(lua_State* L) {
503 get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
504 return 0;
505}
506
reed@google.come3823fd2013-05-30 18:55:14 +0000507static int lpaint_getFontID(lua_State* L) {
508 SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
509 SkLua(L).pushU32(SkTypeface::UniqueID(face));
510 return 1;
511}
512
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000513static const struct {
514 const char* fLabel;
515 SkPaint::Align fAlign;
516} gAlignRec[] = {
517 { "left", SkPaint::kLeft_Align },
518 { "center", SkPaint::kCenter_Align },
519 { "right", SkPaint::kRight_Align },
520};
521
522static int lpaint_getTextAlign(lua_State* L) {
523 SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
524 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
525 if (gAlignRec[i].fAlign == align) {
526 lua_pushstring(L, gAlignRec[i].fLabel);
527 return 1;
528 }
529 }
530 return 0;
531}
532
533static int lpaint_setTextAlign(lua_State* L) {
534 if (lua_isstring(L, 2)) {
535 size_t len;
536 const char* label = lua_tolstring(L, 2, &len);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000537
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000538 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
539 if (!strcmp(gAlignRec[i].fLabel, label)) {
540 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
541 break;
542 }
543 }
544 }
545 return 0;
546}
547
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000548static int lpaint_getStroke(lua_State* L) {
549 lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
550 return 1;
551}
552
553static int lpaint_setStroke(lua_State* L) {
554 SkPaint::Style style;
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000555
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000556 if (lua_toboolean(L, 2)) {
557 style = SkPaint::kStroke_Style;
558 } else {
559 style = SkPaint::kFill_Style;
560 }
561 get_obj<SkPaint>(L, 1)->setStyle(style);
562 return 0;
563}
564
565static int lpaint_getStrokeWidth(lua_State* L) {
566 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
567 return 1;
568}
569
570static int lpaint_setStrokeWidth(lua_State* L) {
571 get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
572 return 0;
573}
574
575static int lpaint_measureText(lua_State* L) {
576 if (lua_isstring(L, 2)) {
577 size_t len;
578 const char* text = lua_tolstring(L, 2, &len);
579 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
580 return 1;
581 }
582 return 0;
583}
584
585struct FontMetrics {
586 SkScalar fTop; //!< The greatest distance above the baseline for any glyph (will be <= 0)
587 SkScalar fAscent; //!< The recommended distance above the baseline (will be <= 0)
588 SkScalar fDescent; //!< The recommended distance below the baseline (will be >= 0)
589 SkScalar fBottom; //!< The greatest distance below the baseline for any glyph (will be >= 0)
590 SkScalar fLeading; //!< The recommended distance to add between lines of text (will be >= 0)
591 SkScalar fAvgCharWidth; //!< the average charactor width (>= 0)
592 SkScalar fXMin; //!< The minimum bounding box x value for all glyphs
593 SkScalar fXMax; //!< The maximum bounding box x value for all glyphs
594 SkScalar fXHeight; //!< the height of an 'x' in px, or 0 if no 'x' in face
595};
596
597static int lpaint_getFontMetrics(lua_State* L) {
598 SkPaint::FontMetrics fm;
599 SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000600
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000601 lua_newtable(L);
602 setfield_scalar(L, "top", fm.fTop);
603 setfield_scalar(L, "ascent", fm.fAscent);
604 setfield_scalar(L, "descent", fm.fDescent);
605 setfield_scalar(L, "bottom", fm.fBottom);
606 setfield_scalar(L, "leading", fm.fLeading);
607 SkLua(L).pushScalar(height);
608 return 2;
609}
610
reed@google.com29563872013-07-10 21:23:49 +0000611static int lpaint_getEffects(lua_State* L) {
612 const SkPaint* paint = get_obj<SkPaint>(L, 1);
613
614 lua_newtable(L);
615 setfield_bool_if(L, "looper", !!paint->getLooper());
616 setfield_bool_if(L, "pathEffect", !!paint->getPathEffect());
617 setfield_bool_if(L, "rasterizer", !!paint->getRasterizer());
618 setfield_bool_if(L, "maskFilter", !!paint->getMaskFilter());
619 setfield_bool_if(L, "shader", !!paint->getShader());
620 setfield_bool_if(L, "colorFilter", !!paint->getColorFilter());
621 setfield_bool_if(L, "imageFilter", !!paint->getImageFilter());
622 setfield_bool_if(L, "xfermode", !!paint->getXfermode());
623 return 1;
624}
625
reed@google.com74ce6f02013-05-22 15:13:18 +0000626static int lpaint_gc(lua_State* L) {
627 get_obj<SkPaint>(L, 1)->~SkPaint();
628 return 0;
629}
630
631static const struct luaL_Reg gSkPaint_Methods[] = {
632 { "isAntiAlias", lpaint_isAntiAlias },
633 { "setAntiAlias", lpaint_setAntiAlias },
634 { "getColor", lpaint_getColor },
635 { "setColor", lpaint_setColor },
reed@google.come3823fd2013-05-30 18:55:14 +0000636 { "getTextSize", lpaint_getTextSize },
637 { "setTextSize", lpaint_setTextSize },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000638 { "getTypeface", lpaint_getTypeface },
639 { "setTypeface", lpaint_setTypeface },
reed@google.come3823fd2013-05-30 18:55:14 +0000640 { "getFontID", lpaint_getFontID },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000641 { "getTextAlign", lpaint_getTextAlign },
642 { "setTextAlign", lpaint_setTextAlign },
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000643 { "getStroke", lpaint_getStroke },
644 { "setStroke", lpaint_setStroke },
645 { "getStrokeWidth", lpaint_getStrokeWidth },
646 { "setStrokeWidth", lpaint_setStrokeWidth },
647 { "measureText", lpaint_measureText },
648 { "getFontMetrics", lpaint_getFontMetrics },
reed@google.com29563872013-07-10 21:23:49 +0000649 { "getEffects", lpaint_getEffects },
reed@google.com74ce6f02013-05-22 15:13:18 +0000650 { "__gc", lpaint_gc },
651 { NULL, NULL }
652};
653
654///////////////////////////////////////////////////////////////////////////////
655
humper@google.com2815c192013-07-10 22:42:30 +0000656static int lmatrix_getType(lua_State* L) {
657 SkMatrix::TypeMask mask = get_obj<SkMatrix>(L, 1)->getType();
658
659 lua_newtable(L);
660 setfield_boolean(L, "translate", SkToBool(mask & SkMatrix::kTranslate_Mask));
661 setfield_boolean(L, "scale", SkToBool(mask & SkMatrix::kScale_Mask));
662 setfield_boolean(L, "affine", SkToBool(mask & SkMatrix::kAffine_Mask));
663 setfield_boolean(L, "perspective", SkToBool(mask & SkMatrix::kPerspective_Mask));
664 return 1;
665}
666
667static const struct luaL_Reg gSkMatrix_Methods[] = {
668 { "getType", lmatrix_getType },
669 { NULL, NULL }
670};
671
672///////////////////////////////////////////////////////////////////////////////
673
reed@google.com74ce6f02013-05-22 15:13:18 +0000674static int lpath_getBounds(lua_State* L) {
675 SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
676 return 1;
677}
678
679static int lpath_isEmpty(lua_State* L) {
680 lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
681 return 1;
682}
683
684static int lpath_isRect(lua_State* L) {
685 SkRect r;
686 bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
687 int ret_count = 1;
688 lua_pushboolean(L, pred);
689 if (pred) {
690 SkLua(L).pushRect(r);
691 ret_count += 1;
692 }
693 return ret_count;
694}
695
696static const char* dir2string(SkPath::Direction dir) {
697 static const char* gStr[] = {
698 "unknown", "cw", "ccw"
699 };
700 SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
701 return gStr[dir];
702}
703
704static int lpath_isNestedRects(lua_State* L) {
705 SkRect rects[2];
706 SkPath::Direction dirs[2];
707 bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
708 int ret_count = 1;
709 lua_pushboolean(L, pred);
710 if (pred) {
711 SkLua lua(L);
712 lua.pushRect(rects[0]);
713 lua.pushRect(rects[1]);
714 lua_pushstring(L, dir2string(dirs[0]));
715 lua_pushstring(L, dir2string(dirs[0]));
716 ret_count += 4;
717 }
718 return ret_count;
719}
720
721static int lpath_reset(lua_State* L) {
722 get_obj<SkPath>(L, 1)->reset();
723 return 0;
724}
725
726static int lpath_moveTo(lua_State* L) {
727 get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
728 return 0;
729}
730
731static int lpath_lineTo(lua_State* L) {
732 get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
733 return 0;
734}
735
736static int lpath_quadTo(lua_State* L) {
737 get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
738 lua2scalar(L, 4), lua2scalar(L, 5));
739 return 0;
740}
741
742static int lpath_cubicTo(lua_State* L) {
743 get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
744 lua2scalar(L, 4), lua2scalar(L, 5),
745 lua2scalar(L, 6), lua2scalar(L, 7));
746 return 0;
747}
748
749static int lpath_close(lua_State* L) {
750 get_obj<SkPath>(L, 1)->close();
751 return 0;
752}
753
754static int lpath_gc(lua_State* L) {
755 get_obj<SkPath>(L, 1)->~SkPath();
756 return 0;
757}
758
759static const struct luaL_Reg gSkPath_Methods[] = {
760 { "getBounds", lpath_getBounds },
761 { "isEmpty", lpath_isEmpty },
762 { "isRect", lpath_isRect },
763 { "isNestedRects", lpath_isNestedRects },
764 { "reset", lpath_reset },
765 { "moveTo", lpath_moveTo },
766 { "lineTo", lpath_lineTo },
767 { "quadTo", lpath_quadTo },
768 { "cubicTo", lpath_cubicTo },
769 { "close", lpath_close },
770 { "__gc", lpath_gc },
771 { NULL, NULL }
772};
773
774///////////////////////////////////////////////////////////////////////////////
775
776static const char* rrect_type(const SkRRect& rr) {
777 switch (rr.getType()) {
778 case SkRRect::kUnknown_Type: return "unknown";
779 case SkRRect::kEmpty_Type: return "empty";
780 case SkRRect::kRect_Type: return "rect";
781 case SkRRect::kOval_Type: return "oval";
782 case SkRRect::kSimple_Type: return "simple";
783 case SkRRect::kComplex_Type: return "complex";
784 }
785 SkASSERT(!"never get here");
786 return "";
787}
788
789static int lrrect_rect(lua_State* L) {
790 SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
791 return 1;
792}
793
794static int lrrect_type(lua_State* L) {
795 lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
796 return 1;
797}
798
799static int lrrect_radii(lua_State* L) {
800 int corner = lua_tointeger(L, 2);
801 SkVector v;
802 if (corner < 0 || corner > 3) {
803 SkDebugf("bad corner index %d", corner);
804 v.set(0, 0);
805 } else {
806 v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
807 }
808 lua_pushnumber(L, v.fX);
809 lua_pushnumber(L, v.fY);
810 return 2;
811}
812
813static int lrrect_gc(lua_State* L) {
814 get_obj<SkRRect>(L, 1)->~SkRRect();
815 return 0;
816}
817
818static const struct luaL_Reg gSkRRect_Methods[] = {
819 { "rect", lrrect_rect },
820 { "type", lrrect_type },
821 { "radii", lrrect_radii },
822 { "__gc", lrrect_gc },
823 { NULL, NULL }
824};
825
826///////////////////////////////////////////////////////////////////////////////
827
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000828static int limage_width(lua_State* L) {
829 lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
830 return 1;
831}
832
833static int limage_height(lua_State* L) {
834 lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
835 return 1;
836}
837
838static int limage_gc(lua_State* L) {
839 get_ref<SkImage>(L, 1)->unref();
840 return 0;
841}
842
843static const struct luaL_Reg gSkImage_Methods[] = {
844 { "width", limage_width },
845 { "height", limage_height },
846 { "__gc", limage_gc },
847 { NULL, NULL }
848};
849
850///////////////////////////////////////////////////////////////////////////////
851
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000852static int ltypeface_gc(lua_State* L) {
853 get_ref<SkTypeface>(L, 1)->unref();
854 return 0;
855}
856
857static const struct luaL_Reg gSkTypeface_Methods[] = {
858 { "__gc", ltypeface_gc },
859 { NULL, NULL }
860};
861
862///////////////////////////////////////////////////////////////////////////////
863
reed@google.com74ce6f02013-05-22 15:13:18 +0000864class AutoCallLua {
865public:
866 AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
867 lua_getglobal(L, func);
868 if (!lua_isfunction(L, -1)) {
869 int t = lua_type(L, -1);
870 SkDebugf("--- expected function %d\n", t);
871 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000872
reed@google.com74ce6f02013-05-22 15:13:18 +0000873 lua_newtable(L);
874 setfield_string(L, "verb", verb);
875 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000876
reed@google.com74ce6f02013-05-22 15:13:18 +0000877 ~AutoCallLua() {
878 if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
879 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
880 }
881 lua_settop(fL, -1);
882 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000883
reed@google.com74ce6f02013-05-22 15:13:18 +0000884private:
885 lua_State* fL;
886};
887
888#define AUTO_LUA(verb) AutoCallLua acl(fL, fFunc.c_str(), verb)
889
890///////////////////////////////////////////////////////////////////////////////
891
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000892static int lsk_newDocumentPDF(lua_State* L) {
893 const char* file = NULL;
894 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
895 file = lua_tolstring(L, 1, NULL);
896 }
897
898 SkDocument* doc = SkDocument::CreatePDF(file);
899 if (NULL == doc) {
900 // do I need to push a nil on the stack and return 1?
901 return 0;
902 } else {
903 push_ref(L, doc);
904 doc->unref();
905 return 1;
906 }
907}
908
reed@google.com3597b732013-05-22 20:12:50 +0000909static int lsk_newPaint(lua_State* L) {
910 push_new<SkPaint>(L);
911 return 1;
912}
913
914static int lsk_newPath(lua_State* L) {
915 push_new<SkPath>(L);
916 return 1;
917}
918
919static int lsk_newRRect(lua_State* L) {
920 SkRRect* rr = push_new<SkRRect>(L);
921 rr->setEmpty();
922 return 1;
923}
924
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000925static int lsk_newTypeface(lua_State* L) {
926 const char* name = NULL;
927 int style = SkTypeface::kNormal;
skia.committer@gmail.com63193672013-06-08 07:01:13 +0000928
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000929 int count = lua_gettop(L);
930 if (count > 0 && lua_isstring(L, 1)) {
931 name = lua_tolstring(L, 1, NULL);
932 if (count > 1 && lua_isnumber(L, 2)) {
933 style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
934 }
935 }
936
937 SkTypeface* face = SkTypeface::CreateFromName(name,
938 (SkTypeface::Style)style);
939// SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
940 if (NULL == face) {
941 face = SkTypeface::RefDefault();
942 }
943 push_ref(L, face);
944 face->unref();
945 return 1;
946}
reed@google.com3597b732013-05-22 20:12:50 +0000947
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000948static int lsk_loadImage(lua_State* L) {
949 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
950 const char* name = lua_tolstring(L, 1, NULL);
951 SkAutoDataUnref data(SkData::NewFromFileName(name));
952 if (data.get()) {
953 SkImage* image = SkImage::NewEncodedData(data.get());
954 if (image) {
955 push_ref(L, image);
956 image->unref();
957 return 1;
958 }
959 }
960 }
961 return 0;
962}
963
reed@google.com3597b732013-05-22 20:12:50 +0000964static void register_Sk(lua_State* L) {
965 lua_newtable(L);
966 lua_pushvalue(L, -1);
967 lua_setglobal(L, "Sk");
968 // the Sk table is still on top
969
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000970 setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000971 setfield_function(L, "loadImage", lsk_loadImage);
reed@google.com3597b732013-05-22 20:12:50 +0000972 setfield_function(L, "newPaint", lsk_newPaint);
973 setfield_function(L, "newPath", lsk_newPath);
974 setfield_function(L, "newRRect", lsk_newRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000975 setfield_function(L, "newTypeface", lsk_newTypeface);
reed@google.com3597b732013-05-22 20:12:50 +0000976 lua_pop(L, 1); // pop off the Sk table
977}
978
reed@google.com74ce6f02013-05-22 15:13:18 +0000979#define REG_CLASS(L, C) \
980 do { \
reed@google.com3597b732013-05-22 20:12:50 +0000981 luaL_newmetatable(L, get_mtname<C>()); \
reed@google.com74ce6f02013-05-22 15:13:18 +0000982 lua_pushvalue(L, -1); \
983 lua_setfield(L, -2, "__index"); \
984 luaL_setfuncs(L, g##C##_Methods, 0); \
985 lua_pop(L, 1); /* pop off the meta-table */ \
986 } while (0)
987
988void SkLua::Load(lua_State* L) {
reed@google.com3597b732013-05-22 20:12:50 +0000989 register_Sk(L);
reed@google.com74ce6f02013-05-22 15:13:18 +0000990 REG_CLASS(L, SkCanvas);
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000991 REG_CLASS(L, SkDocument);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000992 REG_CLASS(L, SkImage);
reed@google.com74ce6f02013-05-22 15:13:18 +0000993 REG_CLASS(L, SkPath);
994 REG_CLASS(L, SkPaint);
995 REG_CLASS(L, SkRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000996 REG_CLASS(L, SkTypeface);
humper@google.com2815c192013-07-10 22:42:30 +0000997 REG_CLASS(L, SkMatrix);
reed@google.com74ce6f02013-05-22 15:13:18 +0000998}
zachr@google.com28c27c82013-06-20 17:15:05 +0000999
reed@google.com7bce9982013-06-20 17:40:21 +00001000extern "C" int luaopen_skia(lua_State* L);
zachr@google.com28c27c82013-06-20 17:15:05 +00001001extern "C" int luaopen_skia(lua_State* L) {
1002 SkLua::Load(L);
1003 return 0;
1004}