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