• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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