blob: f6054dfe5464febc10b6974460d32606822db50b [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:
22 test_bounder(const SkBitmap& bm) : fCanvas(bm) {}
23protected:
24 virtual bool onIRect(const SkIRect& r)
25 {
26 SkRect rr;
27
28 rr.set(SkIntToScalar(r.fLeft), SkIntToScalar(r.fTop),
29 SkIntToScalar(r.fRight), SkIntToScalar(r.fBottom));
30
31 SkPaint p;
32
33 p.setStyle(SkPaint::kStroke_Style);
34 p.setColor(SK_ColorYELLOW);
35
36#if 0
37 rr.inset(SK_ScalarHalf, SK_ScalarHalf);
38#else
39 rr.inset(-SK_ScalarHalf, -SK_ScalarHalf);
40#endif
41
42 fCanvas.drawRect(rr, p);
43 return true;
44 }
45private:
46 SkCanvas fCanvas;
47};
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@android.comf2b98d62010-12-20 18:26:13 +000069void SkWindow::setMatrix(const SkMatrix& matrix) {
70 if (fMatrix != matrix) {
71 fMatrix = matrix;
72 this->inval(NULL);
73 }
74}
75
76void SkWindow::preConcat(const SkMatrix& matrix) {
77 SkMatrix m;
78 m.setConcat(fMatrix, matrix);
79 this->setMatrix(m);
80}
81
82void SkWindow::postConcat(const SkMatrix& matrix) {
83 SkMatrix m;
84 m.setConcat(matrix, fMatrix);
85 this->setMatrix(m);
86}
87
reed@android.com8a1c16f2008-12-17 15:59:43 +000088void SkWindow::setConfig(SkBitmap::Config config)
89{
90 this->resize(fBitmap.width(), fBitmap.height(), config);
91}
92
reed@android.com8a1c16f2008-12-17 15:59:43 +000093void SkWindow::resize(int width, int height, SkBitmap::Config config)
94{
95 if (config == SkBitmap::kNo_Config)
96 config = fConfig;
97
98 if (width != fBitmap.width() || height != fBitmap.height() || config != fConfig)
99 {
100 fConfig = config;
101 fBitmap.setConfig(config, width, height);
102 fBitmap.allocPixels();
reed@android.comf2b98d62010-12-20 18:26:13 +0000103 fBitmap.setIsOpaque(true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104
105 this->setSize(SkIntToScalar(width), SkIntToScalar(height));
106 this->inval(NULL);
107 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108}
109
110void SkWindow::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
111{
112 fBitmap.eraseARGB(a, r, g, b);
113}
114
115void SkWindow::eraseRGB(U8CPU r, U8CPU g, U8CPU b)
116{
117 fBitmap.eraseRGB(r, g, b);
118}
119
reed@android.comf2b98d62010-12-20 18:26:13 +0000120bool SkWindow::handleInval(const SkRect* localR)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121{
122 SkIRect ir;
123
reed@android.comf2b98d62010-12-20 18:26:13 +0000124 if (localR) {
125 SkRect devR;
126 SkMatrix inverse;
127 if (!fMatrix.invert(&inverse)) {
128 return false;
129 }
130 fMatrix.mapRect(&devR, *localR);
131 devR.round(&ir);
132 } else {
reed@google.comf9bb7a82011-03-01 15:15:13 +0000133 ir.set(0, 0,
134 SkScalarRound(this->width()),
135 SkScalarRound(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000136 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 fDirtyRgn.op(ir, SkRegion::kUnion_Op);
138
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139 this->onHandleInval(ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 return true;
141}
142
reed@android.comf2b98d62010-12-20 18:26:13 +0000143void SkWindow::forceInvalAll() {
reed@google.com261b8e22011-04-14 17:53:24 +0000144 fDirtyRgn.setRect(0, 0,
145 SkScalarCeil(this->width()),
146 SkScalarCeil(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000147}
148
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
150 #include <windows.h>
151 #include <gx.h>
152 extern GXDisplayProperties gDisplayProps;
153#endif
154
155#ifdef SK_SIMULATE_FAILED_MALLOC
156extern bool gEnableControlledThrow;
157#endif
158
reed@android.comf2b98d62010-12-20 18:26:13 +0000159bool SkWindow::update(SkIRect* updateArea, SkCanvas* canvas)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160{
161 if (!fDirtyRgn.isEmpty())
162 {
163 SkBitmap bm = this->getBitmap();
164
165#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
166 char* buffer = (char*)GXBeginDraw();
167 SkASSERT(buffer);
168
169 RECT rect;
170 GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect);
171 buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch;
172
173 bm.setPixels(buffer);
174#endif
175
reed@android.comf2b98d62010-12-20 18:26:13 +0000176 SkCanvas rasterCanvas;
177 SkDevice* device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
reed@android.comf2b98d62010-12-20 18:26:13 +0000179 if (NULL == canvas) {
180 canvas = &rasterCanvas;
reed@android.comf2b98d62010-12-20 18:26:13 +0000181 }
reed@google.comaf951c92011-06-16 19:10:39 +0000182 canvas->setBitmapDevice(bm);
reed@android.comf2b98d62010-12-20 18:26:13 +0000183
184 canvas->clipRegion(fDirtyRgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 if (updateArea)
186 *updateArea = fDirtyRgn.getBounds();
187
reed@android.comf2b98d62010-12-20 18:26:13 +0000188 SkAutoCanvasRestore acr(canvas, true);
189 canvas->concat(fMatrix);
190
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 // empty this now, so we can correctly record any inval calls that
192 // might be made during the draw call.
193 fDirtyRgn.setEmpty();
194
195#ifdef TEST_BOUNDER
196 test_bounder b(bm);
reed@android.comf2b98d62010-12-20 18:26:13 +0000197 canvas->setBounder(&b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198#endif
199#ifdef SK_SIMULATE_FAILED_MALLOC
200 gEnableControlledThrow = true;
201#endif
202#ifdef SK_BUILD_FOR_WIN32
reed@android.comf2b98d62010-12-20 18:26:13 +0000203 //try {
204 this->draw(canvas);
205 //}
206 //catch (...) {
207 //}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208#else
reed@android.comf2b98d62010-12-20 18:26:13 +0000209 this->draw(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210#endif
211#ifdef SK_SIMULATE_FAILED_MALLOC
212 gEnableControlledThrow = false;
213#endif
214#ifdef TEST_BOUNDER
reed@android.comf2b98d62010-12-20 18:26:13 +0000215 canvas->setBounder(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216#endif
217
218#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
219 GXEndDraw();
220#endif
221
222 return true;
223 }
224 return false;
225}
226
227bool SkWindow::handleChar(SkUnichar uni)
228{
229 if (this->onHandleChar(uni))
230 return true;
231
232 SkView* focus = this->getFocusView();
233 if (focus == NULL)
234 focus = this;
235
236 SkEvent evt(SK_EventType_Unichar);
237 evt.setFast32(uni);
238 return focus->doEvent(evt);
239}
240
241bool SkWindow::handleKey(SkKey key)
242{
243 if (key == kNONE_SkKey)
244 return false;
245
246 if (this->onHandleKey(key))
247 return true;
248
249 // send an event to the focus-view
250 {
251 SkView* focus = this->getFocusView();
252 if (focus == NULL)
253 focus = this;
254
255 SkEvent evt(SK_EventType_Key);
256 evt.setFast32(key);
257 if (focus->doEvent(evt))
258 return true;
259 }
260
261 if (key == kUp_SkKey || key == kDown_SkKey)
262 {
263 if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL)
264 this->onSetFocusView(NULL);
265 return true;
266 }
267 return false;
268}
269
270bool SkWindow::handleKeyUp(SkKey key)
271{
272 if (key == kNONE_SkKey)
273 return false;
274
275 if (this->onHandleKeyUp(key))
276 return true;
277
278 //send an event to the focus-view
279 {
280 SkView* focus = this->getFocusView();
281 if (focus == NULL)
282 focus = this;
283
284 //should this one be the same?
285 SkEvent evt(SK_EventType_KeyUp);
286 evt.setFast32(key);
287 if (focus->doEvent(evt))
288 return true;
289 }
290 return false;
291}
292
yangsu@google.com654d72f2011-08-01 17:27:33 +0000293void SkWindow::addMenu(SkOSMenu* menu) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 *fMenus.append() = menu;
295 this->onAddMenu(menu);
296}
297
reed@android.com0ae6b242008-12-23 16:49:54 +0000298void SkWindow::setTitle(const char title[]) {
299 if (NULL == title) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300 title = "";
reed@android.com0ae6b242008-12-23 16:49:54 +0000301 }
302 fTitle.set(title);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303 this->onSetTitle(title);
304}
305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306//////////////////////////////////////////////////////////////////////
307
308bool SkWindow::onEvent(const SkEvent& evt)
309{
310 if (evt.isType(SK_EventDelayInval))
311 {
312 SkRegion::Iterator iter(fDirtyRgn);
313
314 for (; !iter.done(); iter.next())
315 this->onHandleInval(iter.rect());
316 fWaitingOnInval = false;
317 return true;
318 }
319 return this->INHERITED::onEvent(evt);
320}
321
322bool SkWindow::onGetFocusView(SkView** focus) const
323{
324 if (focus)
325 *focus = fFocusView;
326 return true;
327}
328
329bool SkWindow::onSetFocusView(SkView* focus)
330{
331 if (fFocusView != focus)
332 {
333 if (fFocusView)
334 fFocusView->onFocusChange(false);
335 fFocusView = focus;
336 if (focus)
337 focus->onFocusChange(true);
338 }
339 return true;
340}
341
342//////////////////////////////////////////////////////////////////////
343
344void SkWindow::onHandleInval(const SkIRect&)
345{
346}
347
348bool SkWindow::onHandleChar(SkUnichar)
349{
350 return false;
351}
352
353bool SkWindow::onHandleKey(SkKey key)
354{
355 return false;
356}
357
358bool SkWindow::onHandleKeyUp(SkKey key)
359{
360 return false;
361}
362
Scroggod3aed392011-06-22 13:26:56 +0000363bool SkWindow::handleClick(int x, int y, Click::State state, void *owner) {
364 return this->onDispatchClick(x, y, state, owner);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000365}
366
Scroggod3aed392011-06-22 13:26:56 +0000367bool SkWindow::onDispatchClick(int x, int y, Click::State state,
368 void* owner) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 bool handled = false;
370
Scroggod3aed392011-06-22 13:26:56 +0000371 // First, attempt to find an existing click with this owner.
372 int index = -1;
373 for (int i = 0; i < fClicks.count(); i++) {
374 if (owner == fClicks[i]->fOwner) {
375 index = i;
376 break;
377 }
378 }
379
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 switch (state) {
Scroggod3aed392011-06-22 13:26:56 +0000381 case Click::kDown_State: {
382 if (index != -1) {
383 delete fClicks[index];
384 fClicks.remove(index);
385 }
386 Click* click = this->findClickHandler(SkIntToScalar(x),
387 SkIntToScalar(y));
388
389 if (click) {
390 click->fOwner = owner;
391 *fClicks.append() = click;
392 SkView::DoClickDown(click, x, y);
393 handled = true;
394 }
395 break;
396 }
397 case Click::kMoved_State:
398 if (index != -1) {
399 SkView::DoClickMoved(fClicks[index], x, y);
400 handled = true;
401 }
402 break;
403 case Click::kUp_State:
404 if (index != -1) {
405 SkView::DoClickUp(fClicks[index], x, y);
406 delete fClicks[index];
407 fClicks.remove(index);
408 handled = true;
409 }
410 break;
411 default:
412 // Do nothing
413 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414 }
415 return handled;
416}
417