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