1 /*
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 "SampleCode.h"
9 #include "SkView.h"
10 #include "SkLua.h"
11 #include "SkCanvas.h"
12 #include "Resources.h"
13 #include "SkData.h"
14
15 extern "C" {
16 #include "lua.h"
17 #include "lualib.h"
18 #include "lauxlib.h"
19 }
20
21 //#define LUA_FILENAME "test.lua"
22 #define LUA_FILENAME "slides.lua"
23
24 static const char gDrawName[] = "onDrawContent";
25 static const char gClickName[] = "onClickHandler";
26 static const char gUnicharName[] = "onCharHandler";
27
28 static const char gLuaClickHandlerName[] = "lua-click-handler";
29
30 static const char gMissingCode[] = ""
31 "local paint = Sk.newPaint()"
32 "paint:setAntiAlias(true)"
33 "paint:setTextSize(30)"
34 ""
35 "function onDrawContent(canvas)"
36 " canvas:drawText('missing \"test.lua\"', 20, 50, paint)"
37 "end"
38 ;
39
40 class LuaView : public SampleView {
41 public:
LuaView()42 LuaView() : fLua(nullptr) {}
43
~LuaView()44 virtual ~LuaView() { delete fLua; }
45
setImageFilename(lua_State * L)46 void setImageFilename(lua_State* L) {
47 SkString str = GetResourcePath("mandrill_256.png");
48
49 lua_getglobal(L, "setImageFilename");
50 if (lua_isfunction(L, -1)) {
51 fLua->pushString(str.c_str());
52 if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
53 SkDebugf("lua err: %s\n", lua_tostring(L, -1));
54 }
55 }
56 }
57
ensureLua()58 lua_State* ensureLua() {
59 if (nullptr == fLua) {
60 fLua = new SkLua;
61
62 SkString str = GetResourcePath(LUA_FILENAME);
63 SkData* data = SkData::NewFromFileName(str.c_str());
64 if (data) {
65 fLua->runCode(data->data(), data->size());
66 data->unref();
67 this->setImageFilename(fLua->get());
68 } else {
69 fLua->runCode(gMissingCode);
70 }
71 }
72 return fLua->get();
73 }
74
75 protected:
onQuery(SkEvent * evt)76 bool onQuery(SkEvent* evt) override {
77 if (SampleCode::TitleQ(*evt)) {
78 SampleCode::TitleR(evt, "Lua");
79 return true;
80 }
81 SkUnichar uni;
82 if (SampleCode::CharQ(*evt, &uni)) {
83 lua_State* L = this->ensureLua();
84 lua_getglobal(L, gUnicharName);
85 if (lua_isfunction(L, -1)) {
86 SkString str;
87 str.appendUnichar(uni);
88 fLua->pushString(str.c_str());
89 if (lua_pcall(L, 1, 1, 0) != LUA_OK) {
90 SkDebugf("lua err: %s\n", lua_tostring(L, -1));
91 } else {
92 if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
93 this->inval(nullptr);
94 return true;
95 }
96 }
97 }
98 }
99 return this->INHERITED::onQuery(evt);
100 }
101
onDrawContent(SkCanvas * canvas)102 void onDrawContent(SkCanvas* canvas) override {
103 lua_State* L = this->ensureLua();
104
105 lua_getglobal(L, gDrawName);
106 if (!lua_isfunction(L, -1)) {
107 int t = lua_type(L, -1);
108 SkDebugf("--- expected %s function %d, ignoring.\n", gDrawName, t);
109 lua_pop(L, 1);
110 } else {
111 // does it make sense to try to "cache" the lua version of this
112 // canvas between draws?
113 fLua->pushCanvas(canvas);
114 fLua->pushScalar(this->width());
115 fLua->pushScalar(this->height());
116 if (lua_pcall(L, 3, 1, 0) != LUA_OK) {
117 SkDebugf("lua err: %s\n", lua_tostring(L, -1));
118 } else {
119 if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
120 this->inval(nullptr);
121 }
122 }
123 }
124 }
125
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)126 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
127 unsigned modi) override {
128 lua_State* L = this->ensureLua();
129 lua_getglobal(L, gClickName);
130 if (lua_isfunction(L, -1)) {
131 fLua->pushScalar(x);
132 fLua->pushScalar(y);
133 fLua->pushString("down");
134 if (lua_pcall(L, 3, 1, 0) != LUA_OK) {
135 SkDebugf("lua err: %s\n", lua_tostring(L, -1));
136 } else {
137 if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
138 this->inval(nullptr);
139 Click* c = new Click(this);
140 c->setType(gLuaClickHandlerName);
141 return c;
142 }
143 }
144 }
145 return this->INHERITED::onFindClickHandler(x, y, modi);
146 }
147
onClick(Click * click)148 bool onClick(Click* click) override {
149 if (click->getType() != gLuaClickHandlerName) {
150 return this->INHERITED::onClick(click);
151 }
152
153 const char* state = nullptr;
154 switch (click->fState) {
155 case Click::kMoved_State:
156 state = "moved";
157 break;
158 case Click::kUp_State:
159 state = "up";
160 break;
161 default:
162 break;
163 }
164 if (state) {
165 this->inval(nullptr);
166 lua_State* L = fLua->get();
167 lua_getglobal(L, gClickName);
168 fLua->pushScalar(click->fCurr.x());
169 fLua->pushScalar(click->fCurr.y());
170 fLua->pushString(state);
171 lua_pcall(L, 3, 1, 0);
172 return lua_isboolean(L, -1) && lua_toboolean(L, -1);
173 }
174 return true;
175 }
176
177 private:
178 SkLua* fLua;
179
180 typedef SampleView INHERITED;
181 };
182
183 //////////////////////////////////////////////////////////////////////////////
184
MyFactory()185 static SkView* MyFactory() { return new LuaView; }
186 static SkViewRegister reg(MyFactory);
187