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
69SkCanvas* SkWindow::createCanvas() {
70    return new SkCanvas(this->getBitmap());
71}
72
73void SkWindow::setMatrix(const SkMatrix& matrix) {
74    if (fMatrix != matrix) {
75        fMatrix = matrix;
76        this->inval(NULL);
77    }
78}
79
80void SkWindow::preConcat(const SkMatrix& matrix) {
81    SkMatrix m;
82    m.setConcat(fMatrix, matrix);
83    this->setMatrix(m);
84}
85
86void SkWindow::postConcat(const SkMatrix& matrix) {
87    SkMatrix m;
88    m.setConcat(matrix, fMatrix);
89    this->setMatrix(m);
90}
91
92void SkWindow::setConfig(SkBitmap::Config config)
93{
94    this->resize(fBitmap.width(), fBitmap.height(), config);
95}
96
97void SkWindow::resize(int width, int height, SkBitmap::Config config)
98{
99    if (config == SkBitmap::kNo_Config)
100        config = fConfig;
101
102    if (width != fBitmap.width() || height != fBitmap.height() || config != fConfig)
103    {
104        fConfig = config;
105        fBitmap.setConfig(config, width, height, 0, kOpaque_SkAlphaType);
106        fBitmap.allocPixels();
107
108        this->setSize(SkIntToScalar(width), SkIntToScalar(height));
109        this->inval(NULL);
110    }
111}
112
113void SkWindow::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
114{
115    fBitmap.eraseARGB(a, r, g, b);
116}
117
118void SkWindow::eraseRGB(U8CPU r, U8CPU g, U8CPU b)
119{
120    fBitmap.eraseARGB(0xFF, r, g, b);
121}
122
123bool SkWindow::handleInval(const SkRect* localR)
124{
125    SkIRect    ir;
126
127    if (localR) {
128        SkRect devR;
129        SkMatrix inverse;
130        if (!fMatrix.invert(&inverse)) {
131            return false;
132        }
133        fMatrix.mapRect(&devR, *localR);
134        devR.round(&ir);
135    } else {
136        ir.set(0, 0,
137               SkScalarRound(this->width()),
138               SkScalarRound(this->height()));
139    }
140    fDirtyRgn.op(ir, SkRegion::kUnion_Op);
141
142    this->onHandleInval(ir);
143    return true;
144}
145
146void SkWindow::forceInvalAll() {
147    fDirtyRgn.setRect(0, 0,
148                      SkScalarCeil(this->width()),
149                      SkScalarCeil(this->height()));
150}
151
152#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
153    #include <windows.h>
154    #include <gx.h>
155    extern GXDisplayProperties gDisplayProps;
156#endif
157
158#ifdef SK_SIMULATE_FAILED_MALLOC
159extern bool gEnableControlledThrow;
160#endif
161
162bool SkWindow::update(SkIRect* updateArea)
163{
164    if (!fDirtyRgn.isEmpty())
165    {
166        SkBitmap bm = this->getBitmap();
167
168#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
169        char* buffer = (char*)GXBeginDraw();
170        SkASSERT(buffer);
171
172        RECT    rect;
173        GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect);
174        buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch;
175
176        bm.setPixels(buffer);
177#endif
178
179        SkAutoTUnref<SkCanvas> canvas(this->createCanvas());
180
181        canvas->clipRegion(fDirtyRgn);
182        if (updateArea)
183            *updateArea = fDirtyRgn.getBounds();
184
185        SkAutoCanvasRestore acr(canvas, true);
186        canvas->concat(fMatrix);
187
188        // empty this now, so we can correctly record any inval calls that
189        // might be made during the draw call.
190        fDirtyRgn.setEmpty();
191
192#ifdef TEST_BOUNDER
193        test_bounder    b(bm);
194        canvas->setBounder(&b);
195#endif
196#ifdef SK_SIMULATE_FAILED_MALLOC
197        gEnableControlledThrow = true;
198#endif
199#ifdef SK_BUILD_FOR_WIN32
200        //try {
201            this->draw(canvas);
202        //}
203        //catch (...) {
204        //}
205#else
206        this->draw(canvas);
207#endif
208#ifdef SK_SIMULATE_FAILED_MALLOC
209        gEnableControlledThrow = false;
210#endif
211#ifdef TEST_BOUNDER
212        canvas->setBounder(NULL);
213#endif
214
215#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
216        GXEndDraw();
217#endif
218
219        return true;
220    }
221    return false;
222}
223
224bool SkWindow::handleChar(SkUnichar uni)
225{
226    if (this->onHandleChar(uni))
227        return true;
228
229    SkView* focus = this->getFocusView();
230    if (focus == NULL)
231        focus = this;
232
233    SkEvent evt(SK_EventType_Unichar);
234    evt.setFast32(uni);
235    return focus->doEvent(evt);
236}
237
238bool SkWindow::handleKey(SkKey key)
239{
240    if (key == kNONE_SkKey)
241        return false;
242
243    if (this->onHandleKey(key))
244        return true;
245
246    // send an event to the focus-view
247    {
248        SkView* focus = this->getFocusView();
249        if (focus == NULL)
250            focus = this;
251
252        SkEvent evt(SK_EventType_Key);
253        evt.setFast32(key);
254        if (focus->doEvent(evt))
255            return true;
256    }
257
258    if (key == kUp_SkKey || key == kDown_SkKey)
259    {
260        if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL)
261            this->onSetFocusView(NULL);
262        return true;
263    }
264    return false;
265}
266
267bool SkWindow::handleKeyUp(SkKey key)
268{
269    if (key == kNONE_SkKey)
270        return false;
271
272    if (this->onHandleKeyUp(key))
273        return true;
274
275    //send an event to the focus-view
276    {
277        SkView* focus = this->getFocusView();
278        if (focus == NULL)
279            focus = this;
280
281        //should this one be the same?
282        SkEvent evt(SK_EventType_KeyUp);
283        evt.setFast32(key);
284        if (focus->doEvent(evt))
285            return true;
286    }
287    return false;
288}
289
290void SkWindow::addMenu(SkOSMenu* menu) {
291    *fMenus.append() = menu;
292    this->onAddMenu(menu);
293}
294
295void SkWindow::setTitle(const char title[]) {
296    if (NULL == title) {
297        title = "";
298    }
299    fTitle.set(title);
300    this->onSetTitle(title);
301}
302
303//////////////////////////////////////////////////////////////////////
304
305bool SkWindow::onEvent(const SkEvent& evt)
306{
307    if (evt.isType(SK_EventDelayInval))
308    {
309        SkRegion::Iterator    iter(fDirtyRgn);
310
311        for (; !iter.done(); iter.next())
312            this->onHandleInval(iter.rect());
313        fWaitingOnInval = false;
314        return true;
315    }
316    return this->INHERITED::onEvent(evt);
317}
318
319bool SkWindow::onGetFocusView(SkView** focus) const
320{
321    if (focus)
322        *focus = fFocusView;
323    return true;
324}
325
326bool SkWindow::onSetFocusView(SkView* focus)
327{
328    if (fFocusView != focus)
329    {
330        if (fFocusView)
331            fFocusView->onFocusChange(false);
332        fFocusView = focus;
333        if (focus)
334            focus->onFocusChange(true);
335    }
336    return true;
337}
338
339//////////////////////////////////////////////////////////////////////
340
341void SkWindow::onHandleInval(const SkIRect&)
342{
343}
344
345bool SkWindow::onHandleChar(SkUnichar)
346{
347    return false;
348}
349
350bool SkWindow::onHandleKey(SkKey)
351{
352    return false;
353}
354
355bool SkWindow::onHandleKeyUp(SkKey)
356{
357    return false;
358}
359
360bool SkWindow::handleClick(int x, int y, Click::State state, void *owner,
361                           unsigned modifierKeys) {
362    return this->onDispatchClick(x, y, state, owner, modifierKeys);
363}
364
365bool SkWindow::onDispatchClick(int x, int y, Click::State state,
366                               void* owner, unsigned modifierKeys) {
367    bool handled = false;
368
369    // First, attempt to find an existing click with this owner.
370    int index = -1;
371    for (int i = 0; i < fClicks.count(); i++) {
372        if (owner == fClicks[i]->fOwner) {
373            index = i;
374            break;
375        }
376    }
377
378    switch (state) {
379        case Click::kDown_State: {
380            if (index != -1) {
381                delete fClicks[index];
382                fClicks.remove(index);
383            }
384            Click* click = this->findClickHandler(SkIntToScalar(x),
385                                                  SkIntToScalar(y), modifierKeys);
386
387            if (click) {
388                click->fOwner = owner;
389                *fClicks.append() = click;
390                SkView::DoClickDown(click, x, y, modifierKeys);
391                handled = true;
392            }
393            break;
394        }
395        case Click::kMoved_State:
396            if (index != -1) {
397                SkView::DoClickMoved(fClicks[index], x, y, modifierKeys);
398                handled = true;
399            }
400            break;
401        case Click::kUp_State:
402            if (index != -1) {
403                SkView::DoClickUp(fClicks[index], x, y, modifierKeys);
404                delete fClicks[index];
405                fClicks.remove(index);
406                handled = true;
407            }
408            break;
409        default:
410            // Do nothing
411            break;
412    }
413    return handled;
414}
415