blob: 9e9477596a1fd402c7e5469438ca3ff10bc5fa6f [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"
bsalomon@google.com4ebe3822014-02-26 20:22:32 +00009
10#if SK_SUPPORT_GPU
11#include "GrReducedClip.h"
12#endif
13
reed@google.com74ce6f02013-05-22 15:13:18 +000014#include "SkCanvas.h"
mike@reedtribe.org792bbd12013-06-11 02:20:28 +000015#include "SkData.h"
mike@reedtribe.orgfb858242013-06-08 16:39:44 +000016#include "SkDocument.h"
mike@reedtribe.org792bbd12013-06-11 02:20:28 +000017#include "SkImage.h"
18#include "SkMatrix.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000019#include "SkPaint.h"
20#include "SkPath.h"
reed@google.com5fdc9832013-07-24 15:47:52 +000021#include "SkPixelRef.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000022#include "SkRRect.h"
23#include "SkString.h"
reed@google.come3823fd2013-05-30 18:55:14 +000024#include "SkTypeface.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000025
26extern "C" {
reed@google.com3597b732013-05-22 20:12:50 +000027 #include "lua.h"
28 #include "lualib.h"
29 #include "lauxlib.h"
reed@google.com74ce6f02013-05-22 15:13:18 +000030}
31
reed@google.comfd345872013-05-22 20:53:42 +000032// return the metatable name for a given class
reed@google.com3597b732013-05-22 20:12:50 +000033template <typename T> const char* get_mtname();
reed@google.comfd345872013-05-22 20:53:42 +000034#define DEF_MTNAME(T) \
35 template <> const char* get_mtname<T>() { \
36 return #T "_LuaMetaTableName"; \
37 }
38
39DEF_MTNAME(SkCanvas)
mike@reedtribe.orgfb858242013-06-08 16:39:44 +000040DEF_MTNAME(SkDocument)
mike@reedtribe.org792bbd12013-06-11 02:20:28 +000041DEF_MTNAME(SkImage)
reed@google.comfd345872013-05-22 20:53:42 +000042DEF_MTNAME(SkMatrix)
43DEF_MTNAME(SkRRect)
44DEF_MTNAME(SkPath)
45DEF_MTNAME(SkPaint)
commit-bot@chromium.org1301bf32014-03-17 23:09:47 +000046DEF_MTNAME(SkPathEffect)
reed@google.com5fdc9832013-07-24 15:47:52 +000047DEF_MTNAME(SkShader)
mike@reedtribe.orge6469f12013-06-08 03:15:47 +000048DEF_MTNAME(SkTypeface)
reed@google.com74ce6f02013-05-22 15:13:18 +000049
reed@google.com3597b732013-05-22 20:12:50 +000050template <typename T> T* push_new(lua_State* L) {
51 T* addr = (T*)lua_newuserdata(L, sizeof(T));
52 new (addr) T;
53 luaL_getmetatable(L, get_mtname<T>());
54 lua_setmetatable(L, -2);
55 return addr;
56}
reed@google.com74ce6f02013-05-22 15:13:18 +000057
58template <typename T> void push_obj(lua_State* L, const T& obj) {
59 new (lua_newuserdata(L, sizeof(T))) T(obj);
reed@google.com3597b732013-05-22 20:12:50 +000060 luaL_getmetatable(L, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000061 lua_setmetatable(L, -2);
62}
63
64template <typename T> void push_ref(lua_State* L, T* ref) {
commit-bot@chromium.org77887af2013-12-17 14:28:19 +000065 *(T**)lua_newuserdata(L, sizeof(T*)) = SkSafeRef(ref);
reed@google.com3597b732013-05-22 20:12:50 +000066 luaL_getmetatable(L, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000067 lua_setmetatable(L, -2);
68}
69
70template <typename T> T* get_ref(lua_State* L, int index) {
reed@google.com3597b732013-05-22 20:12:50 +000071 return *(T**)luaL_checkudata(L, index, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000072}
73
74template <typename T> T* get_obj(lua_State* L, int index) {
reed@google.com3597b732013-05-22 20:12:50 +000075 return (T*)luaL_checkudata(L, index, get_mtname<T>());
reed@google.com74ce6f02013-05-22 15:13:18 +000076}
77
reed@google.com88c9ec92013-05-22 15:43:21 +000078static bool lua2bool(lua_State* L, int index) {
79 return !!lua_toboolean(L, index);
80}
81
reed@google.com74ce6f02013-05-22 15:13:18 +000082///////////////////////////////////////////////////////////////////////////////
83
reed@google.com3597b732013-05-22 20:12:50 +000084SkLua::SkLua(const char termCode[]) : fTermCode(termCode), fWeOwnL(true) {
85 fL = luaL_newstate();
86 luaL_openlibs(fL);
87 SkLua::Load(fL);
88}
89
90SkLua::SkLua(lua_State* L) : fL(L), fWeOwnL(false) {}
91
92SkLua::~SkLua() {
93 if (fWeOwnL) {
94 if (fTermCode.size() > 0) {
95 lua_getglobal(fL, fTermCode.c_str());
96 if (lua_pcall(fL, 0, 0, 0) != LUA_OK) {
97 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
98 }
99 }
100 lua_close(fL);
101 }
102}
103
104bool SkLua::runCode(const char code[]) {
105 int err = luaL_loadstring(fL, code) || lua_pcall(fL, 0, 0, 0);
106 if (err) {
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000107 SkDebugf("--- lua failed: %s\n", lua_tostring(fL, -1));
reed@google.com3597b732013-05-22 20:12:50 +0000108 return false;
109 }
110 return true;
111}
112
113bool SkLua::runCode(const void* code, size_t size) {
114 SkString str((const char*)code, size);
115 return this->runCode(str.c_str());
116}
117
118///////////////////////////////////////////////////////////////////////////////
119
120#define CHECK_SETFIELD(key) do if (key) lua_setfield(fL, -2, key); while (0)
121
reed@google.com29563872013-07-10 21:23:49 +0000122static void setfield_bool_if(lua_State* L, const char key[], bool pred) {
123 if (pred) {
124 lua_pushboolean(L, true);
125 lua_setfield(L, -2, key);
126 }
127}
128
reed@google.com74ce6f02013-05-22 15:13:18 +0000129static void setfield_string(lua_State* L, const char key[], const char value[]) {
130 lua_pushstring(L, value);
131 lua_setfield(L, -2, key);
132}
133
134static void setfield_number(lua_State* L, const char key[], double value) {
135 lua_pushnumber(L, value);
136 lua_setfield(L, -2, key);
137}
138
humper@google.com2815c192013-07-10 22:42:30 +0000139static void setfield_boolean(lua_State* L, const char key[], bool value) {
140 lua_pushboolean(L, value);
141 lua_setfield(L, -2, key);
142}
143
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000144static void setfield_scalar(lua_State* L, const char key[], SkScalar value) {
145 setfield_number(L, key, SkScalarToLua(value));
146}
147
reed@google.com3597b732013-05-22 20:12:50 +0000148static void setfield_function(lua_State* L,
149 const char key[], lua_CFunction value) {
150 lua_pushcfunction(L, value);
151 lua_setfield(L, -2, key);
reed@google.com74ce6f02013-05-22 15:13:18 +0000152}
153
reed@google.come3823fd2013-05-30 18:55:14 +0000154static void setarray_number(lua_State* L, int index, double value) {
155 lua_pushnumber(L, value);
156 lua_rawseti(L, -2, index);
157}
158
commit-bot@chromium.org4d803a92014-05-14 16:03:14 +0000159static void setarray_scalar(lua_State* L, int index, SkScalar value) {
160 setarray_number(L, index, SkScalarToLua(value));
161}
162
reed@google.com74ce6f02013-05-22 15:13:18 +0000163void SkLua::pushBool(bool value, const char key[]) {
164 lua_pushboolean(fL, value);
165 CHECK_SETFIELD(key);
166}
167
168void SkLua::pushString(const char str[], const char key[]) {
169 lua_pushstring(fL, str);
170 CHECK_SETFIELD(key);
171}
172
reed@google.come3823fd2013-05-30 18:55:14 +0000173void SkLua::pushString(const char str[], size_t length, const char key[]) {
174 // TODO: how to do this w/o making a copy?
175 SkString s(str, length);
176 lua_pushstring(fL, s.c_str());
177 CHECK_SETFIELD(key);
178}
179
reed@google.com74ce6f02013-05-22 15:13:18 +0000180void SkLua::pushString(const SkString& str, const char key[]) {
181 lua_pushstring(fL, str.c_str());
182 CHECK_SETFIELD(key);
183}
184
185void SkLua::pushColor(SkColor color, const char key[]) {
186 lua_newtable(fL);
187 setfield_number(fL, "a", SkColorGetA(color) / 255.0);
188 setfield_number(fL, "r", SkColorGetR(color) / 255.0);
189 setfield_number(fL, "g", SkColorGetG(color) / 255.0);
190 setfield_number(fL, "b", SkColorGetB(color) / 255.0);
191 CHECK_SETFIELD(key);
192}
193
reed@google.come3823fd2013-05-30 18:55:14 +0000194void SkLua::pushU32(uint32_t value, const char key[]) {
195 lua_pushnumber(fL, (double)value);
196 CHECK_SETFIELD(key);
197}
198
reed@google.com74ce6f02013-05-22 15:13:18 +0000199void SkLua::pushScalar(SkScalar value, const char key[]) {
200 lua_pushnumber(fL, SkScalarToLua(value));
201 CHECK_SETFIELD(key);
202}
203
reed@google.come3823fd2013-05-30 18:55:14 +0000204void SkLua::pushArrayU16(const uint16_t array[], int count, const char key[]) {
205 lua_newtable(fL);
206 for (int i = 0; i < count; ++i) {
207 // make it base-1 to match lua convention
208 setarray_number(fL, i + 1, (double)array[i]);
209 }
210 CHECK_SETFIELD(key);
211}
212
commit-bot@chromium.org1301bf32014-03-17 23:09:47 +0000213void SkLua::pushArrayPoint(const SkPoint array[], int count, const char key[]) {
214 lua_newtable(fL);
215 for (int i = 0; i < count; ++i) {
216 // make it base-1 to match lua convention
217 lua_newtable(fL);
218 this->pushScalar(array[i].fX, "x");
219 this->pushScalar(array[i].fY, "y");
220 lua_rawseti(fL, -2, i + 1);
221 }
222 CHECK_SETFIELD(key);
223}
224
commit-bot@chromium.org4d803a92014-05-14 16:03:14 +0000225void SkLua::pushArrayScalar(const SkScalar array[], int count, const char key[]) {
226 lua_newtable(fL);
227 for (int i = 0; i < count; ++i) {
228 // make it base-1 to match lua convention
229 setarray_scalar(fL, i + 1, array[i]);
230 }
231 CHECK_SETFIELD(key);
232}
233
reed@google.com74ce6f02013-05-22 15:13:18 +0000234void SkLua::pushRect(const SkRect& r, const char key[]) {
235 lua_newtable(fL);
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000236 setfield_scalar(fL, "left", r.fLeft);
237 setfield_scalar(fL, "top", r.fTop);
238 setfield_scalar(fL, "right", r.fRight);
239 setfield_scalar(fL, "bottom", r.fBottom);
reed@google.com74ce6f02013-05-22 15:13:18 +0000240 CHECK_SETFIELD(key);
241}
242
243void SkLua::pushRRect(const SkRRect& rr, const char key[]) {
244 push_obj(fL, rr);
245 CHECK_SETFIELD(key);
246}
247
commit-bot@chromium.org4d803a92014-05-14 16:03:14 +0000248void SkLua::pushDash(const SkPathEffect::DashInfo& info, const char key[]) {
249 lua_newtable(fL);
250 setfield_scalar(fL, "phase", info.fPhase);
251 this->pushArrayScalar(info.fIntervals, info.fCount, "intervals");
252 CHECK_SETFIELD(key);
253}
254
255
reed@google.com74ce6f02013-05-22 15:13:18 +0000256void SkLua::pushMatrix(const SkMatrix& matrix, const char key[]) {
257 push_obj(fL, matrix);
258 CHECK_SETFIELD(key);
259}
260
261void SkLua::pushPaint(const SkPaint& paint, const char key[]) {
262 push_obj(fL, paint);
263 CHECK_SETFIELD(key);
264}
265
266void SkLua::pushPath(const SkPath& path, const char key[]) {
267 push_obj(fL, path);
268 CHECK_SETFIELD(key);
269}
270
271void SkLua::pushCanvas(SkCanvas* canvas, const char key[]) {
272 push_ref(fL, canvas);
273 CHECK_SETFIELD(key);
274}
275
commit-bot@chromium.org5cc25352014-02-24 18:59:48 +0000276static const char* element_type(SkClipStack::Element::Type type) {
277 switch (type) {
278 case SkClipStack::Element::kEmpty_Type:
279 return "empty";
280 case SkClipStack::Element::kRect_Type:
281 return "rect";
282 case SkClipStack::Element::kRRect_Type:
283 return "rrect";
284 case SkClipStack::Element::kPath_Type:
285 return "path";
286 }
287 return "unknown";
288}
289
290static const char* region_op(SkRegion::Op op) {
291 switch (op) {
292 case SkRegion::kDifference_Op:
293 return "difference";
294 case SkRegion::kIntersect_Op:
295 return "intersect";
296 case SkRegion::kUnion_Op:
297 return "union";
298 case SkRegion::kXOR_Op:
299 return "xor";
300 case SkRegion::kReverseDifference_Op:
301 return "reverse-difference";
302 case SkRegion::kReplace_Op:
303 return "replace";
304 }
305 return "unknown";
306}
307
308void SkLua::pushClipStack(const SkClipStack& stack, const char* key) {
309 lua_newtable(fL);
310 SkClipStack::B2TIter iter(stack);
311 const SkClipStack::Element* element;
312 int i = 0;
313 while (NULL != (element = iter.next())) {
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000314 this->pushClipStackElement(*element);
commit-bot@chromium.org5cc25352014-02-24 18:59:48 +0000315 lua_rawseti(fL, -2, ++i);
316 }
317 CHECK_SETFIELD(key);
318}
319
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000320void SkLua::pushClipStackElement(const SkClipStack::Element& element, const char* key) {
321 lua_newtable(fL);
322 SkClipStack::Element::Type type = element.getType();
323 this->pushString(element_type(type), "type");
324 switch (type) {
325 case SkClipStack::Element::kEmpty_Type:
326 break;
327 case SkClipStack::Element::kRect_Type:
328 this->pushRect(element.getRect(), "rect");
329 break;
330 case SkClipStack::Element::kRRect_Type:
331 this->pushRRect(element.getRRect(), "rrect");
332 break;
333 case SkClipStack::Element::kPath_Type:
334 this->pushPath(element.getPath(), "path");
335 break;
336 }
337 this->pushString(region_op(element.getOp()), "op");
338 this->pushBool(element.isAA(), "aa");
339 CHECK_SETFIELD(key);
340}
341
342
reed@google.com74ce6f02013-05-22 15:13:18 +0000343///////////////////////////////////////////////////////////////////////////////
344///////////////////////////////////////////////////////////////////////////////
345
346static SkScalar lua2scalar(lua_State* L, int index) {
347 SkASSERT(lua_isnumber(L, index));
348 return SkLuaToScalar(lua_tonumber(L, index));
349}
350
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000351static SkScalar lua2scalar_def(lua_State* L, int index, SkScalar defaultValue) {
352 if (lua_isnumber(L, index)) {
353 return SkLuaToScalar(lua_tonumber(L, index));
354 } else {
355 return defaultValue;
356 }
357}
358
reed@google.com74ce6f02013-05-22 15:13:18 +0000359static SkScalar getfield_scalar(lua_State* L, int index, const char key[]) {
360 SkASSERT(lua_istable(L, index));
361 lua_pushstring(L, key);
362 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000363
reed@google.com74ce6f02013-05-22 15:13:18 +0000364 SkScalar value = lua2scalar(L, -1);
365 lua_pop(L, 1);
366 return value;
367}
368
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000369static SkScalar getfield_scalar_default(lua_State* L, int index, const char key[], SkScalar def) {
370 SkASSERT(lua_istable(L, index));
371 lua_pushstring(L, key);
372 lua_gettable(L, index);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000373
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000374 SkScalar value;
375 if (lua_isnil(L, -1)) {
376 value = def;
377 } else {
378 value = lua2scalar(L, -1);
379 }
380 lua_pop(L, 1);
381 return value;
382}
383
reed@google.com74ce6f02013-05-22 15:13:18 +0000384static U8CPU unit2byte(SkScalar x) {
385 if (x <= 0) {
386 return 0;
387 } else if (x >= 1) {
388 return 255;
389 } else {
390 return SkScalarRoundToInt(x * 255);
391 }
392}
393
394static SkColor lua2color(lua_State* L, int index) {
395 return SkColorSetARGB(unit2byte(getfield_scalar(L, index, "a")),
396 unit2byte(getfield_scalar(L, index, "r")),
397 unit2byte(getfield_scalar(L, index, "g")),
398 unit2byte(getfield_scalar(L, index, "b")));
399}
400
401static SkRect* lua2rect(lua_State* L, int index, SkRect* rect) {
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000402 rect->set(getfield_scalar_default(L, index, "left", 0),
403 getfield_scalar_default(L, index, "top", 0),
reed@google.com74ce6f02013-05-22 15:13:18 +0000404 getfield_scalar(L, index, "right"),
405 getfield_scalar(L, index, "bottom"));
406 return rect;
407}
408
409static int lcanvas_drawColor(lua_State* L) {
410 get_ref<SkCanvas>(L, 1)->drawColor(lua2color(L, 2));
411 return 0;
412}
413
414static int lcanvas_drawRect(lua_State* L) {
415 SkRect rect;
416 get_ref<SkCanvas>(L, 1)->drawRect(*lua2rect(L, 2, &rect),
417 *get_obj<SkPaint>(L, 3));
418 return 0;
419}
420
421static int lcanvas_drawOval(lua_State* L) {
422 SkRect rect;
423 get_ref<SkCanvas>(L, 1)->drawOval(*lua2rect(L, 2, &rect),
424 *get_obj<SkPaint>(L, 3));
425 return 0;
426}
427
428static int lcanvas_drawCircle(lua_State* L) {
429 get_ref<SkCanvas>(L, 1)->drawCircle(lua2scalar(L, 2),
430 lua2scalar(L, 3),
431 lua2scalar(L, 4),
432 *get_obj<SkPaint>(L, 5));
433 return 0;
434}
435
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000436static int lcanvas_drawImage(lua_State* L) {
437 SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
438 SkImage* image = get_ref<SkImage>(L, 2);
439 if (NULL == image) {
440 return 0;
441 }
442 SkScalar x = lua2scalar(L, 3);
443 SkScalar y = lua2scalar(L, 4);
444
445 SkPaint paint;
446 const SkPaint* paintPtr = NULL;
447 if (lua_isnumber(L, 5)) {
448 paint.setAlpha(SkScalarRoundToInt(lua2scalar(L, 5) * 255));
449 paintPtr = &paint;
450 }
451 image->draw(canvas, x, y, paintPtr);
452 return 0;
453}
454
reed@google.comfd345872013-05-22 20:53:42 +0000455static int lcanvas_drawPath(lua_State* L) {
456 get_ref<SkCanvas>(L, 1)->drawPath(*get_obj<SkPath>(L, 2),
457 *get_obj<SkPaint>(L, 3));
458 return 0;
459}
460
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000461static int lcanvas_drawText(lua_State* L) {
462 if (lua_gettop(L) < 5) {
463 return 0;
464 }
465
466 if (lua_isstring(L, 2) && lua_isnumber(L, 3) && lua_isnumber(L, 4)) {
467 size_t len;
468 const char* text = lua_tolstring(L, 2, &len);
469 get_ref<SkCanvas>(L, 1)->drawText(text, len,
470 lua2scalar(L, 3), lua2scalar(L, 4),
471 *get_obj<SkPaint>(L, 5));
472 }
473 return 0;
474}
475
reed@google.com74ce6f02013-05-22 15:13:18 +0000476static int lcanvas_getSaveCount(lua_State* L) {
477 lua_pushnumber(L, get_ref<SkCanvas>(L, 1)->getSaveCount());
478 return 1;
479}
480
481static int lcanvas_getTotalMatrix(lua_State* L) {
482 SkLua(L).pushMatrix(get_ref<SkCanvas>(L, 1)->getTotalMatrix());
483 return 1;
484}
485
commit-bot@chromium.org5cc25352014-02-24 18:59:48 +0000486static int lcanvas_getClipStack(lua_State* L) {
487 SkLua(L).pushClipStack(*get_ref<SkCanvas>(L, 1)->getClipStack());
488 return 1;
489}
490
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000491int SkLua::lcanvas_getReducedClipStack(lua_State* L) {
492#if SK_SUPPORT_GPU
493 const SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
494 SkISize layerSize = canvas->getTopLayerSize();
495 SkIPoint layerOrigin = canvas->getTopLayerOrigin();
496 SkIRect queryBounds = SkIRect::MakeXYWH(layerOrigin.fX, layerOrigin.fY,
497 layerSize.fWidth, layerSize.fHeight);
498
499 GrReducedClip::ElementList elements;
500 GrReducedClip::InitialState initialState;
501 int32_t genID;
502 SkIRect resultBounds;
503
504 const SkClipStack& stack = *canvas->getClipStack();
505
506 GrReducedClip::ReduceClipStack(stack,
507 queryBounds,
508 &elements,
509 &genID,
510 &initialState,
511 &resultBounds,
512 NULL);
513
514 GrReducedClip::ElementList::Iter iter(elements);
515 int i = 0;
516 lua_newtable(L);
517 while(NULL != iter.get()) {
518 SkLua(L).pushClipStackElement(*iter.get());
519 iter.next();
520 lua_rawseti(L, -2, ++i);
521 }
522 // Currently this only returns the element list to lua, not the initial state or result bounds.
523 // It could return these as additional items on the lua stack.
524 return 1;
525#else
526 return 0;
527#endif
528}
529
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000530static int lcanvas_save(lua_State* L) {
531 lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
532 return 1;
533}
534
535static int lcanvas_restore(lua_State* L) {
536 get_ref<SkCanvas>(L, 1)->restore();
537 return 0;
538}
539
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000540static int lcanvas_scale(lua_State* L) {
541 SkScalar sx = lua2scalar_def(L, 2, 1);
542 SkScalar sy = lua2scalar_def(L, 3, sx);
543 get_ref<SkCanvas>(L, 1)->scale(sx, sy);
544 return 0;
545}
546
reed@google.com3597b732013-05-22 20:12:50 +0000547static int lcanvas_translate(lua_State* L) {
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000548 SkScalar tx = lua2scalar_def(L, 2, 0);
549 SkScalar ty = lua2scalar_def(L, 3, 0);
550 get_ref<SkCanvas>(L, 1)->translate(tx, ty);
551 return 0;
552}
553
554static int lcanvas_rotate(lua_State* L) {
555 SkScalar degrees = lua2scalar_def(L, 2, 0);
556 get_ref<SkCanvas>(L, 1)->rotate(degrees);
reed@google.com3597b732013-05-22 20:12:50 +0000557 return 0;
558}
559
reed@google.com74ce6f02013-05-22 15:13:18 +0000560static int lcanvas_gc(lua_State* L) {
561 get_ref<SkCanvas>(L, 1)->unref();
562 return 0;
563}
564
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000565const struct luaL_Reg gSkCanvas_Methods[] = {
reed@google.com74ce6f02013-05-22 15:13:18 +0000566 { "drawColor", lcanvas_drawColor },
567 { "drawRect", lcanvas_drawRect },
568 { "drawOval", lcanvas_drawOval },
569 { "drawCircle", lcanvas_drawCircle },
mike@reedtribe.org792bbd12013-06-11 02:20:28 +0000570 { "drawImage", lcanvas_drawImage },
reed@google.comfd345872013-05-22 20:53:42 +0000571 { "drawPath", lcanvas_drawPath },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000572 { "drawText", lcanvas_drawText },
reed@google.com74ce6f02013-05-22 15:13:18 +0000573 { "getSaveCount", lcanvas_getSaveCount },
574 { "getTotalMatrix", lcanvas_getTotalMatrix },
commit-bot@chromium.org5cc25352014-02-24 18:59:48 +0000575 { "getClipStack", lcanvas_getClipStack },
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000576#if SK_SUPPORT_GPU
577 { "getReducedClipStack", SkLua::lcanvas_getReducedClipStack },
578#endif
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000579 { "save", lcanvas_save },
580 { "restore", lcanvas_restore },
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000581 { "scale", lcanvas_scale },
reed@google.com3597b732013-05-22 20:12:50 +0000582 { "translate", lcanvas_translate },
mike@reedtribe.org1d32cc62013-06-13 01:28:56 +0000583 { "rotate", lcanvas_rotate },
reed@google.com74ce6f02013-05-22 15:13:18 +0000584 { "__gc", lcanvas_gc },
585 { NULL, NULL }
586};
587
588///////////////////////////////////////////////////////////////////////////////
589
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000590static int ldocument_beginPage(lua_State* L) {
591 const SkRect* contentPtr = NULL;
592 push_ref(L, get_ref<SkDocument>(L, 1)->beginPage(lua2scalar(L, 2),
593 lua2scalar(L, 3),
594 contentPtr));
595 return 1;
596}
597
598static int ldocument_endPage(lua_State* L) {
599 get_ref<SkDocument>(L, 1)->endPage();
600 return 0;
601}
602
603static int ldocument_close(lua_State* L) {
604 get_ref<SkDocument>(L, 1)->close();
605 return 0;
606}
607
608static int ldocument_gc(lua_State* L) {
609 get_ref<SkDocument>(L, 1)->unref();
610 return 0;
611}
612
613static const struct luaL_Reg gSkDocument_Methods[] = {
614 { "beginPage", ldocument_beginPage },
615 { "endPage", ldocument_endPage },
616 { "close", ldocument_close },
617 { "__gc", ldocument_gc },
618 { NULL, NULL }
619};
620
621///////////////////////////////////////////////////////////////////////////////
622
reed@google.com74ce6f02013-05-22 15:13:18 +0000623static int lpaint_isAntiAlias(lua_State* L) {
624 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAntiAlias());
625 return 1;
626}
627
628static int lpaint_setAntiAlias(lua_State* L) {
reed@google.com88c9ec92013-05-22 15:43:21 +0000629 get_obj<SkPaint>(L, 1)->setAntiAlias(lua2bool(L, 2));
reed@google.com74ce6f02013-05-22 15:13:18 +0000630 return 0;
631}
632
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000633static int lpaint_isDither(lua_State* L) {
634 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDither());
635 return 1;
636}
637
638static int lpaint_isUnderlineText(lua_State* L) {
639 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isUnderlineText());
640 return 1;
641}
642
643static int lpaint_isStrikeThruText(lua_State* L) {
644 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isStrikeThruText());
645 return 1;
646}
647
648static int lpaint_isFakeBoldText(lua_State* L) {
649 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isFakeBoldText());
650 return 1;
651}
652
653static int lpaint_isLinearText(lua_State* L) {
654 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLinearText());
655 return 1;
656}
657
658static int lpaint_isSubpixelText(lua_State* L) {
659 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isSubpixelText());
660 return 1;
661}
662
663static int lpaint_isDevKernText(lua_State* L) {
664 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isDevKernText());
665 return 1;
666}
667
668static int lpaint_isLCDRenderText(lua_State* L) {
669 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isLCDRenderText());
670 return 1;
671}
672
673static int lpaint_isEmbeddedBitmapText(lua_State* L) {
674 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isEmbeddedBitmapText());
675 return 1;
676}
677
678static int lpaint_isAutohinted(lua_State* L) {
679 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isAutohinted());
680 return 1;
681}
682
683static int lpaint_isVerticalText(lua_State* L) {
684 lua_pushboolean(L, get_obj<SkPaint>(L, 1)->isVerticalText());
685 return 1;
686}
687
reed@google.com74ce6f02013-05-22 15:13:18 +0000688static int lpaint_getColor(lua_State* L) {
689 SkLua(L).pushColor(get_obj<SkPaint>(L, 1)->getColor());
690 return 1;
691}
692
693static int lpaint_setColor(lua_State* L) {
694 get_obj<SkPaint>(L, 1)->setColor(lua2color(L, 2));
695 return 0;
696}
697
reed@google.come3823fd2013-05-30 18:55:14 +0000698static int lpaint_getTextSize(lua_State* L) {
699 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSize());
700 return 1;
701}
702
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000703static int lpaint_getTextScaleX(lua_State* L) {
704 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextScaleX());
705 return 1;
706}
707
708static int lpaint_getTextSkewX(lua_State* L) {
709 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getTextSkewX());
710 return 1;
711}
712
reed@google.come3823fd2013-05-30 18:55:14 +0000713static int lpaint_setTextSize(lua_State* L) {
714 get_obj<SkPaint>(L, 1)->setTextSize(lua2scalar(L, 2));
715 return 0;
716}
717
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000718static int lpaint_getTypeface(lua_State* L) {
719 push_ref(L, get_obj<SkPaint>(L, 1)->getTypeface());
720 return 1;
721}
722
723static int lpaint_setTypeface(lua_State* L) {
724 get_obj<SkPaint>(L, 1)->setTypeface(get_ref<SkTypeface>(L, 2));
725 return 0;
726}
727
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000728static int lpaint_getHinting(lua_State* L) {
729 SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getHinting());
730 return 1;
731}
732
reed@google.come3823fd2013-05-30 18:55:14 +0000733static int lpaint_getFontID(lua_State* L) {
734 SkTypeface* face = get_obj<SkPaint>(L, 1)->getTypeface();
735 SkLua(L).pushU32(SkTypeface::UniqueID(face));
736 return 1;
737}
738
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000739static const struct {
740 const char* fLabel;
741 SkPaint::Align fAlign;
742} gAlignRec[] = {
743 { "left", SkPaint::kLeft_Align },
744 { "center", SkPaint::kCenter_Align },
745 { "right", SkPaint::kRight_Align },
746};
747
748static int lpaint_getTextAlign(lua_State* L) {
749 SkPaint::Align align = get_obj<SkPaint>(L, 1)->getTextAlign();
750 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
751 if (gAlignRec[i].fAlign == align) {
752 lua_pushstring(L, gAlignRec[i].fLabel);
753 return 1;
754 }
755 }
756 return 0;
757}
758
759static int lpaint_setTextAlign(lua_State* L) {
760 if (lua_isstring(L, 2)) {
761 size_t len;
762 const char* label = lua_tolstring(L, 2, &len);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000763
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000764 for (size_t i = 0; i < SK_ARRAY_COUNT(gAlignRec); ++i) {
765 if (!strcmp(gAlignRec[i].fLabel, label)) {
766 get_obj<SkPaint>(L, 1)->setTextAlign(gAlignRec[i].fAlign);
767 break;
768 }
769 }
770 }
771 return 0;
772}
773
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000774static int lpaint_getStroke(lua_State* L) {
775 lua_pushboolean(L, SkPaint::kStroke_Style == get_obj<SkPaint>(L, 1)->getStyle());
776 return 1;
777}
778
779static int lpaint_setStroke(lua_State* L) {
780 SkPaint::Style style;
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000781
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000782 if (lua_toboolean(L, 2)) {
783 style = SkPaint::kStroke_Style;
784 } else {
785 style = SkPaint::kFill_Style;
786 }
787 get_obj<SkPaint>(L, 1)->setStyle(style);
788 return 0;
789}
790
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000791static int lpaint_getStrokeCap(lua_State* L) {
792 SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeCap());
793 return 1;
794}
795
796static int lpaint_getStrokeJoin(lua_State* L) {
797 SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getStrokeJoin());
798 return 1;
799}
800
801static int lpaint_getTextEncoding(lua_State* L) {
commit-bot@chromium.org641bcc32013-12-19 10:39:59 +0000802 SkLua(L).pushU32(get_obj<SkPaint>(L, 1)->getTextEncoding());
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000803 return 1;
804}
805
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000806static int lpaint_getStrokeWidth(lua_State* L) {
807 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeWidth());
808 return 1;
809}
810
811static int lpaint_setStrokeWidth(lua_State* L) {
812 get_obj<SkPaint>(L, 1)->setStrokeWidth(lua2scalar(L, 2));
813 return 0;
814}
815
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000816static int lpaint_getStrokeMiter(lua_State* L) {
817 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->getStrokeMiter());
818 return 1;
819}
820
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000821static int lpaint_measureText(lua_State* L) {
822 if (lua_isstring(L, 2)) {
823 size_t len;
824 const char* text = lua_tolstring(L, 2, &len);
825 SkLua(L).pushScalar(get_obj<SkPaint>(L, 1)->measureText(text, len));
826 return 1;
827 }
828 return 0;
829}
830
831struct FontMetrics {
832 SkScalar fTop; //!< The greatest distance above the baseline for any glyph (will be <= 0)
833 SkScalar fAscent; //!< The recommended distance above the baseline (will be <= 0)
834 SkScalar fDescent; //!< The recommended distance below the baseline (will be >= 0)
835 SkScalar fBottom; //!< The greatest distance below the baseline for any glyph (will be >= 0)
836 SkScalar fLeading; //!< The recommended distance to add between lines of text (will be >= 0)
837 SkScalar fAvgCharWidth; //!< the average charactor width (>= 0)
838 SkScalar fXMin; //!< The minimum bounding box x value for all glyphs
839 SkScalar fXMax; //!< The maximum bounding box x value for all glyphs
840 SkScalar fXHeight; //!< the height of an 'x' in px, or 0 if no 'x' in face
841};
842
843static int lpaint_getFontMetrics(lua_State* L) {
844 SkPaint::FontMetrics fm;
845 SkScalar height = get_obj<SkPaint>(L, 1)->getFontMetrics(&fm);
skia.committer@gmail.com370c5342013-06-09 07:01:05 +0000846
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000847 lua_newtable(L);
848 setfield_scalar(L, "top", fm.fTop);
849 setfield_scalar(L, "ascent", fm.fAscent);
850 setfield_scalar(L, "descent", fm.fDescent);
851 setfield_scalar(L, "bottom", fm.fBottom);
852 setfield_scalar(L, "leading", fm.fLeading);
853 SkLua(L).pushScalar(height);
854 return 2;
855}
856
reed@google.com29563872013-07-10 21:23:49 +0000857static int lpaint_getEffects(lua_State* L) {
858 const SkPaint* paint = get_obj<SkPaint>(L, 1);
skia.committer@gmail.comde2e4e82013-07-11 07:01:01 +0000859
reed@google.com29563872013-07-10 21:23:49 +0000860 lua_newtable(L);
861 setfield_bool_if(L, "looper", !!paint->getLooper());
862 setfield_bool_if(L, "pathEffect", !!paint->getPathEffect());
863 setfield_bool_if(L, "rasterizer", !!paint->getRasterizer());
864 setfield_bool_if(L, "maskFilter", !!paint->getMaskFilter());
865 setfield_bool_if(L, "shader", !!paint->getShader());
866 setfield_bool_if(L, "colorFilter", !!paint->getColorFilter());
867 setfield_bool_if(L, "imageFilter", !!paint->getImageFilter());
868 setfield_bool_if(L, "xfermode", !!paint->getXfermode());
869 return 1;
870}
871
reed@google.com5fdc9832013-07-24 15:47:52 +0000872static int lpaint_getShader(lua_State* L) {
873 const SkPaint* paint = get_obj<SkPaint>(L, 1);
874 SkShader* shader = paint->getShader();
875 if (shader) {
876 push_ref(L, shader);
877 return 1;
878 }
879 return 0;
880}
881
commit-bot@chromium.org1301bf32014-03-17 23:09:47 +0000882static int lpaint_getPathEffect(lua_State* L) {
883 const SkPaint* paint = get_obj<SkPaint>(L, 1);
884 SkPathEffect* pe = paint->getPathEffect();
885 if (pe) {
886 push_ref(L, pe);
887 return 1;
888 }
889 return 0;
890}
891
reed@google.com74ce6f02013-05-22 15:13:18 +0000892static int lpaint_gc(lua_State* L) {
893 get_obj<SkPaint>(L, 1)->~SkPaint();
894 return 0;
895}
896
897static const struct luaL_Reg gSkPaint_Methods[] = {
898 { "isAntiAlias", lpaint_isAntiAlias },
899 { "setAntiAlias", lpaint_setAntiAlias },
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000900 { "isDither", lpaint_isDither },
901 { "isUnderlineText", lpaint_isUnderlineText },
902 { "isStrikeThruText", lpaint_isStrikeThruText },
903 { "isFakeBoldText", lpaint_isFakeBoldText },
904 { "isLinearText", lpaint_isLinearText },
905 { "isSubpixelText", lpaint_isSubpixelText },
906 { "isDevKernText", lpaint_isDevKernText },
907 { "isLCDRenderText", lpaint_isLCDRenderText },
908 { "isEmbeddedBitmapText", lpaint_isEmbeddedBitmapText },
909 { "isAutohinted", lpaint_isAutohinted },
910 { "isVerticalText", lpaint_isVerticalText },
reed@google.com74ce6f02013-05-22 15:13:18 +0000911 { "getColor", lpaint_getColor },
912 { "setColor", lpaint_setColor },
reed@google.come3823fd2013-05-30 18:55:14 +0000913 { "getTextSize", lpaint_getTextSize },
914 { "setTextSize", lpaint_setTextSize },
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000915 { "getTextScaleX", lpaint_getTextScaleX },
916 { "getTextSkewX", lpaint_getTextSkewX },
mike@reedtribe.orge6469f12013-06-08 03:15:47 +0000917 { "getTypeface", lpaint_getTypeface },
918 { "setTypeface", lpaint_setTypeface },
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000919 { "getHinting", lpaint_getHinting },
reed@google.come3823fd2013-05-30 18:55:14 +0000920 { "getFontID", lpaint_getFontID },
mike@reedtribe.orgfb858242013-06-08 16:39:44 +0000921 { "getTextAlign", lpaint_getTextAlign },
922 { "setTextAlign", lpaint_setTextAlign },
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000923 { "getStroke", lpaint_getStroke },
924 { "setStroke", lpaint_setStroke },
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000925 { "getStrokeCap", lpaint_getStrokeCap },
926 { "getStrokeJoin", lpaint_getStrokeJoin },
927 { "getTextEncoding", lpaint_getTextEncoding },
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000928 { "getStrokeWidth", lpaint_getStrokeWidth },
929 { "setStrokeWidth", lpaint_setStrokeWidth },
commit-bot@chromium.org1cd71fb2013-12-18 18:28:07 +0000930 { "getStrokeMiter", lpaint_getStrokeMiter },
mike@reedtribe.org73d9f1c2013-06-09 01:54:56 +0000931 { "measureText", lpaint_measureText },
932 { "getFontMetrics", lpaint_getFontMetrics },
reed@google.com29563872013-07-10 21:23:49 +0000933 { "getEffects", lpaint_getEffects },
reed@google.com5fdc9832013-07-24 15:47:52 +0000934 { "getShader", lpaint_getShader },
commit-bot@chromium.org1301bf32014-03-17 23:09:47 +0000935 { "getPathEffect", lpaint_getPathEffect },
reed@google.com74ce6f02013-05-22 15:13:18 +0000936 { "__gc", lpaint_gc },
937 { NULL, NULL }
938};
939
940///////////////////////////////////////////////////////////////////////////////
941
reed@google.com5fdc9832013-07-24 15:47:52 +0000942static const char* mode2string(SkShader::TileMode mode) {
943 static const char* gNames[] = { "clamp", "repeat", "mirror" };
944 SkASSERT((unsigned)mode < SK_ARRAY_COUNT(gNames));
945 return gNames[mode];
946}
947
948static const char* gradtype2string(SkShader::GradientType t) {
949 static const char* gNames[] = {
950 "none", "color", "linear", "radial", "radial2", "sweep", "conical"
951 };
952 SkASSERT((unsigned)t < SK_ARRAY_COUNT(gNames));
953 return gNames[t];
954}
955
956static int lshader_isOpaque(lua_State* L) {
957 SkShader* shader = get_ref<SkShader>(L, 1);
958 return shader && shader->isOpaque();
959}
960
961static int lshader_asABitmap(lua_State* L) {
962 SkShader* shader = get_ref<SkShader>(L, 1);
963 if (shader) {
964 SkBitmap bm;
965 SkMatrix matrix;
966 SkShader::TileMode modes[2];
967 switch (shader->asABitmap(&bm, &matrix, modes)) {
968 case SkShader::kDefault_BitmapType:
969 lua_newtable(L);
970 setfield_number(L, "genID", bm.pixelRef() ? bm.pixelRef()->getGenerationID() : 0);
971 setfield_number(L, "width", bm.width());
972 setfield_number(L, "height", bm.height());
973 setfield_string(L, "tileX", mode2string(modes[0]));
974 setfield_string(L, "tileY", mode2string(modes[1]));
975 return 1;
976 default:
977 break;
978 }
979 }
980 return 0;
981}
982
983static int lshader_asAGradient(lua_State* L) {
984 SkShader* shader = get_ref<SkShader>(L, 1);
985 if (shader) {
986 SkShader::GradientInfo info;
987 sk_bzero(&info, sizeof(info));
commit-bot@chromium.org74f96b92013-08-01 17:32:56 +0000988
989 SkColor colors[3]; // hacked in for extracting info on 3 color case.
skia.committer@gmail.combd74add2013-08-02 07:00:59 +0000990 SkScalar pos[3];
commit-bot@chromium.org74f96b92013-08-01 17:32:56 +0000991
992 info.fColorCount = 3;
993 info.fColors = &colors[0];
994 info.fColorOffsets = &pos[0];
skia.committer@gmail.combd74add2013-08-02 07:00:59 +0000995
reed@google.com5fdc9832013-07-24 15:47:52 +0000996 SkShader::GradientType t = shader->asAGradient(&info);
commit-bot@chromium.org74f96b92013-08-01 17:32:56 +0000997
reed@google.com5fdc9832013-07-24 15:47:52 +0000998 if (SkShader::kNone_GradientType != t) {
999 lua_newtable(L);
1000 setfield_string(L, "type", gradtype2string(t));
1001 setfield_number(L, "colorCount", info.fColorCount);
1002 setfield_string(L, "tile", mode2string(info.fTileMode));
commit-bot@chromium.org74f96b92013-08-01 17:32:56 +00001003
1004 if (info.fColorCount == 3){
1005 setfield_number(L, "midPos", pos[1]);
1006 }
skia.committer@gmail.combd74add2013-08-02 07:00:59 +00001007
reed@google.com5fdc9832013-07-24 15:47:52 +00001008 return 1;
1009 }
1010 }
1011 return 0;
1012}
1013
1014static int lshader_gc(lua_State* L) {
1015 get_ref<SkShader>(L, 1)->unref();
1016 return 0;
1017}
1018
1019static const struct luaL_Reg gSkShader_Methods[] = {
1020 { "isOpaque", lshader_isOpaque },
1021 { "asABitmap", lshader_asABitmap },
1022 { "asAGradient", lshader_asAGradient },
1023 { "__gc", lshader_gc },
1024 { NULL, NULL }
1025};
1026
1027///////////////////////////////////////////////////////////////////////////////
1028
commit-bot@chromium.org4d803a92014-05-14 16:03:14 +00001029static int lpatheffect_asADash(lua_State* L) {
1030 SkPathEffect* pe = get_ref<SkPathEffect>(L, 1);
1031 if (pe) {
1032 SkPathEffect::DashInfo info;
1033 SkPathEffect::DashType dashType = pe->asADash(&info);
1034 if (SkPathEffect::kDash_DashType == dashType) {
1035 SkAutoTArray<SkScalar> intervals(info.fCount);
1036 info.fIntervals = intervals.get();
1037 pe->asADash(&info);
1038 SkLua(L).pushDash(info);
1039 return 1;
1040 }
1041 }
1042 return 0;
1043}
1044
commit-bot@chromium.org1301bf32014-03-17 23:09:47 +00001045static int lpatheffect_gc(lua_State* L) {
1046 get_ref<SkPathEffect>(L, 1)->unref();
1047 return 0;
1048}
1049
1050static const struct luaL_Reg gSkPathEffect_Methods[] = {
commit-bot@chromium.org4d803a92014-05-14 16:03:14 +00001051 { "asADash", lpatheffect_asADash },
commit-bot@chromium.org1301bf32014-03-17 23:09:47 +00001052 { "__gc", lpatheffect_gc },
1053 { NULL, NULL }
1054};
1055
1056///////////////////////////////////////////////////////////////////////////////
1057
humper@google.com2815c192013-07-10 22:42:30 +00001058static int lmatrix_getType(lua_State* L) {
1059 SkMatrix::TypeMask mask = get_obj<SkMatrix>(L, 1)->getType();
skia.committer@gmail.comde2e4e82013-07-11 07:01:01 +00001060
humper@google.com2815c192013-07-10 22:42:30 +00001061 lua_newtable(L);
1062 setfield_boolean(L, "translate", SkToBool(mask & SkMatrix::kTranslate_Mask));
1063 setfield_boolean(L, "scale", SkToBool(mask & SkMatrix::kScale_Mask));
1064 setfield_boolean(L, "affine", SkToBool(mask & SkMatrix::kAffine_Mask));
1065 setfield_boolean(L, "perspective", SkToBool(mask & SkMatrix::kPerspective_Mask));
1066 return 1;
1067}
1068
humper@google.com0f48ee02013-07-26 15:23:43 +00001069static int lmatrix_getScaleX(lua_State* L) {
1070 lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleX());
1071 return 1;
1072}
1073
1074static int lmatrix_getScaleY(lua_State* L) {
1075 lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getScaleY());
1076 return 1;
1077}
1078
1079static int lmatrix_getTranslateX(lua_State* L) {
1080 lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateX());
1081 return 1;
1082}
1083
1084static int lmatrix_getTranslateY(lua_State* L) {
1085 lua_pushnumber(L, get_obj<SkMatrix>(L,1)->getTranslateY());
1086 return 1;
1087}
1088
humper@google.com2815c192013-07-10 22:42:30 +00001089static const struct luaL_Reg gSkMatrix_Methods[] = {
1090 { "getType", lmatrix_getType },
humper@google.com0f48ee02013-07-26 15:23:43 +00001091 { "getScaleX", lmatrix_getScaleX },
1092 { "getScaleY", lmatrix_getScaleY },
1093 { "getTranslateX", lmatrix_getTranslateX },
1094 { "getTranslateY", lmatrix_getTranslateY },
humper@google.com2815c192013-07-10 22:42:30 +00001095 { NULL, NULL }
1096};
1097
1098///////////////////////////////////////////////////////////////////////////////
1099
reed@google.com74ce6f02013-05-22 15:13:18 +00001100static int lpath_getBounds(lua_State* L) {
1101 SkLua(L).pushRect(get_obj<SkPath>(L, 1)->getBounds());
1102 return 1;
1103}
1104
commit-bot@chromium.orgd85b8222014-02-24 21:59:29 +00001105static const char* fill_type_to_str(SkPath::FillType fill) {
1106 switch (fill) {
1107 case SkPath::kEvenOdd_FillType:
1108 return "even-odd";
1109 case SkPath::kWinding_FillType:
1110 return "winding";
1111 case SkPath::kInverseEvenOdd_FillType:
1112 return "inverse-even-odd";
1113 case SkPath::kInverseWinding_FillType:
1114 return "inverse-winding";
1115 }
1116 return "unknown";
1117}
1118
1119static int lpath_getFillType(lua_State* L) {
1120 SkPath::FillType fill = get_obj<SkPath>(L, 1)->getFillType();
1121 SkLua(L).pushString(fill_type_to_str(fill));
1122 return 1;
1123}
1124
1125static SkString segment_masks_to_str(uint32_t segmentMasks) {
1126 SkString result;
1127 bool first = true;
1128 if (SkPath::kLine_SegmentMask & segmentMasks) {
1129 result.append("line");
1130 first = false;
1131 SkDEBUGCODE(segmentMasks &= ~SkPath::kLine_SegmentMask;)
1132 }
1133 if (SkPath::kQuad_SegmentMask & segmentMasks) {
1134 if (!first) {
1135 result.append(" ");
1136 }
1137 result.append("quad");
1138 first = false;
1139 SkDEBUGCODE(segmentMasks &= ~SkPath::kQuad_SegmentMask;)
1140 }
1141 if (SkPath::kConic_SegmentMask & segmentMasks) {
1142 if (!first) {
1143 result.append(" ");
1144 }
1145 result.append("conic");
1146 first = false;
1147 SkDEBUGCODE(segmentMasks &= ~SkPath::kConic_SegmentMask;)
1148 }
1149 if (SkPath::kCubic_SegmentMask & segmentMasks) {
1150 if (!first) {
1151 result.append(" ");
1152 }
1153 result.append("cubic");
1154 SkDEBUGCODE(segmentMasks &= ~SkPath::kCubic_SegmentMask;)
1155 }
1156 SkASSERT(0 == segmentMasks);
1157 return result;
1158}
1159
krajcevski95498ed2014-08-18 08:02:33 -07001160static int lpath_getSegmentTypes(lua_State* L) {
commit-bot@chromium.orgd85b8222014-02-24 21:59:29 +00001161 uint32_t segMasks = get_obj<SkPath>(L, 1)->getSegmentMasks();
1162 SkLua(L).pushString(segment_masks_to_str(segMasks));
1163 return 1;
1164}
1165
1166static int lpath_isConvex(lua_State* L) {
1167 bool isConvex = SkPath::kConvex_Convexity == get_obj<SkPath>(L, 1)->getConvexity();
1168 SkLua(L).pushBool(isConvex);
1169 return 1;
1170}
1171
reed@google.com74ce6f02013-05-22 15:13:18 +00001172static int lpath_isEmpty(lua_State* L) {
1173 lua_pushboolean(L, get_obj<SkPath>(L, 1)->isEmpty());
1174 return 1;
1175}
1176
1177static int lpath_isRect(lua_State* L) {
1178 SkRect r;
1179 bool pred = get_obj<SkPath>(L, 1)->isRect(&r);
1180 int ret_count = 1;
1181 lua_pushboolean(L, pred);
1182 if (pred) {
1183 SkLua(L).pushRect(r);
1184 ret_count += 1;
1185 }
1186 return ret_count;
1187}
1188
1189static const char* dir2string(SkPath::Direction dir) {
1190 static const char* gStr[] = {
1191 "unknown", "cw", "ccw"
1192 };
1193 SkASSERT((unsigned)dir < SK_ARRAY_COUNT(gStr));
1194 return gStr[dir];
1195}
1196
1197static int lpath_isNestedRects(lua_State* L) {
1198 SkRect rects[2];
1199 SkPath::Direction dirs[2];
1200 bool pred = get_obj<SkPath>(L, 1)->isNestedRects(rects, dirs);
1201 int ret_count = 1;
1202 lua_pushboolean(L, pred);
1203 if (pred) {
1204 SkLua lua(L);
1205 lua.pushRect(rects[0]);
1206 lua.pushRect(rects[1]);
1207 lua_pushstring(L, dir2string(dirs[0]));
1208 lua_pushstring(L, dir2string(dirs[0]));
1209 ret_count += 4;
1210 }
1211 return ret_count;
1212}
1213
commit-bot@chromium.orgc5302082014-02-26 21:38:47 +00001214static int lpath_countPoints(lua_State* L) {
1215 lua_pushinteger(L, get_obj<SkPath>(L, 1)->countPoints());
1216 return 1;
1217}
1218
reed@google.com74ce6f02013-05-22 15:13:18 +00001219static int lpath_reset(lua_State* L) {
1220 get_obj<SkPath>(L, 1)->reset();
1221 return 0;
1222}
1223
1224static int lpath_moveTo(lua_State* L) {
1225 get_obj<SkPath>(L, 1)->moveTo(lua2scalar(L, 2), lua2scalar(L, 3));
1226 return 0;
1227}
1228
1229static int lpath_lineTo(lua_State* L) {
1230 get_obj<SkPath>(L, 1)->lineTo(lua2scalar(L, 2), lua2scalar(L, 3));
1231 return 0;
1232}
1233
1234static int lpath_quadTo(lua_State* L) {
1235 get_obj<SkPath>(L, 1)->quadTo(lua2scalar(L, 2), lua2scalar(L, 3),
1236 lua2scalar(L, 4), lua2scalar(L, 5));
1237 return 0;
1238}
1239
1240static int lpath_cubicTo(lua_State* L) {
1241 get_obj<SkPath>(L, 1)->cubicTo(lua2scalar(L, 2), lua2scalar(L, 3),
1242 lua2scalar(L, 4), lua2scalar(L, 5),
1243 lua2scalar(L, 6), lua2scalar(L, 7));
1244 return 0;
1245}
1246
1247static int lpath_close(lua_State* L) {
1248 get_obj<SkPath>(L, 1)->close();
1249 return 0;
1250}
1251
1252static int lpath_gc(lua_State* L) {
1253 get_obj<SkPath>(L, 1)->~SkPath();
1254 return 0;
1255}
1256
1257static const struct luaL_Reg gSkPath_Methods[] = {
1258 { "getBounds", lpath_getBounds },
commit-bot@chromium.orgd85b8222014-02-24 21:59:29 +00001259 { "getFillType", lpath_getFillType },
krajcevski95498ed2014-08-18 08:02:33 -07001260 { "getSegmentTypes", lpath_getSegmentTypes },
commit-bot@chromium.orgd85b8222014-02-24 21:59:29 +00001261 { "isConvex", lpath_isConvex },
reed@google.com74ce6f02013-05-22 15:13:18 +00001262 { "isEmpty", lpath_isEmpty },
1263 { "isRect", lpath_isRect },
1264 { "isNestedRects", lpath_isNestedRects },
commit-bot@chromium.orgc5302082014-02-26 21:38:47 +00001265 { "countPoints", lpath_countPoints },
reed@google.com74ce6f02013-05-22 15:13:18 +00001266 { "reset", lpath_reset },
1267 { "moveTo", lpath_moveTo },
1268 { "lineTo", lpath_lineTo },
1269 { "quadTo", lpath_quadTo },
1270 { "cubicTo", lpath_cubicTo },
1271 { "close", lpath_close },
1272 { "__gc", lpath_gc },
1273 { NULL, NULL }
1274};
1275
1276///////////////////////////////////////////////////////////////////////////////
1277
1278static const char* rrect_type(const SkRRect& rr) {
1279 switch (rr.getType()) {
1280 case SkRRect::kUnknown_Type: return "unknown";
1281 case SkRRect::kEmpty_Type: return "empty";
1282 case SkRRect::kRect_Type: return "rect";
1283 case SkRRect::kOval_Type: return "oval";
1284 case SkRRect::kSimple_Type: return "simple";
commit-bot@chromium.orgf338d7c2014-03-17 21:17:30 +00001285 case SkRRect::kNinePatch_Type: return "nine-patch";
reed@google.com74ce6f02013-05-22 15:13:18 +00001286 case SkRRect::kComplex_Type: return "complex";
1287 }
mtklein@google.com330313a2013-08-22 15:37:26 +00001288 SkDEBUGFAIL("never get here");
reed@google.com74ce6f02013-05-22 15:13:18 +00001289 return "";
1290}
1291
1292static int lrrect_rect(lua_State* L) {
1293 SkLua(L).pushRect(get_obj<SkRRect>(L, 1)->rect());
1294 return 1;
1295}
1296
1297static int lrrect_type(lua_State* L) {
1298 lua_pushstring(L, rrect_type(*get_obj<SkRRect>(L, 1)));
1299 return 1;
1300}
1301
1302static int lrrect_radii(lua_State* L) {
reed@google.com7fa2a652014-01-27 13:42:58 +00001303 int corner = SkToInt(lua_tointeger(L, 2));
reed@google.com74ce6f02013-05-22 15:13:18 +00001304 SkVector v;
1305 if (corner < 0 || corner > 3) {
1306 SkDebugf("bad corner index %d", corner);
1307 v.set(0, 0);
1308 } else {
1309 v = get_obj<SkRRect>(L, 1)->radii((SkRRect::Corner)corner);
1310 }
1311 lua_pushnumber(L, v.fX);
1312 lua_pushnumber(L, v.fY);
1313 return 2;
1314}
1315
1316static int lrrect_gc(lua_State* L) {
1317 get_obj<SkRRect>(L, 1)->~SkRRect();
1318 return 0;
1319}
1320
1321static const struct luaL_Reg gSkRRect_Methods[] = {
1322 { "rect", lrrect_rect },
1323 { "type", lrrect_type },
1324 { "radii", lrrect_radii },
1325 { "__gc", lrrect_gc },
1326 { NULL, NULL }
1327};
1328
1329///////////////////////////////////////////////////////////////////////////////
1330
mike@reedtribe.org792bbd12013-06-11 02:20:28 +00001331static int limage_width(lua_State* L) {
1332 lua_pushinteger(L, get_ref<SkImage>(L, 1)->width());
1333 return 1;
1334}
1335
1336static int limage_height(lua_State* L) {
1337 lua_pushinteger(L, get_ref<SkImage>(L, 1)->height());
1338 return 1;
1339}
1340
1341static int limage_gc(lua_State* L) {
1342 get_ref<SkImage>(L, 1)->unref();
1343 return 0;
1344}
1345
1346static const struct luaL_Reg gSkImage_Methods[] = {
1347 { "width", limage_width },
1348 { "height", limage_height },
1349 { "__gc", limage_gc },
1350 { NULL, NULL }
1351};
1352
1353///////////////////////////////////////////////////////////////////////////////
1354
mike@reedtribe.orge6469f12013-06-08 03:15:47 +00001355static int ltypeface_gc(lua_State* L) {
commit-bot@chromium.org77887af2013-12-17 14:28:19 +00001356 SkSafeUnref(get_ref<SkTypeface>(L, 1));
mike@reedtribe.orge6469f12013-06-08 03:15:47 +00001357 return 0;
1358}
1359
1360static const struct luaL_Reg gSkTypeface_Methods[] = {
1361 { "__gc", ltypeface_gc },
1362 { NULL, NULL }
1363};
1364
1365///////////////////////////////////////////////////////////////////////////////
1366
reed@google.com74ce6f02013-05-22 15:13:18 +00001367class AutoCallLua {
1368public:
1369 AutoCallLua(lua_State* L, const char func[], const char verb[]) : fL(L) {
1370 lua_getglobal(L, func);
1371 if (!lua_isfunction(L, -1)) {
1372 int t = lua_type(L, -1);
1373 SkDebugf("--- expected function %d\n", t);
1374 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +00001375
reed@google.com74ce6f02013-05-22 15:13:18 +00001376 lua_newtable(L);
1377 setfield_string(L, "verb", verb);
1378 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +00001379
reed@google.com74ce6f02013-05-22 15:13:18 +00001380 ~AutoCallLua() {
1381 if (lua_pcall(fL, 1, 0, 0) != LUA_OK) {
1382 SkDebugf("lua err: %s\n", lua_tostring(fL, -1));
1383 }
1384 lua_settop(fL, -1);
1385 }
skia.committer@gmail.com2d816ad2013-05-23 07:01:22 +00001386
reed@google.com74ce6f02013-05-22 15:13:18 +00001387private:
1388 lua_State* fL;
1389};
1390
1391#define AUTO_LUA(verb) AutoCallLua acl(fL, fFunc.c_str(), verb)
1392
1393///////////////////////////////////////////////////////////////////////////////
1394
mike@reedtribe.orgfb858242013-06-08 16:39:44 +00001395static int lsk_newDocumentPDF(lua_State* L) {
1396 const char* file = NULL;
1397 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
1398 file = lua_tolstring(L, 1, NULL);
1399 }
1400
1401 SkDocument* doc = SkDocument::CreatePDF(file);
1402 if (NULL == doc) {
1403 // do I need to push a nil on the stack and return 1?
1404 return 0;
1405 } else {
1406 push_ref(L, doc);
1407 doc->unref();
1408 return 1;
1409 }
1410}
1411
reed@google.com3597b732013-05-22 20:12:50 +00001412static int lsk_newPaint(lua_State* L) {
1413 push_new<SkPaint>(L);
1414 return 1;
1415}
1416
1417static int lsk_newPath(lua_State* L) {
1418 push_new<SkPath>(L);
1419 return 1;
1420}
1421
1422static int lsk_newRRect(lua_State* L) {
1423 SkRRect* rr = push_new<SkRRect>(L);
1424 rr->setEmpty();
1425 return 1;
1426}
1427
mike@reedtribe.orge6469f12013-06-08 03:15:47 +00001428static int lsk_newTypeface(lua_State* L) {
1429 const char* name = NULL;
1430 int style = SkTypeface::kNormal;
skia.committer@gmail.com63193672013-06-08 07:01:13 +00001431
mike@reedtribe.orge6469f12013-06-08 03:15:47 +00001432 int count = lua_gettop(L);
1433 if (count > 0 && lua_isstring(L, 1)) {
1434 name = lua_tolstring(L, 1, NULL);
1435 if (count > 1 && lua_isnumber(L, 2)) {
1436 style = lua_tointegerx(L, 2, NULL) & SkTypeface::kBoldItalic;
1437 }
1438 }
1439
1440 SkTypeface* face = SkTypeface::CreateFromName(name,
1441 (SkTypeface::Style)style);
1442// SkDebugf("---- name <%s> style=%d, face=%p ref=%d\n", name, style, face, face->getRefCnt());
1443 if (NULL == face) {
1444 face = SkTypeface::RefDefault();
1445 }
1446 push_ref(L, face);
1447 face->unref();
1448 return 1;
1449}
reed@google.com3597b732013-05-22 20:12:50 +00001450
mike@reedtribe.org792bbd12013-06-11 02:20:28 +00001451static int lsk_loadImage(lua_State* L) {
1452 if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
1453 const char* name = lua_tolstring(L, 1, NULL);
1454 SkAutoDataUnref data(SkData::NewFromFileName(name));
1455 if (data.get()) {
1456 SkImage* image = SkImage::NewEncodedData(data.get());
1457 if (image) {
1458 push_ref(L, image);
1459 image->unref();
1460 return 1;
1461 }
1462 }
1463 }
1464 return 0;
1465}
1466
reed@google.com3597b732013-05-22 20:12:50 +00001467static void register_Sk(lua_State* L) {
1468 lua_newtable(L);
1469 lua_pushvalue(L, -1);
1470 lua_setglobal(L, "Sk");
1471 // the Sk table is still on top
1472
mike@reedtribe.orgfb858242013-06-08 16:39:44 +00001473 setfield_function(L, "newDocumentPDF", lsk_newDocumentPDF);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +00001474 setfield_function(L, "loadImage", lsk_loadImage);
reed@google.com3597b732013-05-22 20:12:50 +00001475 setfield_function(L, "newPaint", lsk_newPaint);
1476 setfield_function(L, "newPath", lsk_newPath);
1477 setfield_function(L, "newRRect", lsk_newRRect);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +00001478 setfield_function(L, "newTypeface", lsk_newTypeface);
reed@google.com3597b732013-05-22 20:12:50 +00001479 lua_pop(L, 1); // pop off the Sk table
1480}
1481
reed@google.com74ce6f02013-05-22 15:13:18 +00001482#define REG_CLASS(L, C) \
1483 do { \
reed@google.com3597b732013-05-22 20:12:50 +00001484 luaL_newmetatable(L, get_mtname<C>()); \
reed@google.com74ce6f02013-05-22 15:13:18 +00001485 lua_pushvalue(L, -1); \
1486 lua_setfield(L, -2, "__index"); \
1487 luaL_setfuncs(L, g##C##_Methods, 0); \
1488 lua_pop(L, 1); /* pop off the meta-table */ \
1489 } while (0)
1490
1491void SkLua::Load(lua_State* L) {
reed@google.com3597b732013-05-22 20:12:50 +00001492 register_Sk(L);
reed@google.com74ce6f02013-05-22 15:13:18 +00001493 REG_CLASS(L, SkCanvas);
mike@reedtribe.orgfb858242013-06-08 16:39:44 +00001494 REG_CLASS(L, SkDocument);
mike@reedtribe.org792bbd12013-06-11 02:20:28 +00001495 REG_CLASS(L, SkImage);
reed@google.com74ce6f02013-05-22 15:13:18 +00001496 REG_CLASS(L, SkPaint);
commit-bot@chromium.org1301bf32014-03-17 23:09:47 +00001497 REG_CLASS(L, SkPath);
1498 REG_CLASS(L, SkPathEffect);
reed@google.com74ce6f02013-05-22 15:13:18 +00001499 REG_CLASS(L, SkRRect);
reed@google.com5fdc9832013-07-24 15:47:52 +00001500 REG_CLASS(L, SkShader);
mike@reedtribe.orge6469f12013-06-08 03:15:47 +00001501 REG_CLASS(L, SkTypeface);
humper@google.com2815c192013-07-10 22:42:30 +00001502 REG_CLASS(L, SkMatrix);
reed@google.com74ce6f02013-05-22 15:13:18 +00001503}
zachr@google.com28c27c82013-06-20 17:15:05 +00001504
reed@google.com7bce9982013-06-20 17:40:21 +00001505extern "C" int luaopen_skia(lua_State* L);
zachr@google.com28c27c82013-06-20 17:15:05 +00001506extern "C" int luaopen_skia(lua_State* L) {
1507 SkLua::Load(L);
1508 return 0;
1509}