blob: 6754746033380fff8477244d8549fce7ab7d0555 [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
231static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
232 SkASSERT(lua_istable(L, index));
233 lua_pushstring(L, key);
234 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000235
reed@google.com74ce6f02013-05-22 15:13:18 +0000236 SkScalar value = lua2scalar(L, -1);
237 lua_pop(L, 1);
238 return value;
239}
240
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000241static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
242 SkASSERT(lua_istable(L, index));
243 lua_pushstring(L, key);
244 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000245
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000246 SkScalar value;
247 if (lua_isnil(L, -1)) {
248 value = def;
249 } else {
250 value = lua2scalar(L, -1);
251 }
252 lua_pop(L, 1);
253 return value;
254}
255
reed@google.com74ce6f02013-05-22 15:13:18 +0000256static U8CPU unit2byte(SkScalar x) {
257 if (x <= 0) {
258 return 0;
259 } else if (x >= 1) {
260 return 255;
261 } else {
262 return SkScalarRoundToInt(x * 255);
263 }
264}
265
266static SkColor lua2color(lua_State* L, int index) {
267 return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
268 unit2byte(getfield_scalar(L, index, "r")),
269 unit2byte(getfield_scalar(L, index, "g")),
270 unit2byte(getfield_scalar(L, index, "b")));
271}
272
273static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000274 rect->set(getfield_scalar_default(L, index, "left", 0),
275 getfield_scalar_default(L, index, "top", 0),
reed@google.com74ce6f02013-05-22 15:13:18 +0000276 getfield_scalar(L, index, "right"),
277 getfield_scalar(L, index, "bottom"));
278 return rect;
279}
280
281static int lcanvas_drawColor(lua_State* L) {
282 get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
283 return 0;
284}
285
286static int lcanvas_drawRect(lua_State* L) {
287 SkRect rect;
288 get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
289 *get_obj<SkPaint>(L, 3));
290 return 0;
291}
292
293static int lcanvas_drawOval(lua_State* L) {
294 SkRect rect;
295 get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
296 *get_obj<SkPaint>(L, 3));
297 return 0;
298}
299
300static int lcanvas_drawCircle(lua_State* L) {
301 get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
302 lua2scalar(L, 3),
303 lua2scalar(L, 4),
304 *get_obj<SkPaint>(L, 5));
305 return 0;
306}
307
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000308static int lcanvas_drawImage(lua_State* L) {
309 SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
310 SkImage* image = get_ref<SkImage>(L, 2);
311 if (NULL == image) {
312 return 0;
313 }
314 SkScalar x = lua2scalar(L, 3);
315 SkScalar y = lua2scalar(L, 4);
316
317 SkPaint paint;
318 const SkPaint* paintPtr = NULL;
319 if (lua_isnumber(L, 5)) {
320 paint.setAlpha(SkScalarRoundToInt(lua2scalar(L, 5) * 255));
321 paintPtr = &paint;
322 }
323 image->draw(canvas, x, y, paintPtr);
324 return 0;
325}
326
reed@google.comfd345872013-05-22 20:53:42 +0000327static int lcanvas_drawPath(lua_State* L) {
328 get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
329 *get_obj<SkPaint>(L, 3));
330 return 0;
331}
332
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000333static int lcanvas_drawText(lua_State* L) {
334 if (lua_gettop(L) < 5) {
335 return 0;
336 }
337
338 if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
339 size_t len;
340 const char* text = lua_tolstring(L, 2, &len);
341 get_ref<SkCanvas>(L, 1)->drawText(text, len,
342 lua2scalar(L, 3), lua2scalar(L, 4),
343 *get_obj<SkPaint>(L, 5));
344 }
345 return 0;
346}
347
reed@google.com74ce6f02013-05-22 15:13:18 +0000348static int lcanvas_getSaveCount(lua_State* L) {
349 lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
350 return 1;
351}
352
353static int lcanvas_getTotalMatrix(lua_State* L) {
354 SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
355 return 1;
356}
357
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000358static int lcanvas_save(lua_State* L) {
359 lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
360 return 1;
361}
362
363static int lcanvas_restore(lua_State* L) {
364 get_ref<SkCanvas>(L, 1)->restore();
365 return 0;
366}
367
reed@google.com3597b732013-05-22 20:12:50 +0000368static int lcanvas_translate(lua_State* L) {
369 get_ref<SkCanvas>(L, 1)->translate(lua2scalar(L, 2), lua2scalar(L, 3));
370 return 0;
371}
372
reed@google.com74ce6f02013-05-22 15:13:18 +0000373static int lcanvas_gc(lua_State* L) {
374 get_ref<SkCanvas>(L, 1)->unref();
375 return 0;
376}
377
378static const struct luaL_Reg gSkCanvas_Methods[] = {
379 { "drawColor", lcanvas_drawColor },
380 { "drawRect", lcanvas_drawRect },
381 { "drawOval", lcanvas_drawOval },
382 { "drawCircle", lcanvas_drawCircle },
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000383 { "drawImage", lcanvas_drawImage },
reed@google.comfd345872013-05-22 20:53:42 +0000384 { "drawPath", lcanvas_drawPath },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000385 { "drawText", lcanvas_drawText },
reed@google.com74ce6f02013-05-22 15:13:18 +0000386 { "getSaveCount", lcanvas_getSaveCount },
387 { "getTotalMatrix", lcanvas_getTotalMatrix },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000388 { "save", lcanvas_save },
389 { "restore", lcanvas_restore },
reed@google.com3597b732013-05-22 20:12:50 +0000390 { "translate", lcanvas_translate },
reed@google.com74ce6f02013-05-22 15:13:18 +0000391 { "__gc", lcanvas_gc },
392 { NULL, NULL }
393};
394
395///////////////////////////////////////////////////////////////////////////////
396
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000397static int ldocument_beginPage(lua_State* L) {
398 const SkRect* contentPtr = NULL;
399 push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
400 lua2scalar(L, 3),
401 contentPtr));
402 return 1;
403}
404
405static int ldocument_endPage(lua_State* L) {
406 get_ref<SkDocument>(L, 1)->endPage();
407 return 0;
408}
409
410static int ldocument_close(lua_State* L) {
411 get_ref<SkDocument>(L, 1)->close();
412 return 0;
413}
414
415static int ldocument_gc(lua_State* L) {
416 get_ref<SkDocument>(L, 1)->unref();
417 return 0;
418}
419
420static const struct luaL_Reg gSkDocument_Methods[] = {
421 { "beginPage", ldocument_beginPage },
422 { "endPage", ldocument_endPage },
423 { "close", ldocument_close },
424 { "__gc", ldocument_gc },
425 { NULL, NULL }
426};
427
428///////////////////////////////////////////////////////////////////////////////
429
reed@google.com74ce6f02013-05-22 15:13:18 +0000430static int lpaint_isAntiAlias(lua_State* L) {
431 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
432 return 1;
433}
434
435static int lpaint_setAntiAlias(lua_State* L) {
reed@google.com88c9ec92013-05-22 15:43:21 +0000436 get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
reed@google.com74ce6f02013-05-22 15:13:18 +0000437 return 0;
438}
439
440static int lpaint_getColor(lua_State* L) {
441 SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
442 return 1;
443}
444
445static int lpaint_setColor(lua_State* L) {
446 get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
447 return 0;
448}
449
reed@google.come3823fd2013-05-30 18:55:14 +0000450static int lpaint_getTextSize(lua_State* L) {
451 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
452 return 1;
453}
454
455static int lpaint_setTextSize(lua_State* L) {
456 get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
457 return 0;
458}
459
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000460static int lpaint_getTypeface(lua_State* L) {
461 push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
462 return 1;
463}
464
465static int lpaint_setTypeface(lua_State* L) {
466 get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
467 return 0;
468}
469
reed@google.come3823fd2013-05-30 18:55:14 +0000470static int lpaint_getFontID(lua_State* L) {
471 SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
472 SkLua(L).pushU32(SkTypeface::UniqueID(face));
473 return 1;
474}
475
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000476static const struct {
477 const char* fLabel;
478 SkPaint::Align fAlign;
479} gAlignRec[] = {
480 { "left", SkPaint::kLeft_Align },
481 { "center", SkPaint::kCenter_Align },
482 { "right", SkPaint::kRight_Align },
483};
484
485static int lpaint_getTextAlign(lua_State* L) {
486 SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
487 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
488 if (gAlignRec[i].fAlign == align) {
489 lua_pushstring(L, gAlignRec[i].fLabel);
490 return 1;
491 }
492 }
493 return 0;
494}
495
496static int lpaint_setTextAlign(lua_State* L) {
497 if (lua_isstring(L, 2)) {
498 size_t len;
499 const char* label = lua_tolstring(L, 2, &len);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000500
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000501 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
502 if (!strcmp(gAlignRec[i].fLabel, label)) {
503 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
504 break;
505 }
506 }
507 }
508 return 0;
509}
510
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000511static int lpaint_getStroke(lua_State* L) {
512 lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
513 return 1;
514}
515
516static int lpaint_setStroke(lua_State* L) {
517 SkPaint::Style style;
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000518
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000519 if (lua_toboolean(L, 2)) {
520 style = SkPaint::kStroke_Style;
521 } else {
522 style = SkPaint::kFill_Style;
523 }
524 get_obj<SkPaint>(L, 1)->setStyle(style);
525 return 0;
526}
527
528static int lpaint_getStrokeWidth(lua_State* L) {
529 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
530 return 1;
531}
532
533static int lpaint_setStrokeWidth(lua_State* L) {
534 get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
535 return 0;
536}
537
538static int lpaint_measureText(lua_State* L) {
539 if (lua_isstring(L, 2)) {
540 size_t len;
541 const char* text = lua_tolstring(L, 2, &len);
542 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
543 return 1;
544 }
545 return 0;
546}
547
548struct FontMetrics {
549 SkScalar fTop; //!< The greatest distance above the baseline for any glyph (will be <= 0)
550 SkScalar fAscent; //!< The recommended distance above the baseline (will be <= 0)
551 SkScalar fDescent; //!< The recommended distance below the baseline (will be >= 0)
552 SkScalar fBottom; //!< The greatest distance below the baseline for any glyph (will be >= 0)
553 SkScalar fLeading; //!< The recommended distance to add between lines of text (will be >= 0)
554 SkScalar fAvgCharWidth; //!< the average charactor width (>= 0)
555 SkScalar fXMin; //!< The minimum bounding box x value for all glyphs
556 SkScalar fXMax; //!< The maximum bounding box x value for all glyphs
557 SkScalar fXHeight; //!< the height of an 'x' in px, or 0 if no 'x' in face
558};
559
560static int lpaint_getFontMetrics(lua_State* L) {
561 SkPaint::FontMetrics fm;
562 SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000563
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000564 lua_newtable(L);
565 setfield_scalar(L, "top", fm.fTop);
566 setfield_scalar(L, "ascent", fm.fAscent);
567 setfield_scalar(L, "descent", fm.fDescent);
568 setfield_scalar(L, "bottom", fm.fBottom);
569 setfield_scalar(L, "leading", fm.fLeading);
570 SkLua(L).pushScalar(height);
571 return 2;
572}
573
reed@google.com74ce6f02013-05-22 15:13:18 +0000574static int lpaint_gc(lua_State* L) {
575 get_obj<SkPaint>(L, 1)->~SkPaint();
576 return 0;
577}
578
579static const struct luaL_Reg gSkPaint_Methods[] = {
580 { "isAntiAlias", lpaint_isAntiAlias },
581 { "setAntiAlias", lpaint_setAntiAlias },
582 { "getColor", lpaint_getColor },
583 { "setColor", lpaint_setColor },
reed@google.come3823fd2013-05-30 18:55:14 +0000584 { "getTextSize", lpaint_getTextSize },
585 { "setTextSize", lpaint_setTextSize },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000586 { "getTypeface", lpaint_getTypeface },
587 { "setTypeface", lpaint_setTypeface },
reed@google.come3823fd2013-05-30 18:55:14 +0000588 { "getFontID", lpaint_getFontID },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000589 { "getTextAlign", lpaint_getTextAlign },
590 { "setTextAlign", lpaint_setTextAlign },
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000591 { "getStroke", lpaint_getStroke },
592 { "setStroke", lpaint_setStroke },
593 { "getStrokeWidth", lpaint_getStrokeWidth },
594 { "setStrokeWidth", lpaint_setStrokeWidth },
595 { "measureText", lpaint_measureText },
596 { "getFontMetrics", lpaint_getFontMetrics },
reed@google.com74ce6f02013-05-22 15:13:18 +0000597 { "__gc", lpaint_gc },
598 { NULL, NULL }
599};
600
601///////////////////////////////////////////////////////////////////////////////
602
603static int lpath_getBounds(lua_State* L) {
604 SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
605 return 1;
606}
607
608static int lpath_isEmpty(lua_State* L) {
609 lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
610 return 1;
611}
612
613static int lpath_isRect(lua_State* L) {
614 SkRect r;
615 bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
616 int ret_count = 1;
617 lua_pushboolean(L, pred);
618 if (pred) {
619 SkLua(L).pushRect(r);
620 ret_count += 1;
621 }
622 return ret_count;
623}
624
625static const char* dir2string(SkPath::Direction dir) {
626 static const char* gStr[] = {
627 "unknown", "cw", "ccw"
628 };
629 SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
630 return gStr[dir];
631}
632
633static int lpath_isNestedRects(lua_State* L) {
634 SkRect rects[2];
635 SkPath::Direction dirs[2];
636 bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
637 int ret_count = 1;
638 lua_pushboolean(L, pred);
639 if (pred) {
640 SkLua lua(L);
641 lua.pushRect(rects[0]);
642 lua.pushRect(rects[1]);
643 lua_pushstring(L, dir2string(dirs[0]));
644 lua_pushstring(L, dir2string(dirs[0]));
645 ret_count += 4;
646 }
647 return ret_count;
648}
649
650static int lpath_reset(lua_State* L) {
651 get_obj<SkPath>(L, 1)->reset();
652 return 0;
653}
654
655static int lpath_moveTo(lua_State* L) {
656 get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
657 return 0;
658}
659
660static int lpath_lineTo(lua_State* L) {
661 get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
662 return 0;
663}
664
665static int lpath_quadTo(lua_State* L) {
666 get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
667 lua2scalar(L, 4), lua2scalar(L, 5));
668 return 0;
669}
670
671static int lpath_cubicTo(lua_State* L) {
672 get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
673 lua2scalar(L, 4), lua2scalar(L, 5),
674 lua2scalar(L, 6), lua2scalar(L, 7));
675 return 0;
676}
677
678static int lpath_close(lua_State* L) {
679 get_obj<SkPath>(L, 1)->close();
680 return 0;
681}
682
683static int lpath_gc(lua_State* L) {
684 get_obj<SkPath>(L, 1)->~SkPath();
685 return 0;
686}
687
688static const struct luaL_Reg gSkPath_Methods[] = {
689 { "getBounds", lpath_getBounds },
690 { "isEmpty", lpath_isEmpty },
691 { "isRect", lpath_isRect },
692 { "isNestedRects", lpath_isNestedRects },
693 { "reset", lpath_reset },
694 { "moveTo", lpath_moveTo },
695 { "lineTo", lpath_lineTo },
696 { "quadTo", lpath_quadTo },
697 { "cubicTo", lpath_cubicTo },
698 { "close", lpath_close },
699 { "__gc", lpath_gc },
700 { NULL, NULL }
701};
702
703///////////////////////////////////////////////////////////////////////////////
704
705static const char* rrect_type(const SkRRect& rr) {
706 switch (rr.getType()) {
707 case SkRRect::kUnknown_Type: return "unknown";
708 case SkRRect::kEmpty_Type: return "empty";
709 case SkRRect::kRect_Type: return "rect";
710 case SkRRect::kOval_Type: return "oval";
711 case SkRRect::kSimple_Type: return "simple";
712 case SkRRect::kComplex_Type: return "complex";
713 }
714 SkASSERT(!"never get here");
715 return "";
716}
717
718static int lrrect_rect(lua_State* L) {
719 SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
720 return 1;
721}
722
723static int lrrect_type(lua_State* L) {
724 lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
725 return 1;
726}
727
728static int lrrect_radii(lua_State* L) {
729 int corner = lua_tointeger(L, 2);
730 SkVector v;
731 if (corner < 0 || corner > 3) {
732 SkDebugf("bad corner index %d", corner);
733 v.set(0, 0);
734 } else {
735 v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
736 }
737 lua_pushnumber(L, v.fX);
738 lua_pushnumber(L, v.fY);
739 return 2;
740}
741
742static int lrrect_gc(lua_State* L) {
743 get_obj<SkRRect>(L, 1)->~SkRRect();
744 return 0;
745}
746
747static const struct luaL_Reg gSkRRect_Methods[] = {
748 { "rect", lrrect_rect },
749 { "type", lrrect_type },
750 { "radii", lrrect_radii },
751 { "__gc", lrrect_gc },
752 { NULL, NULL }
753};
754
755///////////////////////////////////////////////////////////////////////////////
756
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000757static int limage_width(lua_State* L) {
758 lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
759 return 1;
760}
761
762static int limage_height(lua_State* L) {
763 lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
764 return 1;
765}
766
767static int limage_gc(lua_State* L) {
768 get_ref<SkImage>(L, 1)->unref();
769 return 0;
770}
771
772static const struct luaL_Reg gSkImage_Methods[] = {
773 { "width", limage_width },
774 { "height", limage_height },
775 { "__gc", limage_gc },
776 { NULL, NULL }
777};
778
779///////////////////////////////////////////////////////////////////////////////
780
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000781static int ltypeface_gc(lua_State* L) {
782 get_ref<SkTypeface>(L, 1)->unref();
783 return 0;
784}
785
786static const struct luaL_Reg gSkTypeface_Methods[] = {
787 { "__gc", ltypeface_gc },
788 { NULL, NULL }
789};
790
791///////////////////////////////////////////////////////////////////////////////
792
reed@google.com74ce6f02013-05-22 15:13:18 +0000793class AutoCallLua {
794public:
795 AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
796 lua_getglobal(L, func);
797 if (!lua_isfunction(L, -1)) {
798 int t = lua_type(L, -1);
799 SkDebugf("--- expected function %d\n", t);
800 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000801
reed@google.com74ce6f02013-05-22 15:13:18 +0000802 lua_newtable(L);
803 setfield_string(L, "verb", verb);
804 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000805
reed@google.com74ce6f02013-05-22 15:13:18 +0000806 ~AutoCallLua() {
807 if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
808 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
809 }
810 lua_settop(fL, -1);
811 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +0000812
reed@google.com74ce6f02013-05-22 15:13:18 +0000813private:
814 lua_State* fL;
815};
816
817#define AUTO_LUA(verb) AutoCallLua acl(fL, fFunc.c_str(), verb)
818
819///////////////////////////////////////////////////////////////////////////////
820
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000821static int lsk_newDocumentPDF(lua_State* L) {
822 const char* file = NULL;
823 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
824 file = lua_tolstring(L, 1, NULL);
825 }
826
827 SkDocument* doc = SkDocument::CreatePDF(file);
828 if (NULL == doc) {
829 // do I need to push a nil on the stack and return 1?
830 return 0;
831 } else {
832 push_ref(L, doc);
833 doc->unref();
834 return 1;
835 }
836}
837
reed@google.com3597b732013-05-22 20:12:50 +0000838static int lsk_newPaint(lua_State* L) {
839 push_new<SkPaint>(L);
840 return 1;
841}
842
843static int lsk_newPath(lua_State* L) {
844 push_new<SkPath>(L);
845 return 1;
846}
847
848static int lsk_newRRect(lua_State* L) {
849 SkRRect* rr = push_new<SkRRect>(L);
850 rr->setEmpty();
851 return 1;
852}
853
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000854static int lsk_newTypeface(lua_State* L) {
855 const char* name = NULL;
856 int style = SkTypeface::kNormal;
skia.committer@gmail.com63193672013-06-08 07:01:13 +0000857
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000858 int count = lua_gettop(L);
859 if (count > 0 && lua_isstring(L, 1)) {
860 name = lua_tolstring(L, 1, NULL);
861 if (count > 1 && lua_isnumber(L, 2)) {
862 style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
863 }
864 }
865
866 SkTypeface* face = SkTypeface::CreateFromName(name,
867 (SkTypeface::Style)style);
868// SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
869 if (NULL == face) {
870 face = SkTypeface::RefDefault();
871 }
872 push_ref(L, face);
873 face->unref();
874 return 1;
875}
reed@google.com3597b732013-05-22 20:12:50 +0000876
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000877static int lsk_loadImage(lua_State* L) {
878 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
879 const char* name = lua_tolstring(L, 1, NULL);
880 SkAutoDataUnref data(SkData::NewFromFileName(name));
881 if (data.get()) {
882 SkImage* image = SkImage::NewEncodedData(data.get());
883 if (image) {
884 push_ref(L, image);
885 image->unref();
886 return 1;
887 }
888 }
889 }
890 return 0;
891}
892
reed@google.com3597b732013-05-22 20:12:50 +0000893static void register_Sk(lua_State* L) {
894 lua_newtable(L);
895 lua_pushvalue(L, -1);
896 lua_setglobal(L, "Sk");
897 // the Sk table is still on top
898
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000899 setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000900 setfield_function(L, "loadImage", lsk_loadImage);
reed@google.com3597b732013-05-22 20:12:50 +0000901 setfield_function(L, "newPaint", lsk_newPaint);
902 setfield_function(L, "newPath", lsk_newPath);
903 setfield_function(L, "newRRect", lsk_newRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000904 setfield_function(L, "newTypeface", lsk_newTypeface);
reed@google.com3597b732013-05-22 20:12:50 +0000905 lua_pop(L, 1); // pop off the Sk table
906}
907
reed@google.com74ce6f02013-05-22 15:13:18 +0000908#define REG_CLASS(L, C) \
909 do { \
reed@google.com3597b732013-05-22 20:12:50 +0000910 luaL_newmetatable(L, get_mtname<C>()); \
reed@google.com74ce6f02013-05-22 15:13:18 +0000911 lua_pushvalue(L, -1); \
912 lua_setfield(L, -2, "__index"); \
913 luaL_setfuncs(L, g##C##_Methods, 0); \
914 lua_pop(L, 1); /* pop off the meta-table */ \
915 } while (0)
916
917void SkLua::Load(lua_State* L) {
reed@google.com3597b732013-05-22 20:12:50 +0000918 register_Sk(L);
reed@google.com74ce6f02013-05-22 15:13:18 +0000919 REG_CLASS(L, SkCanvas);
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000920 REG_CLASS(L, SkDocument);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000921 REG_CLASS(L, SkImage);
reed@google.com74ce6f02013-05-22 15:13:18 +0000922 REG_CLASS(L, SkPath);
923 REG_CLASS(L, SkPaint);
924 REG_CLASS(L, SkRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000925 REG_CLASS(L, SkTypeface);
reed@google.com74ce6f02013-05-22 15:13:18 +0000926}