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