blob: 5451fca075ac369fddd2ded1795e158937b4aa71 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkWindow.h"
9#include "SkCanvas.h"
reed@android.comf2b98d62010-12-20 18:26:13 +000010#include "SkDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkOSMenu.h"
12#include "SkSystemEventTypes.h"
13#include "SkTime.h"
14
15#define SK_EventDelayInval "\xd" "n" "\xa" "l"
16
17#define TEST_BOUNDERx
18
19#include "SkBounder.h"
tfarina@chromium.org658650c2014-01-25 18:45:45 +000020class TestSkBounder : public SkBounder {
reed@android.com8a1c16f2008-12-17 15:59:43 +000021public:
tfarina@chromium.org658650c2014-01-25 18:45:45 +000022 explicit TestSkBounder(const SkBitmap& bm) : fCanvas(bm) {}
23
reed@android.com8a1c16f2008-12-17 15:59:43 +000024protected:
tfarina@chromium.org658650c2014-01-25 18:45:45 +000025 virtual bool onIRect(const SkIRect& r) SK_OVERRIDE {
rmistry@google.comd6176b02012-08-23 18:14:13 +000026 SkRect rr;
reed@android.com8a1c16f2008-12-17 15:59:43 +000027
rmistry@google.comd6176b02012-08-23 18:14:13 +000028 rr.set(SkIntToScalar(r.fLeft), SkIntToScalar(r.fTop),
29 SkIntToScalar(r.fRight), SkIntToScalar(r.fBottom));
reed@android.com8a1c16f2008-12-17 15:59:43 +000030
rmistry@google.comd6176b02012-08-23 18:14:13 +000031 SkPaint p;
reed@android.com8a1c16f2008-12-17 15:59:43 +000032
rmistry@google.comd6176b02012-08-23 18:14:13 +000033 p.setStyle(SkPaint::kStroke_Style);
34 p.setColor(SK_ColorYELLOW);
reed@android.com8a1c16f2008-12-17 15:59:43 +000035
36#if 0
rmistry@google.comd6176b02012-08-23 18:14:13 +000037 rr.inset(SK_ScalarHalf, SK_ScalarHalf);
reed@android.com8a1c16f2008-12-17 15:59:43 +000038#else
rmistry@google.comd6176b02012-08-23 18:14:13 +000039 rr.inset(-SK_ScalarHalf, -SK_ScalarHalf);
reed@android.com8a1c16f2008-12-17 15:59:43 +000040#endif
41
rmistry@google.comd6176b02012-08-23 18:14:13 +000042 fCanvas.drawRect(rr, p);
43 return true;
44 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000045private:
rmistry@google.comd6176b02012-08-23 18:14:13 +000046 SkCanvas fCanvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +000047};
48
tfarina@chromium.org658650c2014-01-25 18:45:45 +000049SkWindow::SkWindow() : fFocusView(NULL) {
Scroggod3aed392011-06-22 13:26:56 +000050 fClicks.reset();
51 fWaitingOnInval = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +000052
53#ifdef SK_BUILD_FOR_WINCE
Scroggod3aed392011-06-22 13:26:56 +000054 fConfig = SkBitmap::kRGB_565_Config;
reed@android.com8a1c16f2008-12-17 15:59:43 +000055#else
Scroggod3aed392011-06-22 13:26:56 +000056 fConfig = SkBitmap::kARGB_8888_Config;
reed@android.com8a1c16f2008-12-17 15:59:43 +000057#endif
reed@android.comf2b98d62010-12-20 18:26:13 +000058
59 fMatrix.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +000060}
61
tfarina@chromium.org658650c2014-01-25 18:45:45 +000062SkWindow::~SkWindow() {
Scroggod3aed392011-06-22 13:26:56 +000063 fClicks.deleteAll();
64 fMenus.deleteAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000065}
66
reed@google.com5957f472012-10-01 20:31:56 +000067SkCanvas* SkWindow::createCanvas() {
68 return new SkCanvas(this->getBitmap());
69}
70
reed@android.comf2b98d62010-12-20 18:26:13 +000071void SkWindow::setMatrix(const SkMatrix& matrix) {
72 if (fMatrix != matrix) {
73 fMatrix = matrix;
74 this->inval(NULL);
75 }
76}
77
78void SkWindow::preConcat(const SkMatrix& matrix) {
79 SkMatrix m;
80 m.setConcat(fMatrix, matrix);
81 this->setMatrix(m);
82}
83
84void SkWindow::postConcat(const SkMatrix& matrix) {
85 SkMatrix m;
86 m.setConcat(matrix, fMatrix);
87 this->setMatrix(m);
88}
89
tfarina@chromium.org658650c2014-01-25 18:45:45 +000090void SkWindow::setConfig(SkBitmap::Config config) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000091 this->resize(fBitmap.width(), fBitmap.height(), config);
reed@android.com8a1c16f2008-12-17 15:59:43 +000092}
93
tfarina@chromium.org658650c2014-01-25 18:45:45 +000094void SkWindow::resize(int width, int height, SkBitmap::Config config) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000095 if (config == SkBitmap::kNo_Config)
96 config = fConfig;
reed@android.com8a1c16f2008-12-17 15:59:43 +000097
tfarina@chromium.org658650c2014-01-25 18:45:45 +000098 if (width != fBitmap.width() || height != fBitmap.height() || config != fConfig) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000099 fConfig = config;
reed@google.com383a6972013-10-21 14:00:07 +0000100 fBitmap.setConfig(config, width, height, 0, kOpaque_SkAlphaType);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000101 fBitmap.allocPixels();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102
rmistry@google.comd6176b02012-08-23 18:14:13 +0000103 this->setSize(SkIntToScalar(width), SkIntToScalar(height));
104 this->inval(NULL);
105 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106}
107
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000108bool SkWindow::handleInval(const SkRect* localR) {
109 SkIRect ir;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110
reed@android.comf2b98d62010-12-20 18:26:13 +0000111 if (localR) {
112 SkRect devR;
113 SkMatrix inverse;
114 if (!fMatrix.invert(&inverse)) {
115 return false;
116 }
117 fMatrix.mapRect(&devR, *localR);
118 devR.round(&ir);
119 } else {
reed@google.comf9bb7a82011-03-01 15:15:13 +0000120 ir.set(0, 0,
reed@google.come1ca7052013-12-17 19:22:07 +0000121 SkScalarRoundToInt(this->width()),
122 SkScalarRoundToInt(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000123 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000124 fDirtyRgn.op(ir, SkRegion::kUnion_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125
rmistry@google.comd6176b02012-08-23 18:14:13 +0000126 this->onHandleInval(ir);
127 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128}
129
reed@android.comf2b98d62010-12-20 18:26:13 +0000130void SkWindow::forceInvalAll() {
reed@google.com261b8e22011-04-14 17:53:24 +0000131 fDirtyRgn.setRect(0, 0,
reed@google.come1ca7052013-12-17 19:22:07 +0000132 SkScalarCeilToInt(this->width()),
133 SkScalarCeilToInt(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000134}
135
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000137 #include <windows.h>
138 #include <gx.h>
139 extern GXDisplayProperties gDisplayProps;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140#endif
141
142#ifdef SK_SIMULATE_FAILED_MALLOC
143extern bool gEnableControlledThrow;
144#endif
145
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000146bool SkWindow::update(SkIRect* updateArea) {
147 if (!fDirtyRgn.isEmpty()) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000148 SkBitmap bm = this->getBitmap();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149
150#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000151 char* buffer = (char*)GXBeginDraw();
152 SkASSERT(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153
rmistry@google.comd6176b02012-08-23 18:14:13 +0000154 RECT rect;
155 GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect);
156 buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157
rmistry@google.comd6176b02012-08-23 18:14:13 +0000158 bm.setPixels(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159#endif
160
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000161 SkAutoTUnref<SkCanvas> canvas(this->createCanvas());
162
163 canvas->clipRegion(fDirtyRgn);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000164 if (updateArea)
165 *updateArea = fDirtyRgn.getBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000167 SkAutoCanvasRestore acr(canvas, true);
168 canvas->concat(fMatrix);
reed@android.comf2b98d62010-12-20 18:26:13 +0000169
rmistry@google.comd6176b02012-08-23 18:14:13 +0000170 // empty this now, so we can correctly record any inval calls that
171 // might be made during the draw call.
172 fDirtyRgn.setEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173
174#ifdef TEST_BOUNDER
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000175 TestSkBounder bounder(bm);
176 canvas->setBounder(&bounder);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177#endif
178#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000179 gEnableControlledThrow = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180#endif
181#ifdef SK_BUILD_FOR_WIN32
rmistry@google.comd6176b02012-08-23 18:14:13 +0000182 //try {
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000183 this->draw(canvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000184 //}
185 //catch (...) {
186 //}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187#else
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000188 this->draw(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189#endif
190#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000191 gEnableControlledThrow = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192#endif
193#ifdef TEST_BOUNDER
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000194 canvas->setBounder(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195#endif
196
197#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000198 GXEndDraw();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199#endif
200
rmistry@google.comd6176b02012-08-23 18:14:13 +0000201 return true;
202 }
203 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204}
205
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000206bool SkWindow::handleChar(SkUnichar uni) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000207 if (this->onHandleChar(uni))
208 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209
rmistry@google.comd6176b02012-08-23 18:14:13 +0000210 SkView* focus = this->getFocusView();
211 if (focus == NULL)
212 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213
rmistry@google.comd6176b02012-08-23 18:14:13 +0000214 SkEvent evt(SK_EventType_Unichar);
215 evt.setFast32(uni);
216 return focus->doEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217}
218
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000219bool SkWindow::handleKey(SkKey key) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000220 if (key == kNONE_SkKey)
221 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222
rmistry@google.comd6176b02012-08-23 18:14:13 +0000223 if (this->onHandleKey(key))
224 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225
rmistry@google.comd6176b02012-08-23 18:14:13 +0000226 // send an event to the focus-view
227 {
228 SkView* focus = this->getFocusView();
229 if (focus == NULL)
230 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231
rmistry@google.comd6176b02012-08-23 18:14:13 +0000232 SkEvent evt(SK_EventType_Key);
233 evt.setFast32(key);
234 if (focus->doEvent(evt))
235 return true;
236 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000238 if (key == kUp_SkKey || key == kDown_SkKey) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000239 if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL)
240 this->onSetFocusView(NULL);
241 return true;
242 }
243 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244}
245
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000246bool SkWindow::handleKeyUp(SkKey key) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 if (key == kNONE_SkKey)
248 return false;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000249
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 if (this->onHandleKeyUp(key))
251 return true;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000252
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 //send an event to the focus-view
254 {
255 SkView* focus = this->getFocusView();
256 if (focus == NULL)
257 focus = this;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000258
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259 //should this one be the same?
260 SkEvent evt(SK_EventType_KeyUp);
261 evt.setFast32(key);
262 if (focus->doEvent(evt))
263 return true;
264 }
265 return false;
266}
267
yangsu@google.com654d72f2011-08-01 17:27:33 +0000268void SkWindow::addMenu(SkOSMenu* menu) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000269 *fMenus.append() = menu;
270 this->onAddMenu(menu);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271}
272
reed@android.com0ae6b242008-12-23 16:49:54 +0000273void SkWindow::setTitle(const char title[]) {
274 if (NULL == title) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 title = "";
reed@android.com0ae6b242008-12-23 16:49:54 +0000276 }
277 fTitle.set(title);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 this->onSetTitle(title);
279}
280
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000281bool SkWindow::onEvent(const SkEvent& evt) {
282 if (evt.isType(SK_EventDelayInval)) {
283 for (SkRegion::Iterator iter(fDirtyRgn); !iter.done(); iter.next())
rmistry@google.comd6176b02012-08-23 18:14:13 +0000284 this->onHandleInval(iter.rect());
285 fWaitingOnInval = false;
286 return true;
287 }
288 return this->INHERITED::onEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289}
290
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000291bool SkWindow::onGetFocusView(SkView** focus) const {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000292 if (focus)
293 *focus = fFocusView;
294 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295}
296
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000297bool SkWindow::onSetFocusView(SkView* focus) {
298 if (fFocusView != focus) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000299 if (fFocusView)
300 fFocusView->onFocusChange(false);
301 fFocusView = focus;
302 if (focus)
303 focus->onFocusChange(true);
304 }
305 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306}
307
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000308void SkWindow::onHandleInval(const SkIRect&) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000309}
310
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000311bool SkWindow::onHandleChar(SkUnichar) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000312 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313}
314
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000315bool SkWindow::onHandleKey(SkKey) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000316 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317}
318
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000319bool SkWindow::onHandleKeyUp(SkKey) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320 return false;
321}
322
reed@google.com4d5c26d2013-01-08 16:17:50 +0000323bool SkWindow::handleClick(int x, int y, Click::State state, void *owner,
324 unsigned modifierKeys) {
325 return this->onDispatchClick(x, y, state, owner, modifierKeys);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000326}
327
Scroggod3aed392011-06-22 13:26:56 +0000328bool SkWindow::onDispatchClick(int x, int y, Click::State state,
reed@google.com4d5c26d2013-01-08 16:17:50 +0000329 void* owner, unsigned modifierKeys) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000330 bool handled = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331
Scroggod3aed392011-06-22 13:26:56 +0000332 // First, attempt to find an existing click with this owner.
333 int index = -1;
334 for (int i = 0; i < fClicks.count(); i++) {
335 if (owner == fClicks[i]->fOwner) {
336 index = i;
337 break;
338 }
339 }
340
rmistry@google.comd6176b02012-08-23 18:14:13 +0000341 switch (state) {
Scroggod3aed392011-06-22 13:26:56 +0000342 case Click::kDown_State: {
343 if (index != -1) {
344 delete fClicks[index];
345 fClicks.remove(index);
346 }
347 Click* click = this->findClickHandler(SkIntToScalar(x),
reed@google.com4d5c26d2013-01-08 16:17:50 +0000348 SkIntToScalar(y), modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000349
350 if (click) {
351 click->fOwner = owner;
352 *fClicks.append() = click;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000353 SkView::DoClickDown(click, x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000354 handled = true;
355 }
356 break;
357 }
358 case Click::kMoved_State:
359 if (index != -1) {
reed@google.com4d5c26d2013-01-08 16:17:50 +0000360 SkView::DoClickMoved(fClicks[index], x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000361 handled = true;
362 }
363 break;
364 case Click::kUp_State:
365 if (index != -1) {
reed@google.com4d5c26d2013-01-08 16:17:50 +0000366 SkView::DoClickUp(fClicks[index], x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000367 delete fClicks[index];
368 fClicks.remove(index);
369 handled = true;
370 }
371 break;
372 default:
373 // Do nothing
374 break;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000375 }
376 return handled;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377}