blob: 296229bf2193e0dcaece5f8e7ebd826476cb6417 [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.com74ce6f02013-05-22 15:13:18 +0000114static void setfield_string(lua_State* L, const char key[], const char value[]) {
115 lua_pushstring(L, value);
116 lua_setfield(L, -2, key);
117}
118
119static void setfield_number(lua_State* L, const char key[], double value) {
120 lua_pushnumber(L, value);
121 lua_setfield(L, -2, key);
122}
123
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000124static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
125 setfield_number(L, key, SkScalarToLua(value));
126}
127
reed@google.com3597b732013-05-22 20:12:50 +0000128static void setfield_function(lua_State* L,
129 const char key[], lua_CFunction value) {
130 lua_pushcfunction(L, value);
131 lua_setfield(L, -2, key);
reed@google.com74ce6f02013-05-22 15:13:18 +0000132}
133
reed@google.come3823fd2013-05-30 18:55:14 +0000134static void setarray_number(lua_State* L, int index, double value) {
135 lua_pushnumber(L, value);
136 lua_rawseti(L, -2, index);
137}
138
reed@google.com74ce6f02013-05-22 15:13:18 +0000139void SkLua::pushBool(bool value, const char key[]) {
140 lua_pushboolean(fL, value);
141 CHECK_SETFIELD(key);
142}
143
144void SkLua::pushString(const char str[], const char key[]) {
145 lua_pushstring(fL, str);
146 CHECK_SETFIELD(key);
147}
148
reed@google.come3823fd2013-05-30 18:55:14 +0000149void SkLua::pushString(const char str[], size_t length, const char key[]) {
150 // TODO: how to do this w/o making a copy?
151 SkString s(str, length);
152 lua_pushstring(fL, s.c_str());
153 CHECK_SETFIELD(key);
154}
155
reed@google.com74ce6f02013-05-22 15:13:18 +0000156void SkLua::pushString(const SkString& str, const char key[]) {
157 lua_pushstring(fL, str.c_str());
158 CHECK_SETFIELD(key);
159}
160
161void SkLua::pushColor(SkColor color, const char key[]) {
162 lua_newtable(fL);
163 setfield_number(fL, "a", SkColorGetA(color) / 255.0);
164 setfield_number(fL, "r", SkColorGetR(color) / 255.0);
165 setfield_number(fL, "g", SkColorGetG(color) / 255.0);
166 setfield_number(fL, "b", SkColorGetB(color) / 255.0);
167 CHECK_SETFIELD(key);
168}
169
reed@google.come3823fd2013-05-30 18:55:14 +0000170void SkLua::pushU32(uint32_t value, const char key[]) {
171 lua_pushnumber(fL, (double)value);
172 CHECK_SETFIELD(key);
173}
174
reed@google.com74ce6f02013-05-22 15:13:18 +0000175void SkLua::pushScalar(SkScalar value, const char key[]) {
176 lua_pushnumber(fL, SkScalarToLua(value));
177 CHECK_SETFIELD(key);
178}
179
reed@google.come3823fd2013-05-30 18:55:14 +0000180void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
181 lua_newtable(fL);
182 for (int i = 0; i < count; ++i) {
183 // make it base-1 to match lua convention
184 setarray_number(fL, i + 1, (double)array[i]);
185 }
186 CHECK_SETFIELD(key);
187}
188
reed@google.com74ce6f02013-05-22 15:13:18 +0000189void SkLua::pushRect(const SkRect& r, const char key[]) {
190 lua_newtable(fL);
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000191 setfield_scalar(fL, "left", r.fLeft);
192 setfield_scalar(fL, "top", r.fTop);
193 setfield_scalar(fL, "right", r.fRight);
194 setfield_scalar(fL, "bottom", r.fBottom);
reed@google.com74ce6f02013-05-22 15:13:18 +0000195 CHECK_SETFIELD(key);
196}
197
198void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
199 push_obj(fL, rr);
200 CHECK_SETFIELD(key);
201}
202
203void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
204 push_obj(fL, matrix);
205 CHECK_SETFIELD(key);
206}
207
208void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
209 push_obj(fL, paint);
210 CHECK_SETFIELD(key);
211}
212
213void SkLua::pushPath(const SkPath& path, const char key[]) {
214 push_obj(fL, path);
215 CHECK_SETFIELD(key);
216}
217
218void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
219 push_ref(fL, canvas);
220 CHECK_SETFIELD(key);
221}
222
223///////////////////////////////////////////////////////////////////////////////
224///////////////////////////////////////////////////////////////////////////////
225
226static SkScalar lua2scalar(lua_State* L, int index) {
227 SkASSERT(lua_isnumber(L, index));
228 return SkLuaToScalar(lua_tonumber(L, index));
229}
230
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000231static SkScalar lua2scalar_def(lua_State* L, int index, SkScalar defaultValue) {
232 if (lua_isnumber(L, index)) {
233 return SkLuaToScalar(lua_tonumber(L, index));
234 } else {
235 return defaultValue;
236 }
237}
238
reed@google.com74ce6f02013-05-22 15:13:18 +0000239static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
240 SkASSERT(lua_istable(L, index));
241 lua_pushstring(L, key);
242 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000243
reed@google.com74ce6f02013-05-22 15:13:18 +0000244 SkScalar value = lua2scalar(L, -1);
245 lua_pop(L, 1);
246 return value;
247}
248
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000249static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
250 SkASSERT(lua_istable(L, index));
251 lua_pushstring(L, key);
252 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000253
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000254 SkScalar value;
255 if (lua_isnil(L, -1)) {
256 value = def;
257 } else {
258 value = lua2scalar(L, -1);
259 }
260 lua_pop(L, 1);
261 return value;
262}
263
reed@google.com74ce6f02013-05-22 15:13:18 +0000264static U8CPU unit2byte(SkScalar x) {
265 if (x <= 0) {
266 return 0;
267 } else if (x >= 1) {
268 return 255;
269 } else {
270 return SkScalarRoundToInt(x * 255);
271 }
272}
273
274static SkColor lua2color(lua_State* L, int index) {
275 return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
276 unit2byte(getfield_scalar(L, index, "r")),
277 unit2byte(getfield_scalar(L, index, "g")),
278 unit2byte(getfield_scalar(L, index, "b")));
279}
280
281static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000282 rect->set(getfield_scalar_default(L, index, "left", 0),
283 getfield_scalar_default(L, index, "top", 0),
reed@google.com74ce6f02013-05-22 15:13:18 +0000284 getfield_scalar(L, index, "right"),
285 getfield_scalar(L, index, "bottom"));
286 return rect;
287}
288
289static int lcanvas_drawColor(lua_State* L) {
290 get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
291 return 0;
292}
293
294static int lcanvas_drawRect(lua_State* L) {
295 SkRect rect;
296 get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
297 *get_obj<SkPaint>(L, 3));
298 return 0;
299}
300
301static int lcanvas_drawOval(lua_State* L) {
302 SkRect rect;
303 get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
304 *get_obj<SkPaint>(L, 3));
305 return 0;
306}
307
308static int lcanvas_drawCircle(lua_State* L) {
309 get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
310 lua2scalar(L, 3),
311 lua2scalar(L, 4),
312 *get_obj<SkPaint>(L, 5));
313 return 0;
314}
315
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000316static int lcanvas_drawImage(lua_State* L) {
317 SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
318 SkImage* image = get_ref<SkImage>(L, 2);
319 if (NULL == image) {
320 return 0;
321 }
322 SkScalar x = lua2scalar(L, 3);
323 SkScalar y = lua2scalar(L, 4);
324
325 SkPaint paint;
326 const SkPaint* paintPtr = NULL;
327 if (lua_isnumber(L, 5)) {
328 paint.setAlpha(SkScalarRoundToInt(lua2scalar(L, 5) * 255));
329 paintPtr = &paint;
330 }
331 image->draw(canvas, x, y, paintPtr);
332 return 0;
333}
334
reed@google.comfd345872013-05-22 20:53:42 +0000335static int lcanvas_drawPath(lua_State* L) {
336 get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
337 *get_obj<SkPaint>(L, 3));
338 return 0;
339}
340
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000341static int lcanvas_drawText(lua_State* L) {
342 if (lua_gettop(L) < 5) {
343 return 0;
344 }
345
346 if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
347 size_t len;
348 const char* text = lua_tolstring(L, 2, &len);
349 get_ref<SkCanvas>(L, 1)->drawText(text, len,
350 lua2scalar(L, 3), lua2scalar(L, 4),
351 *get_obj<SkPaint>(L, 5));
352 }
353 return 0;
354}
355
reed@google.com74ce6f02013-05-22 15:13:18 +0000356static int lcanvas_getSaveCount(lua_State* L) {
357 lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
358 return 1;
359}
360
361static int lcanvas_getTotalMatrix(lua_State* L) {
362 SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
363 return 1;
364}
365
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000366static int lcanvas_save(lua_State* L) {
367 lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
368 return 1;
369}
370
371static int lcanvas_restore(lua_State* L) {
372 get_ref<SkCanvas>(L, 1)->restore();
373 return 0;
374}
375
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000376static int lcanvas_scale(lua_State* L) {
377 SkScalar sx = lua2scalar_def(L, 2, 1);
378 SkScalar sy = lua2scalar_def(L, 3, sx);
379 get_ref<SkCanvas>(L, 1)->scale(sx, sy);
380 return 0;
381}
382
reed@google.com3597b732013-05-22 20:12:50 +0000383static int lcanvas_translate(lua_State* L) {
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000384 SkScalar tx = lua2scalar_def(L, 2, 0);
385 SkScalar ty = lua2scalar_def(L, 3, 0);
386 get_ref<SkCanvas>(L, 1)->translate(tx, ty);
387 return 0;
388}
389
390static int lcanvas_rotate(lua_State* L) {
391 SkScalar degrees = lua2scalar_def(L, 2, 0);
392 get_ref<SkCanvas>(L, 1)->rotate(degrees);
reed@google.com3597b732013-05-22 20:12:50 +0000393 return 0;
394}
395
reed@google.com74ce6f02013-05-22 15:13:18 +0000396static int lcanvas_gc(lua_State* L) {
397 get_ref<SkCanvas>(L, 1)->unref();
398 return 0;
399}
400
401static const struct luaL_Reg gSkCanvas_Methods[] = {
402 { "drawColor", lcanvas_drawColor },
403 { "drawRect", lcanvas_drawRect },
404 { "drawOval", lcanvas_drawOval },
405 { "drawCircle", lcanvas_drawCircle },
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000406 { "drawImage", lcanvas_drawImage },
reed@google.comfd345872013-05-22 20:53:42 +0000407 { "drawPath", lcanvas_drawPath },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000408 { "drawText", lcanvas_drawText },
reed@google.com74ce6f02013-05-22 15:13:18 +0000409 { "getSaveCount", lcanvas_getSaveCount },
410 { "getTotalMatrix", lcanvas_getTotalMatrix },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000411 { "save", lcanvas_save },
412 { "restore", lcanvas_restore },
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000413 { "scale", lcanvas_scale },
reed@google.com3597b732013-05-22 20:12:50 +0000414 { "translate", lcanvas_translate },
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000415 { "rotate", lcanvas_rotate },
reed@google.com74ce6f02013-05-22 15:13:18 +0000416 { "__gc", lcanvas_gc },
417 { NULL, NULL }
418};
419
420///////////////////////////////////////////////////////////////////////////////
421
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000422static int ldocument_beginPage(lua_State* L) {
423 const SkRect* contentPtr = NULL;
424 push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
425 lua2scalar(L, 3),
426 contentPtr));
427 return 1;
428}
429
430static int ldocument_endPage(lua_State* L) {
431 get_ref<SkDocument>(L, 1)->endPage();
432 return 0;
433}
434
435static int ldocument_close(lua_State* L) {
436 get_ref<SkDocument>(L, 1)->close();
437 return 0;
438}
439
440static int ldocument_gc(lua_State* L) {
441 get_ref<SkDocument>(L, 1)->unref();
442 return 0;
443}
444
445static const struct luaL_Reg gSkDocument_Methods[] = {
446 { "beginPage", ldocument_beginPage },
447 { "endPage", ldocument_endPage },
448 { "close", ldocument_close },
449 { "__gc", ldocument_gc },
450 { NULL, NULL }
451};
452
453///////////////////////////////////////////////////////////////////////////////
454
reed@google.com74ce6f02013-05-22 15:13:18 +0000455static int lpaint_isAntiAlias(lua_State* L) {
456 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
457 return 1;
458}
459
460static int lpaint_setAntiAlias(lua_State* L) {
reed@google.com88c9ec92013-05-22 15:43:21 +0000461 get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
reed@google.com74ce6f02013-05-22 15:13:18 +0000462 return 0;
463}
464
465static int lpaint_getColor(lua_State* L) {
466 SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
467 return 1;
468}
469
470static int lpaint_setColor(lua_State* L) {
471 get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
472 return 0;
473}
474
reed@google.come3823fd2013-05-30 18:55:14 +0000475static int lpaint_getTextSize(lua_State* L) {
476 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
477 return 1;
478}
479
480static int lpaint_setTextSize(lua_State* L) {
481 get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
482 return 0;
483}
484
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000485static int lpaint_getTypeface(lua_State* L) {
486 push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
487 return 1;
488}
489
490static int lpaint_setTypeface(lua_State* L) {
491 get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
492 return 0;
493}
494
reed@google.come3823fd2013-05-30 18:55:14 +0000495static int lpaint_getFontID(lua_State* L) {
496 SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
497 SkLua(L).pushU32(SkTypeface::UniqueID(face));
498 return 1;
499}
500
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000501static const struct {
502 const char* fLabel;
503 SkPaint::Align fAlign;
504} gAlignRec[] = {
505 { "left", SkPaint::kLeft_Align },
506 { "center", SkPaint::kCenter_Align },
507 { "right", SkPaint::kRight_Align },
508};
509
510static int lpaint_getTextAlign(lua_State* L) {
511 SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
512 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
513 if (gAlignRec[i].fAlign == align) {
514 lua_pushstring(L, gAlignRec[i].fLabel);
515 return 1;
516 }
517 }
518 return 0;
519}
520
521static int lpaint_setTextAlign(lua_State* L) {
522 if (lua_isstring(L, 2)) {
523 size_t len;
524 const char* label = lua_tolstring(L, 2, &len);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000525
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000526 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
527 if (!strcmp(gAlignRec[i].fLabel, label)) {
528 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
529 break;
530 }
531 }
532 }
533 return 0;
534}
535
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000536static int lpaint_getStroke(lua_State* L) {
537 lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
538 return 1;
539}
540
541static int lpaint_setStroke(lua_State* L) {
542 SkPaint::Style style;
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000543
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000544 if (lua_toboolean(L, 2)) {
545 style = SkPaint::kStroke_Style;
546 } else {
547 style = SkPaint::kFill_Style;
548 }
549 get_obj<SkPaint>(L, 1)->setStyle(style);
550 return 0;
551}
552
553static int lpaint_getStrokeWidth(lua_State* L) {
554 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
555 return 1;
556}
557
558static int lpaint_setStrokeWidth(lua_State* L) {
559 get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
560 return 0;
561}
562
563static int lpaint_measureText(lua_State* L) {
564 if (lua_isstring(L, 2)) {
565 size_t len;
566 const char* text = lua_tolstring(L, 2, &len);
567 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
568 return 1;
569 }
570 return 0;
571}
572
573struct FontMetrics {
574 SkScalar fTop; //!< The greatest distance above the baseline for any glyph (will be <= 0)
575 SkScalar fAscent; //!< The recommended distance above the baseline (will be <= 0)
576 SkScalar fDescent; //!< The recommended distance below the baseline (will be >= 0)
577 SkScalar fBottom; //!< The greatest distance below the baseline for any glyph (will be >= 0)
578 SkScalar fLeading; //!< The recommended distance to add between lines of text (will be >= 0)
579 SkScalar fAvgCharWidth; //!< the average charactor width (>= 0)
580 SkScalar fXMin; //!< The minimum bounding box x value for all glyphs
581 SkScalar fXMax; //!< The maximum bounding box x value for all glyphs
582 SkScalar fXHeight; //!< the height of an 'x' in px, or 0 if no 'x' in face
583};
584
585static int lpaint_getFontMetrics(lua_State* L) {
586 SkPaint::FontMetrics fm;
587 SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000588
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000589 lua_newtable(L);
590 setfield_scalar(L, "top", fm.fTop);
591 setfield_scalar(L, "ascent", fm.fAscent);
592 setfield_scalar(L, "descent", fm.fDescent);
593 setfield_scalar(L, "bottom", fm.fBottom);
594 setfield_scalar(L, "leading", fm.fLeading);
595 SkLua(L).pushScalar(height);
596 return 2;
597}
598
reed@google.com74ce6f02013-05-22 15:13:18 +0000599static int lpaint_gc(lua_State* L) {
600 get_obj<SkPaint>(L, 1)->~SkPaint();
601 return 0;
602}
603
604static const struct luaL_Reg gSkPaint_Methods[] = {
605 { "isAntiAlias", lpaint_isAntiAlias },
606 { "setAntiAlias", lpaint_setAntiAlias },
607 { "getColor", lpaint_getColor },
608 { "setColor", lpaint_setColor },
reed@google.come3823fd2013-05-30 18:55:14 +0000609 { "getTextSize", lpaint_getTextSize },
610 { "setTextSize", lpaint_setTextSize },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000611 { "getTypeface", lpaint_getTypeface },
612 { "setTypeface", lpaint_setTypeface },
reed@google.come3823fd2013-05-30 18:55:14 +0000613 { "getFontID", lpaint_getFontID },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000614 { "getTextAlign", lpaint_getTextAlign },
615 { "setTextAlign", lpaint_setTextAlign },
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000616 { "getStroke", lpaint_getStroke },
617 { "setStroke", lpaint_setStroke },
618 { "getStrokeWidth", lpaint_getStrokeWidth },
619 { "setStrokeWidth", lpaint_setStrokeWidth },
620 { "measureText", lpaint_measureText },
621 { "getFontMetrics", lpaint_getFontMetrics },
reed@google.com74ce6f02013-05-22 15:13:18 +0000622 { "__gc", lpaint_gc },
623 { NULL, NULL }
624};
625
626///////////////////////////////////////////////////////////////////////////////
627
628static int lpath_getBounds(lua_State* L) {
629 SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
630 return 1;
631}
632
633static int lpath_isEmpty(lua_State* L) {
634 lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
635 return 1;
636}
637
638static int lpath_isRect(lua_State* L) {
639 SkRect r;
640 bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
641 int ret_count = 1;
642 lua_pushboolean(L, pred);
643 if (pred) {
644 SkLua(L).pushRect(r);
645 ret_count += 1;
646 }
647 return ret_count;
648}
649
650static const char* dir2string(SkPath::Direction dir) {
651 static const char* gStr[] = {
652 "unknown", "cw", "ccw"
653 };
654 SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
655 return gStr[dir];
656}
657
658static int lpath_isNestedRects(lua_State* L) {
659 SkRect rects[2];
660 SkPath::Direction dirs[2];
661 bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
662 int ret_count = 1;
663 lua_pushboolean(L, pred);
664 if (pred) {
665 SkLua lua(L);
666 lua.pushRect(rects[0]);
667 lua.pushRect(rects[1]);
668 lua_pushstring(L, dir2string(dirs[0]));
669 lua_pushstring(L, dir2string(dirs[0]));
670 ret_count += 4;
671 }
672 return ret_count;
673}
674
675static int lpath_reset(lua_State* L) {
676 get_obj<SkPath>(L, 1)->reset();
677 return 0;
678}
679
680static int lpath_moveTo(lua_State* L) {
681 get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
682 return 0;
683}
684
685static int lpath_lineTo(lua_State* L) {
686 get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
687 return 0;
688}
689
690static int lpath_quadTo(lua_State* L) {
691 get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
692 lua2scalar(L, 4), lua2scalar(L, 5));
693 return 0;
694}
695
696static int lpath_cubicTo(lua_State* L) {
697 get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
698 lua2scalar(L, 4), lua2scalar(L, 5),
699 lua2scalar(L, 6), lua2scalar(L, 7));
700 return 0;
701}
702
703static int lpath_close(lua_State* L) {
704 get_obj<SkPath>(L, 1)->close();
705 return 0;
706}
707
708static int lpath_gc(lua_State* L) {
709 get_obj<SkPath>(L, 1)->~SkPath();
710 return 0;
711}
712
713static const struct luaL_Reg gSkPath_Methods[] = {
714 { "getBounds", lpath_getBounds },
715 { "isEmpty", lpath_isEmpty },
716 { "isRect", lpath_isRect },
717 { "isNestedRects", lpath_isNestedRects },
718 { "reset", lpath_reset },
719 { "moveTo", lpath_moveTo },
720 { "lineTo", lpath_lineTo },
721 { "quadTo", lpath_quadTo },
722 { "cubicTo", lpath_cubicTo },
723 { "close", lpath_close },
724 { "__gc", lpath_gc },
725 { NULL, NULL }
726};
727
728///////////////////////////////////////////////////////////////////////////////
729
730static const char* rrect_type(const SkRRect& rr) {
731 switch (rr.getType()) {
732 case SkRRect::kUnknown_Type: return "unknown";
733 case SkRRect::kEmpty_Type: return "empty";
734 case SkRRect::kRect_Type: return "rect";
735 case SkRRect::kOval_Type: return "oval";
736 case SkRRect::kSimple_Type: return "simple";
737 case SkRRect::kComplex_Type: return "complex";
738 }
739 SkASSERT(!"never get here");
740 return "";
741}
742
743static int lrrect_rect(lua_State* L) {
744 SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
745 return 1;
746}
747
748static int lrrect_type(lua_State* L) {
749 lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
750 return 1;
751}
752
753static int lrrect_radii(lua_State* L) {
754 int corner = lua_tointeger(L, 2);
755 SkVector v;
756 if (corner < 0 || corner > 3) {
757 SkDebugf("bad corner index %d", corner);
758 v.set(0, 0);
759 } else {
760 v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
761 }
762 lua_pushnumber(L, v.fX);
763 lua_pushnumber(L, v.fY);
764 return 2;
765}
766
767static int lrrect_gc(lua_State* L) {
768 get_obj<SkRRect>(L, 1)->~SkRRect();
769 return 0;
770}
771
772static const struct luaL_Reg gSkRRect_Methods[] = {
773 { "rect", lrrect_rect },
774 { "type", lrrect_type },
775 { "radii", lrrect_radii },
776 { "__gc", lrrect_gc },
777 { NULL, NULL }
778};
779
780///////////////////////////////////////////////////////////////////////////////
781
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000782static int limage_width(lua_State* L) {
783 lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
784 return 1;
785}
786
787static int limage_height(lua_State* L) {
788 lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
789 return 1;
790}
791
792static int limage_gc(lua_State* L) {
793 get_ref<SkImage>(L, 1)->unref();
794 return 0;
795}
796
797static const struct luaL_Reg gSkImage_Methods[] = {
798 { "width", limage_width },
799 { "height", limage_height },
800 { "__gc", limage_gc },
801 { NULL, NULL }
802};
803
804///////////////////////////////////////////////////////////////////////////////
805
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000806static int ltypeface_gc(lua_State* L) {
807 get_ref<SkTypeface>(L, 1)->unref();
808 return 0;
809}
810
811static const struct luaL_Reg gSkTypeface_Methods[] = {
812 { "__gc", ltypeface_gc },
813 { NULL, NULL }
814};
815
816///////////////////////////////////////////////////////////////////////////////
817
reed@google.com74ce6f02013-05-22 15:13:18 +0000818class AutoCallLua {
819public:
820 AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
821 lua_getglobal(L, func);
822 if (!lua_isfunction(L, -1)) {
823 int t = lua_type(L, -1);
824 SkDebugf("--- expected function %d\n", t);
825 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000826
reed@google.com74ce6f02013-05-22 15:13:18 +0000827 lua_newtable(L);
828 setfield_string(L, "verb", verb);
829 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000830
reed@google.com74ce6f02013-05-22 15:13:18 +0000831 ~AutoCallLua() {
832 if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
833 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
834 }
835 lua_settop(fL, -1);
836 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000837
reed@google.com74ce6f02013-05-22 15:13:18 +0000838private:
839 lua_State* fL;
840};
841
842#define AUTO_LUA(verb) AutoCallLua acl(fL, fFunc.c_str(), verb)
843
844///////////////////////////////////////////////////////////////////////////////
845
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000846static int lsk_newDocumentPDF(lua_State* L) {
847 const char* file = NULL;
848 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
849 file = lua_tolstring(L, 1, NULL);
850 }
851
852 SkDocument* doc = SkDocument::CreatePDF(file);
853 if (NULL == doc) {
854 // do I need to push a nil on the stack and return 1?
855 return 0;
856 } else {
857 push_ref(L, doc);
858 doc->unref();
859 return 1;
860 }
861}
862
reed@google.com3597b732013-05-22 20:12:50 +0000863static int lsk_newPaint(lua_State* L) {
864 push_new<SkPaint>(L);
865 return 1;
866}
867
868static int lsk_newPath(lua_State* L) {
869 push_new<SkPath>(L);
870 return 1;
871}
872
873static int lsk_newRRect(lua_State* L) {
874 SkRRect* rr = push_new<SkRRect>(L);
875 rr->setEmpty();
876 return 1;
877}
878
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000879static int lsk_newTypeface(lua_State* L) {
880 const char* name = NULL;
881 int style = SkTypeface::kNormal;
skia.committer@gmail.com63193672013-06-08 07:01:13 +0000882
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000883 int count = lua_gettop(L);
884 if (count > 0 && lua_isstring(L, 1)) {
885 name = lua_tolstring(L, 1, NULL);
886 if (count > 1 && lua_isnumber(L, 2)) {
887 style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
888 }
889 }
890
891 SkTypeface* face = SkTypeface::CreateFromName(name,
892 (SkTypeface::Style)style);
893// SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
894 if (NULL == face) {
895 face = SkTypeface::RefDefault();
896 }
897 push_ref(L, face);
898 face->unref();
899 return 1;
900}
reed@google.com3597b732013-05-22 20:12:50 +0000901
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000902static int lsk_loadImage(lua_State* L) {
903 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
904 const char* name = lua_tolstring(L, 1, NULL);
905 SkAutoDataUnref data(SkData::NewFromFileName(name));
906 if (data.get()) {
907 SkImage* image = SkImage::NewEncodedData(data.get());
908 if (image) {
909 push_ref(L, image);
910 image->unref();
911 return 1;
912 }
913 }
914 }
915 return 0;
916}
917
reed@google.com3597b732013-05-22 20:12:50 +0000918static void register_Sk(lua_State* L) {
919 lua_newtable(L);
920 lua_pushvalue(L, -1);
921 lua_setglobal(L, "Sk");
922 // the Sk table is still on top
923
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000924 setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000925 setfield_function(L, "loadImage", lsk_loadImage);
reed@google.com3597b732013-05-22 20:12:50 +0000926 setfield_function(L, "newPaint", lsk_newPaint);
927 setfield_function(L, "newPath", lsk_newPath);
928 setfield_function(L, "newRRect", lsk_newRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000929 setfield_function(L, "newTypeface", lsk_newTypeface);
reed@google.com3597b732013-05-22 20:12:50 +0000930 lua_pop(L, 1); // pop off the Sk table
931}
932
reed@google.com74ce6f02013-05-22 15:13:18 +0000933#define REG_CLASS(L, C) \
934 do { \
reed@google.com3597b732013-05-22 20:12:50 +0000935 luaL_newmetatable(L, get_mtname<C>()); \
reed@google.com74ce6f02013-05-22 15:13:18 +0000936 lua_pushvalue(L, -1); \
937 lua_setfield(L, -2, "__index"); \
938 luaL_setfuncs(L, g##C##_Methods, 0); \
939 lua_pop(L, 1); /* pop off the meta-table */ \
940 } while (0)
941
942void SkLua::Load(lua_State* L) {
reed@google.com3597b732013-05-22 20:12:50 +0000943 register_Sk(L);
reed@google.com74ce6f02013-05-22 15:13:18 +0000944 REG_CLASS(L, SkCanvas);
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000945 REG_CLASS(L, SkDocument);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000946 REG_CLASS(L, SkImage);
reed@google.com74ce6f02013-05-22 15:13:18 +0000947 REG_CLASS(L, SkPath);
948 REG_CLASS(L, SkPaint);
949 REG_CLASS(L, SkRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000950 REG_CLASS(L, SkTypeface);
reed@google.com74ce6f02013-05-22 15:13:18 +0000951}
zachr@google.com28c27c82013-06-20 17:15:05 +0000952
953extern "C" int luaopen_skia(lua_State* L) {
954 SkLua::Load(L);
955 return 0;
956}