1
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 */
8#include "SkWindow.h"
9#include "SkCanvas.h"
10#include "SkDevice.h"
11#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{
51    fClicks.reset();
52    fWaitingOnInval = false;
53
54#ifdef SK_BUILD_FOR_WINCE
55    fConfig = SkBitmap::kRGB_565_Config;
56#else
57    fConfig = SkBitmap::kARGB_8888_Config;
58#endif
59
60    fMatrix.reset();
61}
62
63SkWindow::~SkWindow()
64{
65    fClicks.deleteAll();
66    fMenus.deleteAll();
67}
68
69void 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
88void SkWindow::setConfig(SkBitmap::Config config)
89{
90	this->resize(fBitmap.width(), fBitmap.height(), config);
91}
92
93void 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();
103        fBitmap.setIsOpaque(true);
104
105		this->setSize(SkIntToScalar(width), SkIntToScalar(height));
106		this->inval(NULL);
107	}
108}
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
120bool SkWindow::handleInval(const SkRect* localR)
121{
122	SkIRect	ir;
123
124    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 {
133        ir.set(0, 0,
134			   SkScalarRound(this->width()),
135			   SkScalarRound(this->height()));
136    }
137	fDirtyRgn.op(ir, SkRegion::kUnion_Op);
138
139	this->onHandleInval(ir);
140	return true;
141}
142
143void SkWindow::forceInvalAll() {
144    fDirtyRgn.setRect(0, 0,
145                      SkScalarCeil(this->width()),
146                      SkScalarCeil(this->height()));
147}
148
149#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
159bool SkWindow::update(SkIRect* updateArea, SkCanvas* canvas)
160{
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
176		SkCanvas	rasterCanvas;
177
178        if (NULL == canvas) {
179            canvas = &rasterCanvas;
180        }
181        canvas->setBitmapDevice(bm);
182
183		canvas->clipRegion(fDirtyRgn);
184		if (updateArea)
185			*updateArea = fDirtyRgn.getBounds();
186
187        SkAutoCanvasRestore acr(canvas, true);
188        canvas->concat(fMatrix);
189
190		// empty this now, so we can correctly record any inval calls that
191		// might be made during the draw call.
192		fDirtyRgn.setEmpty();
193
194#ifdef TEST_BOUNDER
195		test_bounder	b(bm);
196		canvas->setBounder(&b);
197#endif
198#ifdef SK_SIMULATE_FAILED_MALLOC
199		gEnableControlledThrow = true;
200#endif
201#ifdef SK_BUILD_FOR_WIN32
202		//try {
203			this->draw(canvas);
204		//}
205		//catch (...) {
206		//}
207#else
208		this->draw(canvas);
209#endif
210#ifdef SK_SIMULATE_FAILED_MALLOC
211		gEnableControlledThrow = false;
212#endif
213#ifdef TEST_BOUNDER
214		canvas->setBounder(NULL);
215#endif
216
217#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
218		GXEndDraw();
219#endif
220
221		return true;
222	}
223	return false;
224}
225
226bool SkWindow::handleChar(SkUnichar uni)
227{
228	if (this->onHandleChar(uni))
229		return true;
230
231	SkView* focus = this->getFocusView();
232	if (focus == NULL)
233		focus = this;
234
235	SkEvent evt(SK_EventType_Unichar);
236	evt.setFast32(uni);
237	return focus->doEvent(evt);
238}
239
240bool SkWindow::handleKey(SkKey key)
241{
242	if (key == kNONE_SkKey)
243		return false;
244
245	if (this->onHandleKey(key))
246		return true;
247
248	// send an event to the focus-view
249	{
250		SkView* focus = this->getFocusView();
251		if (focus == NULL)
252			focus = this;
253
254		SkEvent evt(SK_EventType_Key);
255		evt.setFast32(key);
256		if (focus->doEvent(evt))
257			return true;
258	}
259
260	if (key == kUp_SkKey || key == kDown_SkKey)
261	{
262		if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL)
263			this->onSetFocusView(NULL);
264		return true;
265	}
266	return false;
267}
268
269bool SkWindow::handleKeyUp(SkKey key)
270{
271    if (key == kNONE_SkKey)
272        return false;
273
274    if (this->onHandleKeyUp(key))
275        return true;
276
277    //send an event to the focus-view
278    {
279        SkView* focus = this->getFocusView();
280        if (focus == NULL)
281            focus = this;
282
283        //should this one be the same?
284        SkEvent evt(SK_EventType_KeyUp);
285        evt.setFast32(key);
286        if (focus->doEvent(evt))
287            return true;
288    }
289    return false;
290}
291
292void SkWindow::addMenu(SkOSMenu* menu) {
293	*fMenus.append() = menu;
294	this->onAddMenu(menu);
295}
296
297void SkWindow::setTitle(const char title[]) {
298    if (NULL == title) {
299        title = "";
300    }
301    fTitle.set(title);
302    this->onSetTitle(title);
303}
304
305//////////////////////////////////////////////////////////////////////
306
307bool SkWindow::onEvent(const SkEvent& evt)
308{
309	if (evt.isType(SK_EventDelayInval))
310	{
311		SkRegion::Iterator	iter(fDirtyRgn);
312
313		for (; !iter.done(); iter.next())
314			this->onHandleInval(iter.rect());
315		fWaitingOnInval = false;
316		return true;
317	}
318	return this->INHERITED::onEvent(evt);
319}
320
321bool SkWindow::onGetFocusView(SkView** focus) const
322{
323	if (focus)
324		*focus = fFocusView;
325	return true;
326}
327
328bool SkWindow::onSetFocusView(SkView* focus)
329{
330	if (fFocusView != focus)
331	{
332		if (fFocusView)
333			fFocusView->onFocusChange(false);
334		fFocusView = focus;
335		if (focus)
336			focus->onFocusChange(true);
337	}
338	return true;
339}
340
341//////////////////////////////////////////////////////////////////////
342
343void SkWindow::onHandleInval(const SkIRect&)
344{
345}
346
347bool SkWindow::onHandleChar(SkUnichar)
348{
349	return false;
350}
351
352bool SkWindow::onHandleKey(SkKey key)
353{
354	return false;
355}
356
357bool SkWindow::onHandleKeyUp(SkKey key)
358{
359    return false;
360}
361
362bool SkWindow::handleClick(int x, int y, Click::State state, void *owner) {
363    return this->onDispatchClick(x, y, state, owner);
364}
365
366bool SkWindow::onDispatchClick(int x, int y, Click::State state,
367        void* owner) {
368	bool handled = false;
369
370    // First, attempt to find an existing click with this owner.
371    int index = -1;
372    for (int i = 0; i < fClicks.count(); i++) {
373        if (owner == fClicks[i]->fOwner) {
374            index = i;
375            break;
376        }
377    }
378
379	switch (state) {
380        case Click::kDown_State: {
381            if (index != -1) {
382                delete fClicks[index];
383                fClicks.remove(index);
384            }
385            Click* click = this->findClickHandler(SkIntToScalar(x),
386                    SkIntToScalar(y));
387
388            if (click) {
389                click->fOwner = owner;
390                *fClicks.append() = click;
391                SkView::DoClickDown(click, x, y);
392                handled = true;
393            }
394            break;
395        }
396        case Click::kMoved_State:
397            if (index != -1) {
398                SkView::DoClickMoved(fClicks[index], x, y);
399                handled = true;
400            }
401            break;
402        case Click::kUp_State:
403            if (index != -1) {
404                SkView::DoClickUp(fClicks[index], x, y);
405                delete fClicks[index];
406                fClicks.remove(index);
407                handled = true;
408            }
409            break;
410        default:
411            // Do nothing
412            break;
413	}
414	return handled;
415}
416
417