blob: ef3264f6d29676223bd67a66b79d92a09203e3ef [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
293void SkWindow::addMenu(SkOSMenu* menu)
294{
295 *fMenus.append() = menu;
296 this->onAddMenu(menu);
297}
298
reed@android.com0ae6b242008-12-23 16:49:54 +0000299void SkWindow::setTitle(const char title[]) {
300 if (NULL == title) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 title = "";
reed@android.com0ae6b242008-12-23 16:49:54 +0000302 }
303 fTitle.set(title);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 this->onSetTitle(title);
305}
306
307bool SkWindow::handleMenu(uint32_t cmd)
308{
309 for (int i = 0; i < fMenus.count(); i++)
310 {
311 SkEvent* evt = fMenus[i]->createEvent(cmd);
312 if (evt)
313 {
314 evt->post(this->getSinkID());
315 return true;
316 }
317 }
318 return false;
319}
320
321//////////////////////////////////////////////////////////////////////
322
323bool SkWindow::onEvent(const SkEvent& evt)
324{
325 if (evt.isType(SK_EventDelayInval))
326 {
327 SkRegion::Iterator iter(fDirtyRgn);
328
329 for (; !iter.done(); iter.next())
330 this->onHandleInval(iter.rect());
331 fWaitingOnInval = false;
332 return true;
333 }
334 return this->INHERITED::onEvent(evt);
335}
336
337bool SkWindow::onGetFocusView(SkView** focus) const
338{
339 if (focus)
340 *focus = fFocusView;
341 return true;
342}
343
344bool SkWindow::onSetFocusView(SkView* focus)
345{
346 if (fFocusView != focus)
347 {
348 if (fFocusView)
349 fFocusView->onFocusChange(false);
350 fFocusView = focus;
351 if (focus)
352 focus->onFocusChange(true);
353 }
354 return true;
355}
356
357//////////////////////////////////////////////////////////////////////
358
359void SkWindow::onHandleInval(const SkIRect&)
360{
361}
362
363bool SkWindow::onHandleChar(SkUnichar)
364{
365 return false;
366}
367
368bool SkWindow::onHandleKey(SkKey key)
369{
370 return false;
371}
372
373bool SkWindow::onHandleKeyUp(SkKey key)
374{
375 return false;
376}
377
Scroggod3aed392011-06-22 13:26:56 +0000378bool SkWindow::handleClick(int x, int y, Click::State state, void *owner) {
379 return this->onDispatchClick(x, y, state, owner);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000380}
381
Scroggod3aed392011-06-22 13:26:56 +0000382bool SkWindow::onDispatchClick(int x, int y, Click::State state,
383 void* owner) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 bool handled = false;
385
Scroggod3aed392011-06-22 13:26:56 +0000386 // First, attempt to find an existing click with this owner.
387 int index = -1;
388 for (int i = 0; i < fClicks.count(); i++) {
389 if (owner == fClicks[i]->fOwner) {
390 index = i;
391 break;
392 }
393 }
394
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395 switch (state) {
Scroggod3aed392011-06-22 13:26:56 +0000396 case Click::kDown_State: {
397 if (index != -1) {
398 delete fClicks[index];
399 fClicks.remove(index);
400 }
401 Click* click = this->findClickHandler(SkIntToScalar(x),
402 SkIntToScalar(y));
403
404 if (click) {
405 click->fOwner = owner;
406 *fClicks.append() = click;
407 SkView::DoClickDown(click, x, y);
408 handled = true;
409 }
410 break;
411 }
412 case Click::kMoved_State:
413 if (index != -1) {
414 SkView::DoClickMoved(fClicks[index], x, y);
415 handled = true;
416 }
417 break;
418 case Click::kUp_State:
419 if (index != -1) {
420 SkView::DoClickUp(fClicks[index], x, y);
421 delete fClicks[index];
422 fClicks.remove(index);
423 handled = true;
424 }
425 break;
426 default:
427 // Do nothing
428 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 }
430 return handled;
431}
432