1 /*
2 * Copyright 2017 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 "src/core/SkUtils.h"
9 #include "tools/ModifierKey.h"
10 #include "tools/sk_app/ios/WindowContextFactory_ios.h"
11 #include "tools/sk_app/ios/Window_ios.h"
12 #include "tools/timer/Timer.h"
13
14 namespace sk_app {
15
16 SkTDynamicHash<Window_ios, Uint32> Window_ios::gWindowMap;
17
CreateNativeWindow(void *)18 Window* Window::CreateNativeWindow(void*) {
19 Window_ios* window = new Window_ios();
20 if (!window->initWindow()) {
21 delete window;
22 return nullptr;
23 }
24
25 return window;
26 }
27
initWindow()28 bool Window_ios::initWindow() {
29 if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) {
30 this->closeWindow();
31 }
32 // we already have a window
33 if (fWindow) {
34 return true;
35 }
36
37 constexpr int initialWidth = 1280;
38 constexpr int initialHeight = 960;
39
40 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
41 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
42 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
43
44 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
45 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
46 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
47 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
48 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
49 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
50
51 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
52
53 if (fRequestedDisplayParams.fMSAASampleCount > 1) {
54 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
55 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fRequestedDisplayParams.fMSAASampleCount);
56 } else {
57 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
58 }
59 // TODO: handle other display params
60
61 uint32_t windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_ALLOW_HIGHDPI;
62 fWindow = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
63 initialWidth, initialHeight, windowFlags);
64
65 if (!fWindow) {
66 return false;
67 }
68
69 fMSAASampleCount = fRequestedDisplayParams.fMSAASampleCount;
70
71 // add to hashtable of windows
72 fWindowID = SDL_GetWindowID(fWindow);
73 gWindowMap.add(this);
74
75 fGLContext = SDL_GL_CreateContext(fWindow);
76 if (!fGLContext) {
77 SkDebugf("%s\n", SDL_GetError());
78 this->closeWindow();
79 return false;
80 }
81
82 return true;
83 }
84
closeWindow()85 void Window_ios::closeWindow() {
86 if (fGLContext) {
87 SDL_GL_DeleteContext(fGLContext);
88 fGLContext = nullptr;
89 }
90
91 if (fWindow) {
92 gWindowMap.remove(fWindowID);
93 SDL_DestroyWindow(fWindow);
94 fWindowID = 0;
95 fWindow = nullptr;
96 }
97 }
98
get_key(const SDL_Keysym & keysym)99 static Window::Key get_key(const SDL_Keysym& keysym) {
100 static const struct {
101 SDL_Keycode fSDLK;
102 Window::Key fKey;
103 } gPair[] = {
104 { SDLK_BACKSPACE, Window::Key::kBack },
105 { SDLK_CLEAR, Window::Key::kBack },
106 { SDLK_RETURN, Window::Key::kOK },
107 { SDLK_UP, Window::Key::kUp },
108 { SDLK_DOWN, Window::Key::kDown },
109 { SDLK_LEFT, Window::Key::kLeft },
110 { SDLK_RIGHT, Window::Key::kRight },
111 { SDLK_TAB, Window::Key::kTab },
112 { SDLK_PAGEUP, Window::Key::kPageUp },
113 { SDLK_PAGEDOWN, Window::Key::kPageDown },
114 { SDLK_HOME, Window::Key::kHome },
115 { SDLK_END, Window::Key::kEnd },
116 { SDLK_DELETE, Window::Key::kDelete },
117 { SDLK_ESCAPE, Window::Key::kEscape },
118 { SDLK_LSHIFT, Window::Key::kShift },
119 { SDLK_RSHIFT, Window::Key::kShift },
120 { SDLK_LCTRL, Window::Key::kCtrl },
121 { SDLK_RCTRL, Window::Key::kCtrl },
122 { SDLK_LALT, Window::Key::kOption },
123 { SDLK_LALT, Window::Key::kOption },
124 { 'A', Window::Key::kA },
125 { 'C', Window::Key::kC },
126 { 'V', Window::Key::kV },
127 { 'X', Window::Key::kX },
128 { 'Y', Window::Key::kY },
129 { 'Z', Window::Key::kZ },
130 };
131 for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
132 if (gPair[i].fSDLK == keysym.sym) {
133 return gPair[i].fKey;
134 }
135 }
136 return Window::Key::kNONE;
137 }
138
get_modifiers(const SDL_Event & event)139 static ModifierKey get_modifiers(const SDL_Event& event) {
140 static const struct {
141 unsigned fSDLMask;
142 ModifierKey fSkMask;
143 } gModifiers[] = {
144 { KMOD_SHIFT, ModifierKey::kShift },
145 { KMOD_CTRL, ModifierKey::kControl },
146 { KMOD_ALT, ModifierKey::kOption },
147 };
148
149 ModifierKey modifiers = ModifierKey::kNone;
150
151 switch (event.type) {
152 case SDL_KEYDOWN:
153 // fall through
154 case SDL_KEYUP: {
155 for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
156 if (event.key.keysym.mod & gModifiers[i].fSDLMask) {
157 modifiers |= gModifiers[i].fSkMask;
158 }
159 }
160 if (0 == event.key.repeat) {
161 modifiers |= ModifierKey::kFirstPress;
162 }
163 break;
164 }
165
166 default: {
167 SDL_Keymod mod = SDL_GetModState();
168 for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
169 if (mod & gModifiers[i].fSDLMask) {
170 modifiers |= gModifiers[i].fSkMask;
171 }
172 }
173 break;
174 }
175 }
176 return modifiers;
177 }
178
HandleWindowEvent(const SDL_Event & event)179 bool Window_ios::HandleWindowEvent(const SDL_Event& event) {
180 Window_ios* win = gWindowMap.find(event.window.windowID);
181 if (win && win->handleEvent(event)) {
182 return true;
183 }
184
185 return false;
186 }
187
handleEvent(const SDL_Event & event)188 bool Window_ios::handleEvent(const SDL_Event& event) {
189 switch (event.type) {
190 case SDL_WINDOWEVENT:
191 if (SDL_WINDOWEVENT_EXPOSED == event.window.event) {
192 this->onPaint();
193 } else if (SDL_WINDOWEVENT_RESIZED == event.window.event) {
194 this->onResize(event.window.data1, event.window.data2);
195 }
196 break;
197
198 case SDL_FINGERDOWN:
199 this->onTouch(event.tfinger.fingerId, InputState::kDown,
200 (int)(this->width()*event.tfinger.x),
201 (int)(this->height()*event.tfinger.y));
202 break;
203
204 case SDL_FINGERUP:
205 this->onTouch(event.tfinger.fingerId, InputState::kUp,
206 (int)(this->width()*event.tfinger.x),
207 (int)(this->height()*event.tfinger.y));
208 break;
209
210 case SDL_FINGERMOTION:
211 this->onTouch(event.tfinger.fingerId, InputState::kMove,
212 (int)(this->width()*event.tfinger.x),
213 (int)(this->height()*event.tfinger.y));
214 break;
215
216 case SDL_KEYDOWN: {
217 Window::Key key = get_key(event.key.keysym);
218 if (key != Window::Key::kNONE) {
219 if (!this->onKey(key, InputState::kDown, get_modifiers(event))) {
220 if (event.key.keysym.sym == SDLK_ESCAPE) {
221 return true;
222 }
223 }
224 }
225 } break;
226
227 case SDL_KEYUP: {
228 Window::Key key = get_key(event.key.keysym);
229 if (key != Window::Key::kNONE) {
230 (void) this->onKey(key, InputState::kUp,
231 get_modifiers(event));
232 }
233 } break;
234
235 case SDL_TEXTINPUT: {
236 const char* textIter = &event.text.text[0];
237 while (SkUnichar c = SkUTF8_NextUnichar(&textIter)) {
238 (void) this->onChar(c, get_modifiers(event));
239 }
240 } break;
241
242 default:
243 break;
244 }
245
246 return false;
247 }
248
setTitle(const char * title)249 void Window_ios::setTitle(const char* title) {
250 SDL_SetWindowTitle(fWindow, title);
251 }
252
show()253 void Window_ios::show() {
254 SDL_ShowWindow(fWindow);
255 }
256
attach(BackendType attachType)257 bool Window_ios::attach(BackendType attachType) {
258 this->initWindow();
259
260 window_context_factory::IOSWindowInfo info;
261 info.fWindow = fWindow;
262 info.fGLContext = fGLContext;
263 switch (attachType) {
264 case kRaster_BackendType:
265 fWindowContext = MakeRasterForIOS(info, fRequestedDisplayParams);
266 break;
267
268 case kNativeGL_BackendType:
269 default:
270 fWindowContext = MakeGLForIOS(info, fRequestedDisplayParams);
271 break;
272 }
273 this->onBackendCreated();
274
275 return (SkToBool(fWindowContext));
276 }
277
onInval()278 void Window_ios::onInval() {
279 SDL_Event sdlevent;
280 sdlevent.type = SDL_WINDOWEVENT;
281 sdlevent.window.windowID = fWindowID;
282 sdlevent.window.event = SDL_WINDOWEVENT_EXPOSED;
283 SDL_PushEvent(&sdlevent);
284 }
285
286 } // namespace sk_app
287