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