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
17SkWindow::SkWindow() : fFocusView(NULL) {
18    fClicks.reset();
19    fWaitingOnInval = false;
20
21#ifdef SK_BUILD_FOR_WINCE
22    fColorType = kRGB_565_SkColorType;
23#else
24    fColorType = kN32_SkColorType;
25#endif
26
27    fMatrix.reset();
28}
29
30SkWindow::~SkWindow() {
31    fClicks.deleteAll();
32    fMenus.deleteAll();
33}
34
35SkCanvas* SkWindow::createCanvas() {
36    return new SkCanvas(this->getBitmap());
37}
38
39void SkWindow::setMatrix(const SkMatrix& matrix) {
40    if (fMatrix != matrix) {
41        fMatrix = matrix;
42        this->inval(NULL);
43    }
44}
45
46void SkWindow::preConcat(const SkMatrix& matrix) {
47    SkMatrix m;
48    m.setConcat(fMatrix, matrix);
49    this->setMatrix(m);
50}
51
52void SkWindow::postConcat(const SkMatrix& matrix) {
53    SkMatrix m;
54    m.setConcat(matrix, fMatrix);
55    this->setMatrix(m);
56}
57
58void SkWindow::setColorType(SkColorType ct) {
59    this->resize(fBitmap.width(), fBitmap.height(), ct);
60}
61
62void SkWindow::resize(int width, int height, SkColorType ct) {
63    if (ct == kUnknown_SkColorType)
64        ct = fColorType;
65
66    if (width != fBitmap.width() || height != fBitmap.height() || ct != fColorType) {
67        fColorType = ct;
68        fBitmap.allocPixels(SkImageInfo::Make(width, height,
69                                              ct, kPremul_SkAlphaType));
70
71        this->setSize(SkIntToScalar(width), SkIntToScalar(height));
72        this->inval(NULL);
73    }
74}
75
76bool SkWindow::handleInval(const SkRect* localR) {
77    SkIRect ir;
78
79    if (localR) {
80        SkRect devR;
81        SkMatrix inverse;
82        if (!fMatrix.invert(&inverse)) {
83            return false;
84        }
85        fMatrix.mapRect(&devR, *localR);
86        devR.round(&ir);
87    } else {
88        ir.set(0, 0,
89               SkScalarRoundToInt(this->width()),
90               SkScalarRoundToInt(this->height()));
91    }
92    fDirtyRgn.op(ir, SkRegion::kUnion_Op);
93
94    this->onHandleInval(ir);
95    return true;
96}
97
98void SkWindow::forceInvalAll() {
99    fDirtyRgn.setRect(0, 0,
100                      SkScalarCeilToInt(this->width()),
101                      SkScalarCeilToInt(this->height()));
102}
103
104#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
105    #include <windows.h>
106    #include <gx.h>
107    extern GXDisplayProperties gDisplayProps;
108#endif
109
110#ifdef SK_SIMULATE_FAILED_MALLOC
111extern bool gEnableControlledThrow;
112#endif
113
114bool SkWindow::update(SkIRect* updateArea) {
115    if (!fDirtyRgn.isEmpty()) {
116        SkBitmap bm = this->getBitmap();
117
118#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
119        char* buffer = (char*)GXBeginDraw();
120        SkASSERT(buffer);
121
122        RECT    rect;
123        GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect);
124        buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch;
125
126        bm.setPixels(buffer);
127#endif
128
129        SkAutoTUnref<SkCanvas> canvas(this->createCanvas());
130
131        canvas->clipRegion(fDirtyRgn);
132        if (updateArea)
133            *updateArea = fDirtyRgn.getBounds();
134
135        SkAutoCanvasRestore acr(canvas, true);
136        canvas->concat(fMatrix);
137
138        // empty this now, so we can correctly record any inval calls that
139        // might be made during the draw call.
140        fDirtyRgn.setEmpty();
141
142#ifdef SK_SIMULATE_FAILED_MALLOC
143        gEnableControlledThrow = true;
144#endif
145#ifdef SK_BUILD_FOR_WIN32
146        //try {
147            this->draw(canvas);
148        //}
149        //catch (...) {
150        //}
151#else
152        this->draw(canvas);
153#endif
154#ifdef SK_SIMULATE_FAILED_MALLOC
155        gEnableControlledThrow = false;
156#endif
157
158#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
159        GXEndDraw();
160#endif
161
162        return true;
163    }
164    return false;
165}
166
167bool SkWindow::handleChar(SkUnichar uni) {
168    if (this->onHandleChar(uni))
169        return true;
170
171    SkView* focus = this->getFocusView();
172    if (focus == NULL)
173        focus = this;
174
175    SkEvent evt(SK_EventType_Unichar);
176    evt.setFast32(uni);
177    return focus->doEvent(evt);
178}
179
180bool SkWindow::handleKey(SkKey key) {
181    if (key == kNONE_SkKey)
182        return false;
183
184    if (this->onHandleKey(key))
185        return true;
186
187    // send an event to the focus-view
188    {
189        SkView* focus = this->getFocusView();
190        if (focus == NULL)
191            focus = this;
192
193        SkEvent evt(SK_EventType_Key);
194        evt.setFast32(key);
195        if (focus->doEvent(evt))
196            return true;
197    }
198
199    if (key == kUp_SkKey || key == kDown_SkKey) {
200        if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL)
201            this->onSetFocusView(NULL);
202        return true;
203    }
204    return false;
205}
206
207bool SkWindow::handleKeyUp(SkKey key) {
208    if (key == kNONE_SkKey)
209        return false;
210
211    if (this->onHandleKeyUp(key))
212        return true;
213
214    //send an event to the focus-view
215    {
216        SkView* focus = this->getFocusView();
217        if (focus == NULL)
218            focus = this;
219
220        //should this one be the same?
221        SkEvent evt(SK_EventType_KeyUp);
222        evt.setFast32(key);
223        if (focus->doEvent(evt))
224            return true;
225    }
226    return false;
227}
228
229void SkWindow::addMenu(SkOSMenu* menu) {
230    *fMenus.append() = menu;
231    this->onAddMenu(menu);
232}
233
234void SkWindow::setTitle(const char title[]) {
235    if (NULL == title) {
236        title = "";
237    }
238    fTitle.set(title);
239    this->onSetTitle(title);
240}
241
242bool SkWindow::onEvent(const SkEvent& evt) {
243    if (evt.isType(SK_EventDelayInval)) {
244        for (SkRegion::Iterator iter(fDirtyRgn); !iter.done(); iter.next())
245            this->onHandleInval(iter.rect());
246        fWaitingOnInval = false;
247        return true;
248    }
249    return this->INHERITED::onEvent(evt);
250}
251
252bool SkWindow::onGetFocusView(SkView** focus) const {
253    if (focus)
254        *focus = fFocusView;
255    return true;
256}
257
258bool SkWindow::onSetFocusView(SkView* focus) {
259    if (fFocusView != focus) {
260        if (fFocusView)
261            fFocusView->onFocusChange(false);
262        fFocusView = focus;
263        if (focus)
264            focus->onFocusChange(true);
265    }
266    return true;
267}
268
269void SkWindow::onHandleInval(const SkIRect&) {
270}
271
272bool SkWindow::onHandleChar(SkUnichar) {
273    return false;
274}
275
276bool SkWindow::onHandleKey(SkKey) {
277    return false;
278}
279
280bool SkWindow::onHandleKeyUp(SkKey) {
281    return false;
282}
283
284bool SkWindow::handleClick(int x, int y, Click::State state, void *owner,
285                           unsigned modifierKeys) {
286    return this->onDispatchClick(x, y, state, owner, modifierKeys);
287}
288
289bool SkWindow::onDispatchClick(int x, int y, Click::State state,
290                               void* owner, unsigned modifierKeys) {
291    bool handled = false;
292
293    // First, attempt to find an existing click with this owner.
294    int index = -1;
295    for (int i = 0; i < fClicks.count(); i++) {
296        if (owner == fClicks[i]->fOwner) {
297            index = i;
298            break;
299        }
300    }
301
302    switch (state) {
303        case Click::kDown_State: {
304            if (index != -1) {
305                delete fClicks[index];
306                fClicks.remove(index);
307            }
308            Click* click = this->findClickHandler(SkIntToScalar(x),
309                                                  SkIntToScalar(y), modifierKeys);
310
311            if (click) {
312                click->fOwner = owner;
313                *fClicks.append() = click;
314                SkView::DoClickDown(click, x, y, modifierKeys);
315                handled = true;
316            }
317            break;
318        }
319        case Click::kMoved_State:
320            if (index != -1) {
321                SkView::DoClickMoved(fClicks[index], x, y, modifierKeys);
322                handled = true;
323            }
324            break;
325        case Click::kUp_State:
326            if (index != -1) {
327                SkView::DoClickUp(fClicks[index], x, y, modifierKeys);
328                delete fClicks[index];
329                fClicks.remove(index);
330                handled = true;
331            }
332            break;
333        default:
334            // Do nothing
335            break;
336    }
337    return handled;
338}
339