blob: 3c8c9f507049d2ea4b304a7d3543ee469cb4edea [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.orgfb858242013-06-08 16:39:44 +000010#include "SkDocument.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000011#include "SkPaint.h"
12#include "SkPath.h"
13#include "SkMatrix.h"
14#include "SkRRect.h"
15#include "SkString.h"
reed@google.come3823fd2013-05-30 18:55:14 +000016#include "SkTypeface.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000017
18extern "C" {
reed@google.com3597b732013-05-22 20:12:50 +000019 #include "lua.h"
20 #include "lualib.h"
21 #include "lauxlib.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000022}
23
reed@google.comfd345872013-05-22 20:53:42 +000024// return the metatable name for a given class
reed@google.com3597b732013-05-22 20:12:50 +000025template <typename T> const char* get_mtname();
reed@google.comfd345872013-05-22 20:53:42 +000026#define DEF_MTNAME(T) \
27 template <> const char* get_mtname<T>() { \
28 return #T "_LuaMetaTableName"; \
29 }
30
31DEF_MTNAME(SkCanvas)
mike@reedtribe.orgfb858242013-06-08 16:39:44 +000032DEF_MTNAME(SkDocument)
reed@google.comfd345872013-05-22 20:53:42 +000033DEF_MTNAME(SkMatrix)
34DEF_MTNAME(SkRRect)
35DEF_MTNAME(SkPath)
36DEF_MTNAME(SkPaint)
mike@reedtribe.orge6469f12013-06-08 03:15:47 +000037DEF_MTNAME(SkTypeface)
reed@google.com74ce6f02013-05-22 15:13:18 +000038
reed@google.com3597b732013-05-22 20:12:50 +000039template <typename T> T* push_new(lua_State* L) {
40 T* addr = (T*)lua_newuserdata(L, sizeof(T));
41 new (addr) T;
42 luaL_getmetatable(L, get_mtname<T>());
43 lua_setmetatable(L, -2);
44 return addr;
45}
reed@google.com74ce6f02013-05-22 15:13:18 +000046
47template <typename T> void push_obj(lua_State* L, const T& obj) {
48 new (lua_newuserdata(L, sizeof(T))) T(obj);
reed@google.com3597b732013-05-22 20:12:50 +000049 luaL_getmetatable(L, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000050 lua_setmetatable(L, -2);
51}
52
53template <typename T> void push_ref(lua_State* L, T* ref) {
54 *(T**)lua_newuserdata(L, sizeof(T*)) = SkRef(ref);
reed@google.com3597b732013-05-22 20:12:50 +000055 luaL_getmetatable(L, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000056 lua_setmetatable(L, -2);
57}
58
59template <typename T> T* get_ref(lua_State* L, int index) {
reed@google.com3597b732013-05-22 20:12:50 +000060 return *(T**)luaL_checkudata(L, index, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000061}
62
63template <typename T> T* get_obj(lua_State* L, int index) {
reed@google.com3597b732013-05-22 20:12:50 +000064 return (T*)luaL_checkudata(L, index, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000065}
66
reed@google.com88c9ec92013-05-22 15:43:21 +000067static bool lua2bool(lua_State* L, int index) {
68 return !!lua_toboolean(L, index);
69}
70
reed@google.com74ce6f02013-05-22 15:13:18 +000071///////////////////////////////////////////////////////////////////////////////
72
reed@google.com3597b732013-05-22 20:12:50 +000073SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) {
74 fL = luaL_newstate();
75 luaL_openlibs(fL);
76 SkLua::Load(fL);
77}
78
79SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {}
80
81SkLua::~SkLua() {
82 if (fWeOwnL) {
83 if (fTermCode.size() > 0) {
84 lua_getglobal(fL, fTermCode.c_str());
85 if (lua_pcall(fL, 0, 0, 0) != LUA_OK) {
86 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
87 }
88 }
89 lua_close(fL);
90 }
91}
92
93bool SkLua::runCode(const char code[]) {
94 int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0);
95 if (err) {
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +000096 SkDebugf("--- lua failed: %s\n", lua_tostring(fL, -1));
reed@google.com3597b732013-05-22 20:12:50 +000097 return false;
98 }
99 return true;
100}
101
102bool SkLua::runCode(const void* code, size_t size) {
103 SkString str((const char*)code, size);
104 return this->runCode(str.c_str());
105}
106
107///////////////////////////////////////////////////////////////////////////////
108
109#define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0)
110
reed@google.com74ce6f02013-05-22 15:13:18 +0000111static void setfield_string(lua_State* L, const char key[], const char value[]) {
112 lua_pushstring(L, value);
113 lua_setfield(L, -2, key);
114}
115
116static void setfield_number(lua_State* L, const char key[], double value) {
117 lua_pushnumber(L, value);
118 lua_setfield(L, -2, key);
119}
120
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000121static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
122 setfield_number(L, key, SkScalarToLua(value));
123}
124
reed@google.com3597b732013-05-22 20:12:50 +0000125static void setfield_function(lua_State* L,
126 const char key[], lua_CFunction value) {
127 lua_pushcfunction(L, value);
128 lua_setfield(L, -2, key);
reed@google.com74ce6f02013-05-22 15:13:18 +0000129}
130
reed@google.come3823fd2013-05-30 18:55:14 +0000131static void setarray_number(lua_State* L, int index, double value) {
132 lua_pushnumber(L, value);
133 lua_rawseti(L, -2, index);
134}
135
reed@google.com74ce6f02013-05-22 15:13:18 +0000136void SkLua::pushBool(bool value, const char key[]) {
137 lua_pushboolean(fL, value);
138 CHECK_SETFIELD(key);
139}
140
141void SkLua::pushString(const char str[], const char key[]) {
142 lua_pushstring(fL, str);
143 CHECK_SETFIELD(key);
144}
145
reed@google.come3823fd2013-05-30 18:55:14 +0000146void SkLua::pushString(const char str[], size_t length, const char key[]) {
147 // TODO: how to do this w/o making a copy?
148 SkString s(str, length);
149 lua_pushstring(fL, s.c_str());
150 CHECK_SETFIELD(key);
151}
152
reed@google.com74ce6f02013-05-22 15:13:18 +0000153void SkLua::pushString(const SkString& str, const char key[]) {
154 lua_pushstring(fL, str.c_str());
155 CHECK_SETFIELD(key);
156}
157
158void SkLua::pushColor(SkColor color, const char key[]) {
159 lua_newtable(fL);
160 setfield_number(fL, "a", SkColorGetA(color) / 255.0);
161 setfield_number(fL, "r", SkColorGetR(color) / 255.0);
162 setfield_number(fL, "g", SkColorGetG(color) / 255.0);
163 setfield_number(fL, "b", SkColorGetB(color) / 255.0);
164 CHECK_SETFIELD(key);
165}
166
reed@google.come3823fd2013-05-30 18:55:14 +0000167void SkLua::pushU32(uint32_t value, const char key[]) {
168 lua_pushnumber(fL, (double)value);
169 CHECK_SETFIELD(key);
170}
171
reed@google.com74ce6f02013-05-22 15:13:18 +0000172void SkLua::pushScalar(SkScalar value, const char key[]) {
173 lua_pushnumber(fL, SkScalarToLua(value));
174 CHECK_SETFIELD(key);
175}
176
reed@google.come3823fd2013-05-30 18:55:14 +0000177void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
178 lua_newtable(fL);
179 for (int i = 0; i < count; ++i) {
180 // make it base-1 to match lua convention
181 setarray_number(fL, i + 1, (double)array[i]);
182 }
183 CHECK_SETFIELD(key);
184}
185
reed@google.com74ce6f02013-05-22 15:13:18 +0000186void SkLua::pushRect(const SkRect& r, const char key[]) {
187 lua_newtable(fL);
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000188 setfield_scalar(fL, "left", r.fLeft);
189 setfield_scalar(fL, "top", r.fTop);
190 setfield_scalar(fL, "right", r.fRight);
191 setfield_scalar(fL, "bottom", r.fBottom);
reed@google.com74ce6f02013-05-22 15:13:18 +0000192 CHECK_SETFIELD(key);
193}
194
195void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
196 push_obj(fL, rr);
197 CHECK_SETFIELD(key);
198}
199
200void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
201 push_obj(fL, matrix);
202 CHECK_SETFIELD(key);
203}
204
205void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
206 push_obj(fL, paint);
207 CHECK_SETFIELD(key);
208}
209
210void SkLua::pushPath(const SkPath& path, const char key[]) {
211 push_obj(fL, path);
212 CHECK_SETFIELD(key);
213}
214
215void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
216 push_ref(fL, canvas);
217 CHECK_SETFIELD(key);
218}
219
220///////////////////////////////////////////////////////////////////////////////
221///////////////////////////////////////////////////////////////////////////////
222
223static SkScalar lua2scalar(lua_State* L, int index) {
224 SkASSERT(lua_isnumber(L, index));
225 return SkLuaToScalar(lua_tonumber(L, index));
226}
227
228static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
229 SkASSERT(lua_istable(L, index));
230 lua_pushstring(L, key);
231 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000232
reed@google.com74ce6f02013-05-22 15:13:18 +0000233 SkScalar value = lua2scalar(L, -1);
234 lua_pop(L, 1);
235 return value;
236}
237
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000238static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
239 SkASSERT(lua_istable(L, index));
240 lua_pushstring(L, key);
241 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000242
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000243 SkScalar value;
244 if (lua_isnil(L, -1)) {
245 value = def;
246 } else {
247 value = lua2scalar(L, -1);
248 }
249 lua_pop(L, 1);
250 return value;
251}
252
reed@google.com74ce6f02013-05-22 15:13:18 +0000253static U8CPU unit2byte(SkScalar x) {
254 if (x <= 0) {
255 return 0;
256 } else if (x >= 1) {
257 return 255;
258 } else {
259 return SkScalarRoundToInt(x * 255);
260 }
261}
262
263static SkColor lua2color(lua_State* L, int index) {
264 return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
265 unit2byte(getfield_scalar(L, index, "r")),
266 unit2byte(getfield_scalar(L, index, "g")),
267 unit2byte(getfield_scalar(L, index, "b")));
268}
269
270static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000271 rect->set(getfield_scalar_default(L, index, "left", 0),
272 getfield_scalar_default(L, index, "top", 0),
reed@google.com74ce6f02013-05-22 15:13:18 +0000273 getfield_scalar(L, index, "right"),
274 getfield_scalar(L, index, "bottom"));
275 return rect;
276}
277
278static int lcanvas_drawColor(lua_State* L) {
279 get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
280 return 0;
281}
282
283static int lcanvas_drawRect(lua_State* L) {
284 SkRect rect;
285 get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
286 *get_obj<SkPaint>(L, 3));
287 return 0;
288}
289
290static int lcanvas_drawOval(lua_State* L) {
291 SkRect rect;
292 get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
293 *get_obj<SkPaint>(L, 3));
294 return 0;
295}
296
297static int lcanvas_drawCircle(lua_State* L) {
298 get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
299 lua2scalar(L, 3),
300 lua2scalar(L, 4),
301 *get_obj<SkPaint>(L, 5));
302 return 0;
303}
304
reed@google.comfd345872013-05-22 20:53:42 +0000305static int lcanvas_drawPath(lua_State* L) {
306 get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
307 *get_obj<SkPaint>(L, 3));
308 return 0;
309}
310
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000311static int lcanvas_drawText(lua_State* L) {
312 if (lua_gettop(L) < 5) {
313 return 0;
314 }
315
316 if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
317 size_t len;
318 const char* text = lua_tolstring(L, 2, &len);
319 get_ref<SkCanvas>(L, 1)->drawText(text, len,
320 lua2scalar(L, 3), lua2scalar(L, 4),
321 *get_obj<SkPaint>(L, 5));
322 }
323 return 0;
324}
325
reed@google.com74ce6f02013-05-22 15:13:18 +0000326static int lcanvas_getSaveCount(lua_State* L) {
327 lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
328 return 1;
329}
330
331static int lcanvas_getTotalMatrix(lua_State* L) {
332 SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
333 return 1;
334}
335
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000336static int lcanvas_save(lua_State* L) {
337 lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
338 return 1;
339}
340
341static int lcanvas_restore(lua_State* L) {
342 get_ref<SkCanvas>(L, 1)->restore();
343 return 0;
344}
345
reed@google.com3597b732013-05-22 20:12:50 +0000346static int lcanvas_translate(lua_State* L) {
347 get_ref<SkCanvas>(L, 1)->translate(lua2scalar(L, 2), lua2scalar(L, 3));
348 return 0;
349}
350
reed@google.com74ce6f02013-05-22 15:13:18 +0000351static int lcanvas_gc(lua_State* L) {
352 get_ref<SkCanvas>(L, 1)->unref();
353 return 0;
354}
355
356static const struct luaL_Reg gSkCanvas_Methods[] = {
357 { "drawColor", lcanvas_drawColor },
358 { "drawRect", lcanvas_drawRect },
359 { "drawOval", lcanvas_drawOval },
360 { "drawCircle", lcanvas_drawCircle },
reed@google.comfd345872013-05-22 20:53:42 +0000361 { "drawPath", lcanvas_drawPath },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000362 { "drawText", lcanvas_drawText },
reed@google.com74ce6f02013-05-22 15:13:18 +0000363 { "getSaveCount", lcanvas_getSaveCount },
364 { "getTotalMatrix", lcanvas_getTotalMatrix },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000365 { "save", lcanvas_save },
366 { "restore", lcanvas_restore },
reed@google.com3597b732013-05-22 20:12:50 +0000367 { "translate", lcanvas_translate },
reed@google.com74ce6f02013-05-22 15:13:18 +0000368 { "__gc", lcanvas_gc },
369 { NULL, NULL }
370};
371
372///////////////////////////////////////////////////////////////////////////////
373
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000374static int ldocument_beginPage(lua_State* L) {
375 const SkRect* contentPtr = NULL;
376 push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
377 lua2scalar(L, 3),
378 contentPtr));
379 return 1;
380}
381
382static int ldocument_endPage(lua_State* L) {
383 get_ref<SkDocument>(L, 1)->endPage();
384 return 0;
385}
386
387static int ldocument_close(lua_State* L) {
388 get_ref<SkDocument>(L, 1)->close();
389 return 0;
390}
391
392static int ldocument_gc(lua_State* L) {
393 get_ref<SkDocument>(L, 1)->unref();
394 return 0;
395}
396
397static const struct luaL_Reg gSkDocument_Methods[] = {
398 { "beginPage", ldocument_beginPage },
399 { "endPage", ldocument_endPage },
400 { "close", ldocument_close },
401 { "__gc", ldocument_gc },
402 { NULL, NULL }
403};
404
405///////////////////////////////////////////////////////////////////////////////
406
reed@google.com74ce6f02013-05-22 15:13:18 +0000407static int lpaint_isAntiAlias(lua_State* L) {
408 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
409 return 1;
410}
411
412static int lpaint_setAntiAlias(lua_State* L) {
reed@google.com88c9ec92013-05-22 15:43:21 +0000413 get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
reed@google.com74ce6f02013-05-22 15:13:18 +0000414 return 0;
415}
416
417static int lpaint_getColor(lua_State* L) {
418 SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
419 return 1;
420}
421
422static int lpaint_setColor(lua_State* L) {
423 get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
424 return 0;
425}
426
reed@google.come3823fd2013-05-30 18:55:14 +0000427static int lpaint_getTextSize(lua_State* L) {
428 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
429 return 1;
430}
431
432static int lpaint_setTextSize(lua_State* L) {
433 get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
434 return 0;
435}
436
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000437static int lpaint_getTypeface(lua_State* L) {
438 push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
439 return 1;
440}
441
442static int lpaint_setTypeface(lua_State* L) {
443 get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
444 return 0;
445}
446
reed@google.come3823fd2013-05-30 18:55:14 +0000447static int lpaint_getFontID(lua_State* L) {
448 SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
449 SkLua(L).pushU32(SkTypeface::UniqueID(face));
450 return 1;
451}
452
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000453static const struct {
454 const char* fLabel;
455 SkPaint::Align fAlign;
456} gAlignRec[] = {
457 { "left", SkPaint::kLeft_Align },
458 { "center", SkPaint::kCenter_Align },
459 { "right", SkPaint::kRight_Align },
460};
461
462static int lpaint_getTextAlign(lua_State* L) {
463 SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
464 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
465 if (gAlignRec[i].fAlign == align) {
466 lua_pushstring(L, gAlignRec[i].fLabel);
467 return 1;
468 }
469 }
470 return 0;
471}
472
473static int lpaint_setTextAlign(lua_State* L) {
474 if (lua_isstring(L, 2)) {
475 size_t len;
476 const char* label = lua_tolstring(L, 2, &len);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000477
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000478 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
479 if (!strcmp(gAlignRec[i].fLabel, label)) {
480 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
481 break;
482 }
483 }
484 }
485 return 0;
486}
487
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000488static int lpaint_getStroke(lua_State* L) {
489 lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
490 return 1;
491}
492
493static int lpaint_setStroke(lua_State* L) {
494 SkPaint::Style style;
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000495
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000496 if (lua_toboolean(L, 2)) {
497 style = SkPaint::kStroke_Style;
498 } else {
499 style = SkPaint::kFill_Style;
500 }
501 get_obj<SkPaint>(L, 1)->setStyle(style);
502 return 0;
503}
504
505static int lpaint_getStrokeWidth(lua_State* L) {
506 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
507 return 1;
508}
509
510static int lpaint_setStrokeWidth(lua_State* L) {
511 get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
512 return 0;
513}
514
515static int lpaint_measureText(lua_State* L) {
516 if (lua_isstring(L, 2)) {
517 size_t len;
518 const char* text = lua_tolstring(L, 2, &len);
519 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
520 return 1;
521 }
522 return 0;
523}
524
525struct FontMetrics {
526 SkScalar fTop; //!< The greatest distance above the baseline for any glyph (will be <= 0)
527 SkScalar fAscent; //!< The recommended distance above the baseline (will be <= 0)
528 SkScalar fDescent; //!< The recommended distance below the baseline (will be >= 0)
529 SkScalar fBottom; //!< The greatest distance below the baseline for any glyph (will be >= 0)
530 SkScalar fLeading; //!< The recommended distance to add between lines of text (will be >= 0)
531 SkScalar fAvgCharWidth; //!< the average charactor width (>= 0)
532 SkScalar fXMin; //!< The minimum bounding box x value for all glyphs
533 SkScalar fXMax; //!< The maximum bounding box x value for all glyphs
534 SkScalar fXHeight; //!< the height of an 'x' in px, or 0 if no 'x' in face
535};
536
537static int lpaint_getFontMetrics(lua_State* L) {
538 SkPaint::FontMetrics fm;
539 SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000540
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000541 lua_newtable(L);
542 setfield_scalar(L, "top", fm.fTop);
543 setfield_scalar(L, "ascent", fm.fAscent);
544 setfield_scalar(L, "descent", fm.fDescent);
545 setfield_scalar(L, "bottom", fm.fBottom);
546 setfield_scalar(L, "leading", fm.fLeading);
547 SkLua(L).pushScalar(height);
548 return 2;
549}
550
reed@google.com74ce6f02013-05-22 15:13:18 +0000551static int lpaint_gc(lua_State* L) {
552 get_obj<SkPaint>(L, 1)->~SkPaint();
553 return 0;
554}
555
556static const struct luaL_Reg gSkPaint_Methods[] = {
557 { "isAntiAlias", lpaint_isAntiAlias },
558 { "setAntiAlias", lpaint_setAntiAlias },
559 { "getColor", lpaint_getColor },
560 { "setColor", lpaint_setColor },
reed@google.come3823fd2013-05-30 18:55:14 +0000561 { "getTextSize", lpaint_getTextSize },
562 { "setTextSize", lpaint_setTextSize },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000563 { "getTypeface", lpaint_getTypeface },
564 { "setTypeface", lpaint_setTypeface },
reed@google.come3823fd2013-05-30 18:55:14 +0000565 { "getFontID", lpaint_getFontID },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000566 { "getTextAlign", lpaint_getTextAlign },
567 { "setTextAlign", lpaint_setTextAlign },
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000568 { "getStroke", lpaint_getStroke },
569 { "setStroke", lpaint_setStroke },
570 { "getStrokeWidth", lpaint_getStrokeWidth },
571 { "setStrokeWidth", lpaint_setStrokeWidth },
572 { "measureText", lpaint_measureText },
573 { "getFontMetrics", lpaint_getFontMetrics },
reed@google.com74ce6f02013-05-22 15:13:18 +0000574 { "__gc", lpaint_gc },
575 { NULL, NULL }
576};
577
578///////////////////////////////////////////////////////////////////////////////
579
580static int lpath_getBounds(lua_State* L) {
581 SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
582 return 1;
583}
584
585static int lpath_isEmpty(lua_State* L) {
586 lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
587 return 1;
588}
589
590static int lpath_isRect(lua_State* L) {
591 SkRect r;
592 bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
593 int ret_count = 1;
594 lua_pushboolean(L, pred);
595 if (pred) {
596 SkLua(L).pushRect(r);
597 ret_count += 1;
598 }
599 return ret_count;
600}
601
602static const char* dir2string(SkPath::Direction dir) {
603 static const char* gStr[] = {
604 "unknown", "cw", "ccw"
605 };
606 SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
607 return gStr[dir];
608}
609
610static int lpath_isNestedRects(lua_State* L) {
611 SkRect rects[2];
612 SkPath::Direction dirs[2];
613 bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
614 int ret_count = 1;
615 lua_pushboolean(L, pred);
616 if (pred) {
617 SkLua lua(L);
618 lua.pushRect(rects[0]);
619 lua.pushRect(rects[1]);
620 lua_pushstring(L, dir2string(dirs[0]));
621 lua_pushstring(L, dir2string(dirs[0]));
622 ret_count += 4;
623 }
624 return ret_count;
625}
626
627static int lpath_reset(lua_State* L) {
628 get_obj<SkPath>(L, 1)->reset();
629 return 0;
630}
631
632static int lpath_moveTo(lua_State* L) {
633 get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
634 return 0;
635}
636
637static int lpath_lineTo(lua_State* L) {
638 get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
639 return 0;
640}
641
642static int lpath_quadTo(lua_State* L) {
643 get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
644 lua2scalar(L, 4), lua2scalar(L, 5));
645 return 0;
646}
647
648static int lpath_cubicTo(lua_State* L) {
649 get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
650 lua2scalar(L, 4), lua2scalar(L, 5),
651 lua2scalar(L, 6), lua2scalar(L, 7));
652 return 0;
653}
654
655static int lpath_close(lua_State* L) {
656 get_obj<SkPath>(L, 1)->close();
657 return 0;
658}
659
660static int lpath_gc(lua_State* L) {
661 get_obj<SkPath>(L, 1)->~SkPath();
662 return 0;
663}
664
665static const struct luaL_Reg gSkPath_Methods[] = {
666 { "getBounds", lpath_getBounds },
667 { "isEmpty", lpath_isEmpty },
668 { "isRect", lpath_isRect },
669 { "isNestedRects", lpath_isNestedRects },
670 { "reset", lpath_reset },
671 { "moveTo", lpath_moveTo },
672 { "lineTo", lpath_lineTo },
673 { "quadTo", lpath_quadTo },
674 { "cubicTo", lpath_cubicTo },
675 { "close", lpath_close },
676 { "__gc", lpath_gc },
677 { NULL, NULL }
678};
679
680///////////////////////////////////////////////////////////////////////////////
681
682static const char* rrect_type(const SkRRect& rr) {
683 switch (rr.getType()) {
684 case SkRRect::kUnknown_Type: return "unknown";
685 case SkRRect::kEmpty_Type: return "empty";
686 case SkRRect::kRect_Type: return "rect";
687 case SkRRect::kOval_Type: return "oval";
688 case SkRRect::kSimple_Type: return "simple";
689 case SkRRect::kComplex_Type: return "complex";
690 }
691 SkASSERT(!"never get here");
692 return "";
693}
694
695static int lrrect_rect(lua_State* L) {
696 SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
697 return 1;
698}
699
700static int lrrect_type(lua_State* L) {
701 lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
702 return 1;
703}
704
705static int lrrect_radii(lua_State* L) {
706 int corner = lua_tointeger(L, 2);
707 SkVector v;
708 if (corner < 0 || corner > 3) {
709 SkDebugf("bad corner index %d", corner);
710 v.set(0, 0);
711 } else {
712 v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
713 }
714 lua_pushnumber(L, v.fX);
715 lua_pushnumber(L, v.fY);
716 return 2;
717}
718
719static int lrrect_gc(lua_State* L) {
720 get_obj<SkRRect>(L, 1)->~SkRRect();
721 return 0;
722}
723
724static const struct luaL_Reg gSkRRect_Methods[] = {
725 { "rect", lrrect_rect },
726 { "type", lrrect_type },
727 { "radii", lrrect_radii },
728 { "__gc", lrrect_gc },
729 { NULL, NULL }
730};
731
732///////////////////////////////////////////////////////////////////////////////
733
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000734static int ltypeface_gc(lua_State* L) {
735 get_ref<SkTypeface>(L, 1)->unref();
736 return 0;
737}
738
739static const struct luaL_Reg gSkTypeface_Methods[] = {
740 { "__gc", ltypeface_gc },
741 { NULL, NULL }
742};
743
744///////////////////////////////////////////////////////////////////////////////
745
reed@google.com74ce6f02013-05-22 15:13:18 +0000746class AutoCallLua {
747public:
748 AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
749 lua_getglobal(L, func);
750 if (!lua_isfunction(L, -1)) {
751 int t = lua_type(L, -1);
752 SkDebugf("--- expected function %d\n", t);
753 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000754
reed@google.com74ce6f02013-05-22 15:13:18 +0000755 lua_newtable(L);
756 setfield_string(L, "verb", verb);
757 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000758
reed@google.com74ce6f02013-05-22 15:13:18 +0000759 ~AutoCallLua() {
760 if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
761 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
762 }
763 lua_settop(fL, -1);
764 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000765
reed@google.com74ce6f02013-05-22 15:13:18 +0000766private:
767 lua_State* fL;
768};
769
770#define AUTO_LUA(verb) AutoCallLua acl(fL, fFunc.c_str(), verb)
771
772///////////////////////////////////////////////////////////////////////////////
773
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000774static int lsk_newDocumentPDF(lua_State* L) {
775 const char* file = NULL;
776 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
777 file = lua_tolstring(L, 1, NULL);
778 }
779
780 SkDocument* doc = SkDocument::CreatePDF(file);
781 if (NULL == doc) {
782 // do I need to push a nil on the stack and return 1?
783 return 0;
784 } else {
785 push_ref(L, doc);
786 doc->unref();
787 return 1;
788 }
789}
790
reed@google.com3597b732013-05-22 20:12:50 +0000791static int lsk_newPaint(lua_State* L) {
792 push_new<SkPaint>(L);
793 return 1;
794}
795
796static int lsk_newPath(lua_State* L) {
797 push_new<SkPath>(L);
798 return 1;
799}
800
801static int lsk_newRRect(lua_State* L) {
802 SkRRect* rr = push_new<SkRRect>(L);
803 rr->setEmpty();
804 return 1;
805}
806
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000807static int lsk_newTypeface(lua_State* L) {
808 const char* name = NULL;
809 int style = SkTypeface::kNormal;
skia.committer@gmail.com63193672013-06-08 07:01:13 +0000810
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000811 int count = lua_gettop(L);
812 if (count > 0 && lua_isstring(L, 1)) {
813 name = lua_tolstring(L, 1, NULL);
814 if (count > 1 && lua_isnumber(L, 2)) {
815 style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
816 }
817 }
818
819 SkTypeface* face = SkTypeface::CreateFromName(name,
820 (SkTypeface::Style)style);
821// SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
822 if (NULL == face) {
823 face = SkTypeface::RefDefault();
824 }
825 push_ref(L, face);
826 face->unref();
827 return 1;
828}
reed@google.com3597b732013-05-22 20:12:50 +0000829
830static void register_Sk(lua_State* L) {
831 lua_newtable(L);
832 lua_pushvalue(L, -1);
833 lua_setglobal(L, "Sk");
834 // the Sk table is still on top
835
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000836 setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
reed@google.com3597b732013-05-22 20:12:50 +0000837 setfield_function(L, "newPaint", lsk_newPaint);
838 setfield_function(L, "newPath", lsk_newPath);
839 setfield_function(L, "newRRect", lsk_newRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000840 setfield_function(L, "newTypeface", lsk_newTypeface);
reed@google.com3597b732013-05-22 20:12:50 +0000841 lua_pop(L, 1); // pop off the Sk table
842}
843
reed@google.com74ce6f02013-05-22 15:13:18 +0000844#define REG_CLASS(L, C) \
845 do { \
reed@google.com3597b732013-05-22 20:12:50 +0000846 luaL_newmetatable(L, get_mtname<C>()); \
reed@google.com74ce6f02013-05-22 15:13:18 +0000847 lua_pushvalue(L, -1); \
848 lua_setfield(L, -2, "__index"); \
849 luaL_setfuncs(L, g##C##_Methods, 0); \
850 lua_pop(L, 1); /* pop off the meta-table */ \
851 } while (0)
852
853void SkLua::Load(lua_State* L) {
reed@google.com3597b732013-05-22 20:12:50 +0000854 register_Sk(L);
reed@google.com74ce6f02013-05-22 15:13:18 +0000855 REG_CLASS(L, SkCanvas);
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000856 REG_CLASS(L, SkDocument);
reed@google.com74ce6f02013-05-22 15:13:18 +0000857 REG_CLASS(L, SkPath);
858 REG_CLASS(L, SkPaint);
859 REG_CLASS(L, SkRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000860 REG_CLASS(L, SkTypeface);
reed@google.com74ce6f02013-05-22 15:13:18 +0000861}