blob: d6fe32bd8884cf8ff95a3c9673461493562bd95f [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"
20class test_bounder : public SkBounder {
21public:
rmistry@google.comd6176b02012-08-23 18:14:13 +000022 test_bounder(const SkBitmap& bm) : fCanvas(bm) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000023protected:
rmistry@google.comd6176b02012-08-23 18:14:13 +000024 virtual bool onIRect(const SkIRect& r)
25 {
26 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
49SkWindow::SkWindow() : fFocusView(NULL)
50{
Scroggod3aed392011-06-22 13:26:56 +000051 fClicks.reset();
52 fWaitingOnInval = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +000053
54#ifdef SK_BUILD_FOR_WINCE
Scroggod3aed392011-06-22 13:26:56 +000055 fConfig = SkBitmap::kRGB_565_Config;
reed@android.com8a1c16f2008-12-17 15:59:43 +000056#else
Scroggod3aed392011-06-22 13:26:56 +000057 fConfig = SkBitmap::kARGB_8888_Config;
reed@android.com8a1c16f2008-12-17 15:59:43 +000058#endif
reed@android.comf2b98d62010-12-20 18:26:13 +000059
60 fMatrix.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +000061}
62
63SkWindow::~SkWindow()
64{
Scroggod3aed392011-06-22 13:26:56 +000065 fClicks.deleteAll();
66 fMenus.deleteAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000067}
68
reed@google.com5957f472012-10-01 20:31:56 +000069SkCanvas* SkWindow::createCanvas() {
70 return new SkCanvas(this->getBitmap());
71}
72
reed@android.comf2b98d62010-12-20 18:26:13 +000073void SkWindow::setMatrix(const SkMatrix& matrix) {
74 if (fMatrix != matrix) {
75 fMatrix = matrix;
76 this->inval(NULL);
77 }
78}
79
80void SkWindow::preConcat(const SkMatrix& matrix) {
81 SkMatrix m;
82 m.setConcat(fMatrix, matrix);
83 this->setMatrix(m);
84}
85
86void SkWindow::postConcat(const SkMatrix& matrix) {
87 SkMatrix m;
88 m.setConcat(matrix, fMatrix);
89 this->setMatrix(m);
90}
91
reed@android.com8a1c16f2008-12-17 15:59:43 +000092void SkWindow::setConfig(SkBitmap::Config config)
93{
rmistry@google.comd6176b02012-08-23 18:14:13 +000094 this->resize(fBitmap.width(), fBitmap.height(), config);
reed@android.com8a1c16f2008-12-17 15:59:43 +000095}
96
reed@android.com8a1c16f2008-12-17 15:59:43 +000097void SkWindow::resize(int width, int height, SkBitmap::Config config)
98{
rmistry@google.comd6176b02012-08-23 18:14:13 +000099 if (config == SkBitmap::kNo_Config)
100 config = fConfig;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101
rmistry@google.comd6176b02012-08-23 18:14:13 +0000102 if (width != fBitmap.width() || height != fBitmap.height() || config != fConfig)
103 {
104 fConfig = config;
reed@google.com383a6972013-10-21 14:00:07 +0000105 fBitmap.setConfig(config, width, height, 0, kOpaque_SkAlphaType);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000106 fBitmap.allocPixels();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107
rmistry@google.comd6176b02012-08-23 18:14:13 +0000108 this->setSize(SkIntToScalar(width), SkIntToScalar(height));
109 this->inval(NULL);
110 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111}
112
113void SkWindow::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
114{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000115 fBitmap.eraseARGB(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116}
117
118void SkWindow::eraseRGB(U8CPU r, U8CPU g, U8CPU b)
119{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000120 fBitmap.eraseRGB(r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121}
122
reed@android.comf2b98d62010-12-20 18:26:13 +0000123bool SkWindow::handleInval(const SkRect* localR)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000125 SkIRect ir;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126
reed@android.comf2b98d62010-12-20 18:26:13 +0000127 if (localR) {
128 SkRect devR;
129 SkMatrix inverse;
130 if (!fMatrix.invert(&inverse)) {
131 return false;
132 }
133 fMatrix.mapRect(&devR, *localR);
134 devR.round(&ir);
135 } else {
reed@google.comf9bb7a82011-03-01 15:15:13 +0000136 ir.set(0, 0,
rmistry@google.comd6176b02012-08-23 18:14:13 +0000137 SkScalarRound(this->width()),
138 SkScalarRound(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000139 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000140 fDirtyRgn.op(ir, SkRegion::kUnion_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141
rmistry@google.comd6176b02012-08-23 18:14:13 +0000142 this->onHandleInval(ir);
143 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144}
145
reed@android.comf2b98d62010-12-20 18:26:13 +0000146void SkWindow::forceInvalAll() {
reed@google.com261b8e22011-04-14 17:53:24 +0000147 fDirtyRgn.setRect(0, 0,
148 SkScalarCeil(this->width()),
149 SkScalarCeil(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000150}
151
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000153 #include <windows.h>
154 #include <gx.h>
155 extern GXDisplayProperties gDisplayProps;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156#endif
157
158#ifdef SK_SIMULATE_FAILED_MALLOC
159extern bool gEnableControlledThrow;
160#endif
161
reed@google.com511aa0e2012-09-27 21:09:30 +0000162bool SkWindow::update(SkIRect* updateArea)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000164 if (!fDirtyRgn.isEmpty())
165 {
166 SkBitmap bm = this->getBitmap();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167
168#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000169 char* buffer = (char*)GXBeginDraw();
170 SkASSERT(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171
rmistry@google.comd6176b02012-08-23 18:14:13 +0000172 RECT rect;
173 GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect);
174 buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
rmistry@google.comd6176b02012-08-23 18:14:13 +0000176 bm.setPixels(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177#endif
178
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000179 SkAutoTUnref<SkCanvas> canvas(this->createCanvas());
180
181 canvas->clipRegion(fDirtyRgn);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000182 if (updateArea)
183 *updateArea = fDirtyRgn.getBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000185 SkAutoCanvasRestore acr(canvas, true);
186 canvas->concat(fMatrix);
reed@android.comf2b98d62010-12-20 18:26:13 +0000187
rmistry@google.comd6176b02012-08-23 18:14:13 +0000188 // empty this now, so we can correctly record any inval calls that
189 // might be made during the draw call.
190 fDirtyRgn.setEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191
192#ifdef TEST_BOUNDER
rmistry@google.comd6176b02012-08-23 18:14:13 +0000193 test_bounder b(bm);
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000194 canvas->setBounder(&b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195#endif
196#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000197 gEnableControlledThrow = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198#endif
199#ifdef SK_BUILD_FOR_WIN32
rmistry@google.comd6176b02012-08-23 18:14:13 +0000200 //try {
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000201 this->draw(canvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000202 //}
203 //catch (...) {
204 //}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205#else
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000206 this->draw(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207#endif
208#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000209 gEnableControlledThrow = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210#endif
211#ifdef TEST_BOUNDER
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000212 canvas->setBounder(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213#endif
214
215#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000216 GXEndDraw();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217#endif
218
rmistry@google.comd6176b02012-08-23 18:14:13 +0000219 return true;
220 }
221 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222}
223
224bool SkWindow::handleChar(SkUnichar uni)
225{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000226 if (this->onHandleChar(uni))
227 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228
rmistry@google.comd6176b02012-08-23 18:14:13 +0000229 SkView* focus = this->getFocusView();
230 if (focus == NULL)
231 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232
rmistry@google.comd6176b02012-08-23 18:14:13 +0000233 SkEvent evt(SK_EventType_Unichar);
234 evt.setFast32(uni);
235 return focus->doEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236}
237
238bool SkWindow::handleKey(SkKey key)
239{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000240 if (key == kNONE_SkKey)
241 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242
rmistry@google.comd6176b02012-08-23 18:14:13 +0000243 if (this->onHandleKey(key))
244 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245
rmistry@google.comd6176b02012-08-23 18:14:13 +0000246 // send an event to the focus-view
247 {
248 SkView* focus = this->getFocusView();
249 if (focus == NULL)
250 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251
rmistry@google.comd6176b02012-08-23 18:14:13 +0000252 SkEvent evt(SK_EventType_Key);
253 evt.setFast32(key);
254 if (focus->doEvent(evt))
255 return true;
256 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257
rmistry@google.comd6176b02012-08-23 18:14:13 +0000258 if (key == kUp_SkKey || key == kDown_SkKey)
259 {
260 if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL)
261 this->onSetFocusView(NULL);
262 return true;
263 }
264 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265}
266
267bool SkWindow::handleKeyUp(SkKey key)
268{
269 if (key == kNONE_SkKey)
270 return false;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000271
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 if (this->onHandleKeyUp(key))
273 return true;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000274
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 //send an event to the focus-view
276 {
277 SkView* focus = this->getFocusView();
278 if (focus == NULL)
279 focus = this;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000280
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 //should this one be the same?
282 SkEvent evt(SK_EventType_KeyUp);
283 evt.setFast32(key);
284 if (focus->doEvent(evt))
285 return true;
286 }
287 return false;
288}
289
yangsu@google.com654d72f2011-08-01 17:27:33 +0000290void SkWindow::addMenu(SkOSMenu* menu) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000291 *fMenus.append() = menu;
292 this->onAddMenu(menu);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293}
294
reed@android.com0ae6b242008-12-23 16:49:54 +0000295void SkWindow::setTitle(const char title[]) {
296 if (NULL == title) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 title = "";
reed@android.com0ae6b242008-12-23 16:49:54 +0000298 }
299 fTitle.set(title);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300 this->onSetTitle(title);
301}
302
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303//////////////////////////////////////////////////////////////////////
304
305bool SkWindow::onEvent(const SkEvent& evt)
306{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000307 if (evt.isType(SK_EventDelayInval))
308 {
309 SkRegion::Iterator iter(fDirtyRgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310
rmistry@google.comd6176b02012-08-23 18:14:13 +0000311 for (; !iter.done(); iter.next())
312 this->onHandleInval(iter.rect());
313 fWaitingOnInval = false;
314 return true;
315 }
316 return this->INHERITED::onEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317}
318
319bool SkWindow::onGetFocusView(SkView** focus) const
320{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000321 if (focus)
322 *focus = fFocusView;
323 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324}
325
326bool SkWindow::onSetFocusView(SkView* focus)
327{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000328 if (fFocusView != focus)
329 {
330 if (fFocusView)
331 fFocusView->onFocusChange(false);
332 fFocusView = focus;
333 if (focus)
334 focus->onFocusChange(true);
335 }
336 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337}
338
339//////////////////////////////////////////////////////////////////////
340
341void SkWindow::onHandleInval(const SkIRect&)
342{
343}
344
345bool SkWindow::onHandleChar(SkUnichar)
346{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000347 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348}
349
sugoi@google.com93c7ee32013-03-12 14:36:57 +0000350bool SkWindow::onHandleKey(SkKey)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000352 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353}
354
sugoi@google.com93c7ee32013-03-12 14:36:57 +0000355bool SkWindow::onHandleKeyUp(SkKey)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356{
357 return false;
358}
359
reed@google.com4d5c26d2013-01-08 16:17:50 +0000360bool SkWindow::handleClick(int x, int y, Click::State state, void *owner,
361 unsigned modifierKeys) {
362 return this->onDispatchClick(x, y, state, owner, modifierKeys);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000363}
364
Scroggod3aed392011-06-22 13:26:56 +0000365bool SkWindow::onDispatchClick(int x, int y, Click::State state,
reed@google.com4d5c26d2013-01-08 16:17:50 +0000366 void* owner, unsigned modifierKeys) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000367 bool handled = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368
Scroggod3aed392011-06-22 13:26:56 +0000369 // First, attempt to find an existing click with this owner.
370 int index = -1;
371 for (int i = 0; i < fClicks.count(); i++) {
372 if (owner == fClicks[i]->fOwner) {
373 index = i;
374 break;
375 }
376 }
377
rmistry@google.comd6176b02012-08-23 18:14:13 +0000378 switch (state) {
Scroggod3aed392011-06-22 13:26:56 +0000379 case Click::kDown_State: {
380 if (index != -1) {
381 delete fClicks[index];
382 fClicks.remove(index);
383 }
384 Click* click = this->findClickHandler(SkIntToScalar(x),
reed@google.com4d5c26d2013-01-08 16:17:50 +0000385 SkIntToScalar(y), modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000386
387 if (click) {
388 click->fOwner = owner;
389 *fClicks.append() = click;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000390 SkView::DoClickDown(click, x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000391 handled = true;
392 }
393 break;
394 }
395 case Click::kMoved_State:
396 if (index != -1) {
reed@google.com4d5c26d2013-01-08 16:17:50 +0000397 SkView::DoClickMoved(fClicks[index], x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000398 handled = true;
399 }
400 break;
401 case Click::kUp_State:
402 if (index != -1) {
reed@google.com4d5c26d2013-01-08 16:17:50 +0000403 SkView::DoClickUp(fClicks[index], x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000404 delete fClicks[index];
405 fClicks.remove(index);
406 handled = true;
407 }
408 break;
409 default:
410 // Do nothing
411 break;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000412 }
413 return handled;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414}