blob: b35f6f26d88769f04a5634f959cb2e3c3b6d324b [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkWindow.h"
2#include "SkCanvas.h"
reed@android.comf2b98d62010-12-20 18:26:13 +00003#include "SkDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00004#include "SkOSMenu.h"
5#include "SkSystemEventTypes.h"
6#include "SkTime.h"
7
8#define SK_EventDelayInval "\xd" "n" "\xa" "l"
9
10#define TEST_BOUNDERx
11
12#include "SkBounder.h"
13class test_bounder : public SkBounder {
14public:
15 test_bounder(const SkBitmap& bm) : fCanvas(bm) {}
16protected:
17 virtual bool onIRect(const SkIRect& r)
18 {
19 SkRect rr;
20
21 rr.set(SkIntToScalar(r.fLeft), SkIntToScalar(r.fTop),
22 SkIntToScalar(r.fRight), SkIntToScalar(r.fBottom));
23
24 SkPaint p;
25
26 p.setStyle(SkPaint::kStroke_Style);
27 p.setColor(SK_ColorYELLOW);
28
29#if 0
30 rr.inset(SK_ScalarHalf, SK_ScalarHalf);
31#else
32 rr.inset(-SK_ScalarHalf, -SK_ScalarHalf);
33#endif
34
35 fCanvas.drawRect(rr, p);
36 return true;
37 }
38private:
39 SkCanvas fCanvas;
40};
41
42SkWindow::SkWindow() : fFocusView(NULL)
43{
Scroggod3aed392011-06-22 13:26:56 +000044 fClicks.reset();
45 fWaitingOnInval = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +000046
47#ifdef SK_BUILD_FOR_WINCE
Scroggod3aed392011-06-22 13:26:56 +000048 fConfig = SkBitmap::kRGB_565_Config;
reed@android.com8a1c16f2008-12-17 15:59:43 +000049#else
Scroggod3aed392011-06-22 13:26:56 +000050 fConfig = SkBitmap::kARGB_8888_Config;
reed@android.com8a1c16f2008-12-17 15:59:43 +000051#endif
reed@android.comf2b98d62010-12-20 18:26:13 +000052
53 fMatrix.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +000054}
55
56SkWindow::~SkWindow()
57{
Scroggod3aed392011-06-22 13:26:56 +000058 fClicks.deleteAll();
59 fMenus.deleteAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000060}
61
reed@android.comf2b98d62010-12-20 18:26:13 +000062void SkWindow::setMatrix(const SkMatrix& matrix) {
63 if (fMatrix != matrix) {
64 fMatrix = matrix;
65 this->inval(NULL);
66 }
67}
68
69void SkWindow::preConcat(const SkMatrix& matrix) {
70 SkMatrix m;
71 m.setConcat(fMatrix, matrix);
72 this->setMatrix(m);
73}
74
75void SkWindow::postConcat(const SkMatrix& matrix) {
76 SkMatrix m;
77 m.setConcat(matrix, fMatrix);
78 this->setMatrix(m);
79}
80
reed@android.com8a1c16f2008-12-17 15:59:43 +000081void SkWindow::setConfig(SkBitmap::Config config)
82{
83 this->resize(fBitmap.width(), fBitmap.height(), config);
84}
85
reed@android.com8a1c16f2008-12-17 15:59:43 +000086void SkWindow::resize(int width, int height, SkBitmap::Config config)
87{
88 if (config == SkBitmap::kNo_Config)
89 config = fConfig;
90
91 if (width != fBitmap.width() || height != fBitmap.height() || config != fConfig)
92 {
93 fConfig = config;
94 fBitmap.setConfig(config, width, height);
95 fBitmap.allocPixels();
reed@android.comf2b98d62010-12-20 18:26:13 +000096 fBitmap.setIsOpaque(true);
reed@android.com8a1c16f2008-12-17 15:59:43 +000097
98 this->setSize(SkIntToScalar(width), SkIntToScalar(height));
99 this->inval(NULL);
100 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101}
102
103void SkWindow::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
104{
105 fBitmap.eraseARGB(a, r, g, b);
106}
107
108void SkWindow::eraseRGB(U8CPU r, U8CPU g, U8CPU b)
109{
110 fBitmap.eraseRGB(r, g, b);
111}
112
reed@android.comf2b98d62010-12-20 18:26:13 +0000113bool SkWindow::handleInval(const SkRect* localR)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114{
115 SkIRect ir;
116
reed@android.comf2b98d62010-12-20 18:26:13 +0000117 if (localR) {
118 SkRect devR;
119 SkMatrix inverse;
120 if (!fMatrix.invert(&inverse)) {
121 return false;
122 }
123 fMatrix.mapRect(&devR, *localR);
124 devR.round(&ir);
125 } else {
reed@google.comf9bb7a82011-03-01 15:15:13 +0000126 ir.set(0, 0,
127 SkScalarRound(this->width()),
128 SkScalarRound(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000129 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 fDirtyRgn.op(ir, SkRegion::kUnion_Op);
131
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 this->onHandleInval(ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 return true;
134}
135
reed@android.comf2b98d62010-12-20 18:26:13 +0000136void SkWindow::forceInvalAll() {
reed@google.com261b8e22011-04-14 17:53:24 +0000137 fDirtyRgn.setRect(0, 0,
138 SkScalarCeil(this->width()),
139 SkScalarCeil(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000140}
141
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
143 #include <windows.h>
144 #include <gx.h>
145 extern GXDisplayProperties gDisplayProps;
146#endif
147
148#ifdef SK_SIMULATE_FAILED_MALLOC
149extern bool gEnableControlledThrow;
150#endif
151
reed@android.comf2b98d62010-12-20 18:26:13 +0000152bool SkWindow::update(SkIRect* updateArea, SkCanvas* canvas)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153{
154 if (!fDirtyRgn.isEmpty())
155 {
156 SkBitmap bm = this->getBitmap();
157
158#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
159 char* buffer = (char*)GXBeginDraw();
160 SkASSERT(buffer);
161
162 RECT rect;
163 GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect);
164 buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch;
165
166 bm.setPixels(buffer);
167#endif
168
reed@android.comf2b98d62010-12-20 18:26:13 +0000169 SkCanvas rasterCanvas;
170 SkDevice* device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171
reed@android.comf2b98d62010-12-20 18:26:13 +0000172 if (NULL == canvas) {
173 canvas = &rasterCanvas;
reed@android.comf2b98d62010-12-20 18:26:13 +0000174 }
reed@google.comaf951c92011-06-16 19:10:39 +0000175 canvas->setBitmapDevice(bm);
reed@android.comf2b98d62010-12-20 18:26:13 +0000176
177 canvas->clipRegion(fDirtyRgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 if (updateArea)
179 *updateArea = fDirtyRgn.getBounds();
180
reed@android.comf2b98d62010-12-20 18:26:13 +0000181 SkAutoCanvasRestore acr(canvas, true);
182 canvas->concat(fMatrix);
183
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 // empty this now, so we can correctly record any inval calls that
185 // might be made during the draw call.
186 fDirtyRgn.setEmpty();
187
188#ifdef TEST_BOUNDER
189 test_bounder b(bm);
reed@android.comf2b98d62010-12-20 18:26:13 +0000190 canvas->setBounder(&b);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191#endif
192#ifdef SK_SIMULATE_FAILED_MALLOC
193 gEnableControlledThrow = true;
194#endif
195#ifdef SK_BUILD_FOR_WIN32
reed@android.comf2b98d62010-12-20 18:26:13 +0000196 //try {
197 this->draw(canvas);
198 //}
199 //catch (...) {
200 //}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201#else
reed@android.comf2b98d62010-12-20 18:26:13 +0000202 this->draw(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203#endif
204#ifdef SK_SIMULATE_FAILED_MALLOC
205 gEnableControlledThrow = false;
206#endif
207#ifdef TEST_BOUNDER
reed@android.comf2b98d62010-12-20 18:26:13 +0000208 canvas->setBounder(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209#endif
210
211#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
212 GXEndDraw();
213#endif
214
215 return true;
216 }
217 return false;
218}
219
220bool SkWindow::handleChar(SkUnichar uni)
221{
222 if (this->onHandleChar(uni))
223 return true;
224
225 SkView* focus = this->getFocusView();
226 if (focus == NULL)
227 focus = this;
228
229 SkEvent evt(SK_EventType_Unichar);
230 evt.setFast32(uni);
231 return focus->doEvent(evt);
232}
233
234bool SkWindow::handleKey(SkKey key)
235{
236 if (key == kNONE_SkKey)
237 return false;
238
239 if (this->onHandleKey(key))
240 return true;
241
242 // send an event to the focus-view
243 {
244 SkView* focus = this->getFocusView();
245 if (focus == NULL)
246 focus = this;
247
248 SkEvent evt(SK_EventType_Key);
249 evt.setFast32(key);
250 if (focus->doEvent(evt))
251 return true;
252 }
253
254 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;
261}
262
263bool SkWindow::handleKeyUp(SkKey key)
264{
265 if (key == kNONE_SkKey)
266 return false;
267
268 if (this->onHandleKeyUp(key))
269 return true;
270
271 //send an event to the focus-view
272 {
273 SkView* focus = this->getFocusView();
274 if (focus == NULL)
275 focus = this;
276
277 //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
286void SkWindow::addMenu(SkOSMenu* menu)
287{
288 *fMenus.append() = menu;
289 this->onAddMenu(menu);
290}
291
reed@android.com0ae6b242008-12-23 16:49:54 +0000292void SkWindow::setTitle(const char title[]) {
293 if (NULL == title) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 title = "";
reed@android.com0ae6b242008-12-23 16:49:54 +0000295 }
296 fTitle.set(title);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 this->onSetTitle(title);
298}
299
300bool SkWindow::handleMenu(uint32_t cmd)
301{
302 for (int i = 0; i < fMenus.count(); i++)
303 {
304 SkEvent* evt = fMenus[i]->createEvent(cmd);
305 if (evt)
306 {
307 evt->post(this->getSinkID());
308 return true;
309 }
310 }
311 return false;
312}
313
314//////////////////////////////////////////////////////////////////////
315
316bool SkWindow::onEvent(const SkEvent& evt)
317{
318 if (evt.isType(SK_EventDelayInval))
319 {
320 SkRegion::Iterator iter(fDirtyRgn);
321
322 for (; !iter.done(); iter.next())
323 this->onHandleInval(iter.rect());
324 fWaitingOnInval = false;
325 return true;
326 }
327 return this->INHERITED::onEvent(evt);
328}
329
330bool SkWindow::onGetFocusView(SkView** focus) const
331{
332 if (focus)
333 *focus = fFocusView;
334 return true;
335}
336
337bool SkWindow::onSetFocusView(SkView* focus)
338{
339 if (fFocusView != focus)
340 {
341 if (fFocusView)
342 fFocusView->onFocusChange(false);
343 fFocusView = focus;
344 if (focus)
345 focus->onFocusChange(true);
346 }
347 return true;
348}
349
350//////////////////////////////////////////////////////////////////////
351
352void SkWindow::onHandleInval(const SkIRect&)
353{
354}
355
356bool SkWindow::onHandleChar(SkUnichar)
357{
358 return false;
359}
360
361bool SkWindow::onHandleKey(SkKey key)
362{
363 return false;
364}
365
366bool SkWindow::onHandleKeyUp(SkKey key)
367{
368 return false;
369}
370
Scroggod3aed392011-06-22 13:26:56 +0000371bool SkWindow::handleClick(int x, int y, Click::State state, void *owner) {
372 return this->onDispatchClick(x, y, state, owner);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000373}
374
Scroggod3aed392011-06-22 13:26:56 +0000375bool SkWindow::onDispatchClick(int x, int y, Click::State state,
376 void* owner) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 bool handled = false;
378
Scroggod3aed392011-06-22 13:26:56 +0000379 // First, attempt to find an existing click with this owner.
380 int index = -1;
381 for (int i = 0; i < fClicks.count(); i++) {
382 if (owner == fClicks[i]->fOwner) {
383 index = i;
384 break;
385 }
386 }
387
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 switch (state) {
Scroggod3aed392011-06-22 13:26:56 +0000389 case Click::kDown_State: {
390 if (index != -1) {
391 delete fClicks[index];
392 fClicks.remove(index);
393 }
394 Click* click = this->findClickHandler(SkIntToScalar(x),
395 SkIntToScalar(y));
396
397 if (click) {
398 click->fOwner = owner;
399 *fClicks.append() = click;
400 SkView::DoClickDown(click, x, y);
401 handled = true;
402 }
403 break;
404 }
405 case Click::kMoved_State:
406 if (index != -1) {
407 SkView::DoClickMoved(fClicks[index], x, y);
408 handled = true;
409 }
410 break;
411 case Click::kUp_State:
412 if (index != -1) {
413 SkView::DoClickUp(fClicks[index], x, y);
414 delete fClicks[index];
415 fClicks.remove(index);
416 handled = true;
417 }
418 break;
419 default:
420 // Do nothing
421 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 }
423 return handled;
424}
425