blob: 260ff5bc517fb152d29dcf8960e725ff91604738 [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@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{
rmistry@google.comd6176b02012-08-23 18:14:13 +000090 this->resize(fBitmap.width(), fBitmap.height(), config);
reed@android.com8a1c16f2008-12-17 15:59:43 +000091}
92
reed@android.com8a1c16f2008-12-17 15:59:43 +000093void SkWindow::resize(int width, int height, SkBitmap::Config config)
94{
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
rmistry@google.comd6176b02012-08-23 18:14:13 +000098 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
rmistry@google.comd6176b02012-08-23 18:14:13 +0000105 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{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000112 fBitmap.eraseARGB(a, r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113}
114
115void SkWindow::eraseRGB(U8CPU r, U8CPU g, U8CPU b)
116{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000117 fBitmap.eraseRGB(r, g, b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118}
119
reed@android.comf2b98d62010-12-20 18:26:13 +0000120bool SkWindow::handleInval(const SkRect* localR)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000122 SkIRect ir;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123
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,
rmistry@google.comd6176b02012-08-23 18:14:13 +0000134 SkScalarRound(this->width()),
135 SkScalarRound(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000136 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000137 fDirtyRgn.op(ir, SkRegion::kUnion_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138
rmistry@google.comd6176b02012-08-23 18:14:13 +0000139 this->onHandleInval(ir);
140 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141}
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)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000150 #include <windows.h>
151 #include <gx.h>
152 extern GXDisplayProperties gDisplayProps;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153#endif
154
155#ifdef SK_SIMULATE_FAILED_MALLOC
156extern bool gEnableControlledThrow;
157#endif
158
reed@google.com511aa0e2012-09-27 21:09:30 +0000159bool SkWindow::update(SkIRect* updateArea)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000161 if (!fDirtyRgn.isEmpty())
162 {
163 SkBitmap bm = this->getBitmap();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164
165#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000166 char* buffer = (char*)GXBeginDraw();
167 SkASSERT(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168
rmistry@google.comd6176b02012-08-23 18:14:13 +0000169 RECT rect;
170 GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect);
171 buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172
rmistry@google.comd6176b02012-08-23 18:14:13 +0000173 bm.setPixels(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174#endif
reed@google.com4c9e2aa2012-09-27 20:58:01 +0000175 SkCanvas rasterCanvas(bm);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176
reed@google.com4c9e2aa2012-09-27 20:58:01 +0000177 rasterCanvas.clipRegion(fDirtyRgn);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000178 if (updateArea)
179 *updateArea = fDirtyRgn.getBounds();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180
reed@google.com4c9e2aa2012-09-27 20:58:01 +0000181 SkAutoCanvasRestore acr(&rasterCanvas, true);
182 rasterCanvas.concat(fMatrix);
reed@android.comf2b98d62010-12-20 18:26:13 +0000183
rmistry@google.comd6176b02012-08-23 18:14:13 +0000184 // empty this now, so we can correctly record any inval calls that
185 // might be made during the draw call.
186 fDirtyRgn.setEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187
188#ifdef TEST_BOUNDER
rmistry@google.comd6176b02012-08-23 18:14:13 +0000189 test_bounder b(bm);
reed@google.com4c9e2aa2012-09-27 20:58:01 +0000190 rasterCanvas.setBounder(&b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191#endif
192#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000193 gEnableControlledThrow = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194#endif
195#ifdef SK_BUILD_FOR_WIN32
rmistry@google.comd6176b02012-08-23 18:14:13 +0000196 //try {
197 this->draw(canvas);
198 //}
199 //catch (...) {
200 //}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201#else
reed@google.com4c9e2aa2012-09-27 20:58:01 +0000202 this->draw(&rasterCanvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203#endif
204#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000205 gEnableControlledThrow = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206#endif
207#ifdef TEST_BOUNDER
reed@google.com4c9e2aa2012-09-27 20:58:01 +0000208 rasterCanvas.setBounder(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209#endif
210
211#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000212 GXEndDraw();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213#endif
214
rmistry@google.comd6176b02012-08-23 18:14:13 +0000215 return true;
216 }
217 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218}
219
220bool SkWindow::handleChar(SkUnichar uni)
221{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000222 if (this->onHandleChar(uni))
223 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224
rmistry@google.comd6176b02012-08-23 18:14:13 +0000225 SkView* focus = this->getFocusView();
226 if (focus == NULL)
227 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228
rmistry@google.comd6176b02012-08-23 18:14:13 +0000229 SkEvent evt(SK_EventType_Unichar);
230 evt.setFast32(uni);
231 return focus->doEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232}
233
234bool SkWindow::handleKey(SkKey key)
235{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000236 if (key == kNONE_SkKey)
237 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
rmistry@google.comd6176b02012-08-23 18:14:13 +0000239 if (this->onHandleKey(key))
240 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241
rmistry@google.comd6176b02012-08-23 18:14:13 +0000242 // send an event to the focus-view
243 {
244 SkView* focus = this->getFocusView();
245 if (focus == NULL)
246 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247
rmistry@google.comd6176b02012-08-23 18:14:13 +0000248 SkEvent evt(SK_EventType_Key);
249 evt.setFast32(key);
250 if (focus->doEvent(evt))
251 return true;
252 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253
rmistry@google.comd6176b02012-08-23 18:14:13 +0000254 if (key == kUp_SkKey || key == kDown_SkKey)
255 {
256 if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL)
257 this->onSetFocusView(NULL);
258 return true;
259 }
260 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261}
262
263bool SkWindow::handleKeyUp(SkKey key)
264{
265 if (key == kNONE_SkKey)
266 return false;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000267
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 if (this->onHandleKeyUp(key))
269 return true;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 //send an event to the focus-view
272 {
273 SkView* focus = this->getFocusView();
274 if (focus == NULL)
275 focus = this;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000276
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 //should this one be the same?
278 SkEvent evt(SK_EventType_KeyUp);
279 evt.setFast32(key);
280 if (focus->doEvent(evt))
281 return true;
282 }
283 return false;
284}
285
yangsu@google.com654d72f2011-08-01 17:27:33 +0000286void SkWindow::addMenu(SkOSMenu* menu) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000287 *fMenus.append() = menu;
288 this->onAddMenu(menu);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289}
290
reed@android.com0ae6b242008-12-23 16:49:54 +0000291void SkWindow::setTitle(const char title[]) {
292 if (NULL == title) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 title = "";
reed@android.com0ae6b242008-12-23 16:49:54 +0000294 }
295 fTitle.set(title);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 this->onSetTitle(title);
297}
298
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299//////////////////////////////////////////////////////////////////////
300
301bool SkWindow::onEvent(const SkEvent& evt)
302{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000303 if (evt.isType(SK_EventDelayInval))
304 {
305 SkRegion::Iterator iter(fDirtyRgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306
rmistry@google.comd6176b02012-08-23 18:14:13 +0000307 for (; !iter.done(); iter.next())
308 this->onHandleInval(iter.rect());
309 fWaitingOnInval = false;
310 return true;
311 }
312 return this->INHERITED::onEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313}
314
315bool SkWindow::onGetFocusView(SkView** focus) const
316{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000317 if (focus)
318 *focus = fFocusView;
319 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320}
321
322bool SkWindow::onSetFocusView(SkView* focus)
323{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000324 if (fFocusView != focus)
325 {
326 if (fFocusView)
327 fFocusView->onFocusChange(false);
328 fFocusView = focus;
329 if (focus)
330 focus->onFocusChange(true);
331 }
332 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333}
334
335//////////////////////////////////////////////////////////////////////
336
337void SkWindow::onHandleInval(const SkIRect&)
338{
339}
340
341bool SkWindow::onHandleChar(SkUnichar)
342{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000343 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344}
345
346bool SkWindow::onHandleKey(SkKey key)
347{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000348 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349}
350
351bool SkWindow::onHandleKeyUp(SkKey key)
352{
353 return false;
354}
355
Scroggod3aed392011-06-22 13:26:56 +0000356bool SkWindow::handleClick(int x, int y, Click::State state, void *owner) {
357 return this->onDispatchClick(x, y, state, owner);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000358}
359
Scroggod3aed392011-06-22 13:26:56 +0000360bool SkWindow::onDispatchClick(int x, int y, Click::State state,
361 void* owner) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000362 bool handled = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363
Scroggod3aed392011-06-22 13:26:56 +0000364 // First, attempt to find an existing click with this owner.
365 int index = -1;
366 for (int i = 0; i < fClicks.count(); i++) {
367 if (owner == fClicks[i]->fOwner) {
368 index = i;
369 break;
370 }
371 }
372
rmistry@google.comd6176b02012-08-23 18:14:13 +0000373 switch (state) {
Scroggod3aed392011-06-22 13:26:56 +0000374 case Click::kDown_State: {
375 if (index != -1) {
376 delete fClicks[index];
377 fClicks.remove(index);
378 }
379 Click* click = this->findClickHandler(SkIntToScalar(x),
380 SkIntToScalar(y));
381
382 if (click) {
383 click->fOwner = owner;
384 *fClicks.append() = click;
385 SkView::DoClickDown(click, x, y);
386 handled = true;
387 }
388 break;
389 }
390 case Click::kMoved_State:
391 if (index != -1) {
392 SkView::DoClickMoved(fClicks[index], x, y);
393 handled = true;
394 }
395 break;
396 case Click::kUp_State:
397 if (index != -1) {
398 SkView::DoClickUp(fClicks[index], x, y);
399 delete fClicks[index];
400 fClicks.remove(index);
401 handled = true;
402 }
403 break;
404 default:
405 // Do nothing
406 break;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000407 }
408 return handled;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409}
410