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()
18    : fSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)
19    , fFocusView(nullptr)
20{
21    fClicks.reset();
22    fWaitingOnInval = false;
23    fMatrix.reset();
24
25    fBitmap.allocN32Pixels(0, 0);
26}
27
28SkWindow::~SkWindow() {
29    fClicks.deleteAll();
30    fMenus.deleteAll();
31}
32
33sk_sp<SkSurface> SkWindow::makeSurface() {
34    const SkBitmap& bm = this->getBitmap();
35    return SkSurface::MakeRasterDirect(bm.info(), bm.getPixels(), bm.rowBytes(), &fSurfaceProps);
36}
37
38void SkWindow::setMatrix(const SkMatrix& matrix) {
39    if (fMatrix != matrix) {
40        fMatrix = matrix;
41        this->inval(nullptr);
42    }
43}
44
45void SkWindow::preConcat(const SkMatrix& matrix) {
46    SkMatrix m;
47    m.setConcat(fMatrix, matrix);
48    this->setMatrix(m);
49}
50
51void SkWindow::postConcat(const SkMatrix& matrix) {
52    SkMatrix m;
53    m.setConcat(matrix, fMatrix);
54    this->setMatrix(m);
55}
56
57void SkWindow::resize(const SkImageInfo& info) {
58    if (fBitmap.info() != info) {
59        fBitmap.allocPixels(info);
60        this->inval(nullptr);
61    }
62    this->setSize(SkIntToScalar(fBitmap.width()), SkIntToScalar(fBitmap.height()));
63}
64
65void SkWindow::resize(int width, int height) {
66    this->resize(fBitmap.info().makeWH(width, height));
67}
68
69void SkWindow::setColorType(SkColorType ct, sk_sp<SkColorSpace> cs) {
70    const SkImageInfo& info = fBitmap.info();
71    this->resize(SkImageInfo::Make(info.width(), info.height(), ct, kPremul_SkAlphaType, cs));
72}
73
74bool SkWindow::handleInval(const SkRect* localR) {
75    SkIRect ir;
76
77    if (localR) {
78        SkRect devR;
79        SkMatrix inverse;
80        if (!fMatrix.invert(&inverse)) {
81            return false;
82        }
83        fMatrix.mapRect(&devR, *localR);
84        devR.round(&ir);
85    } else {
86        ir.set(0, 0,
87               SkScalarRoundToInt(this->width()),
88               SkScalarRoundToInt(this->height()));
89    }
90    fDirtyRgn.op(ir, SkRegion::kUnion_Op);
91
92    this->onHandleInval(ir);
93    return true;
94}
95
96void SkWindow::forceInvalAll() {
97    fDirtyRgn.setRect(0, 0,
98                      SkScalarCeilToInt(this->width()),
99                      SkScalarCeilToInt(this->height()));
100}
101
102#ifdef SK_SIMULATE_FAILED_MALLOC
103extern bool gEnableControlledThrow;
104#endif
105
106bool SkWindow::update(SkIRect* updateArea) {
107    if (!fDirtyRgn.isEmpty()) {
108        sk_sp<SkSurface> surface(this->makeSurface());
109        SkCanvas* canvas = surface->getCanvas();
110
111        canvas->clipRegion(fDirtyRgn);
112        if (updateArea) {
113            *updateArea = fDirtyRgn.getBounds();
114        }
115
116        SkAutoCanvasRestore acr(canvas, true);
117        canvas->concat(fMatrix);
118
119        // empty this now, so we can correctly record any inval calls that
120        // might be made during the draw call.
121        fDirtyRgn.setEmpty();
122
123#ifdef SK_SIMULATE_FAILED_MALLOC
124        gEnableControlledThrow = true;
125#endif
126#ifdef SK_BUILD_FOR_WIN32
127        //try {
128            this->draw(canvas);
129        //}
130        //catch (...) {
131        //}
132#else
133        this->draw(canvas);
134#endif
135#ifdef SK_SIMULATE_FAILED_MALLOC
136        gEnableControlledThrow = false;
137#endif
138
139        return true;
140    }
141    return false;
142}
143
144bool SkWindow::handleChar(SkUnichar uni) {
145    if (this->onHandleChar(uni))
146        return true;
147
148    SkView* focus = this->getFocusView();
149    if (focus == nullptr)
150        focus = this;
151
152    SkEvent evt(SK_EventType_Unichar);
153    evt.setFast32(uni);
154    return focus->doEvent(evt);
155}
156
157bool SkWindow::handleKey(SkKey key) {
158    if (key == kNONE_SkKey)
159        return false;
160
161    if (this->onHandleKey(key))
162        return true;
163
164    // send an event to the focus-view
165    {
166        SkView* focus = this->getFocusView();
167        if (focus == nullptr)
168            focus = this;
169
170        SkEvent evt(SK_EventType_Key);
171        evt.setFast32(key);
172        if (focus->doEvent(evt))
173            return true;
174    }
175
176    if (key == kUp_SkKey || key == kDown_SkKey) {
177        if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == nullptr)
178            this->onSetFocusView(nullptr);
179        return true;
180    }
181    return false;
182}
183
184bool SkWindow::handleKeyUp(SkKey key) {
185    if (key == kNONE_SkKey)
186        return false;
187
188    if (this->onHandleKeyUp(key))
189        return true;
190
191    //send an event to the focus-view
192    {
193        SkView* focus = this->getFocusView();
194        if (focus == nullptr)
195            focus = this;
196
197        //should this one be the same?
198        SkEvent evt(SK_EventType_KeyUp);
199        evt.setFast32(key);
200        if (focus->doEvent(evt))
201            return true;
202    }
203    return false;
204}
205
206void SkWindow::addMenu(SkOSMenu* menu) {
207    *fMenus.append() = menu;
208    this->onAddMenu(menu);
209}
210
211void SkWindow::setTitle(const char title[]) {
212    if (nullptr == title) {
213        title = "";
214    }
215    fTitle.set(title);
216    this->onSetTitle(title);
217}
218
219bool SkWindow::onEvent(const SkEvent& evt) {
220    if (evt.isType(SK_EventDelayInval)) {
221        for (SkRegion::Iterator iter(fDirtyRgn); !iter.done(); iter.next())
222            this->onHandleInval(iter.rect());
223        fWaitingOnInval = false;
224        return true;
225    }
226    return this->INHERITED::onEvent(evt);
227}
228
229bool SkWindow::onGetFocusView(SkView** focus) const {
230    if (focus)
231        *focus = fFocusView;
232    return true;
233}
234
235bool SkWindow::onSetFocusView(SkView* focus) {
236    if (fFocusView != focus) {
237        if (fFocusView)
238            fFocusView->onFocusChange(false);
239        fFocusView = focus;
240        if (focus)
241            focus->onFocusChange(true);
242    }
243    return true;
244}
245
246void SkWindow::onHandleInval(const SkIRect&) {
247}
248
249bool SkWindow::onHandleChar(SkUnichar) {
250    return false;
251}
252
253bool SkWindow::onHandleKey(SkKey) {
254    return false;
255}
256
257bool SkWindow::onHandleKeyUp(SkKey) {
258    return false;
259}
260
261bool SkWindow::handleClick(int x, int y, Click::State state, void *owner,
262                           unsigned modifierKeys) {
263    return this->onDispatchClick(x, y, state, owner, modifierKeys);
264}
265
266bool SkWindow::onDispatchClick(int x, int y, Click::State state,
267                               void* owner, unsigned modifierKeys) {
268    bool handled = false;
269
270    // First, attempt to find an existing click with this owner.
271    int index = -1;
272    for (int i = 0; i < fClicks.count(); i++) {
273        if (owner == fClicks[i]->fOwner) {
274            index = i;
275            break;
276        }
277    }
278
279    switch (state) {
280        case Click::kDown_State: {
281            if (index != -1) {
282                delete fClicks[index];
283                fClicks.remove(index);
284            }
285            Click* click = this->findClickHandler(SkIntToScalar(x),
286                                                  SkIntToScalar(y), modifierKeys);
287
288            if (click) {
289                click->fOwner = owner;
290                *fClicks.append() = click;
291                SkView::DoClickDown(click, x, y, modifierKeys);
292                handled = true;
293            }
294            break;
295        }
296        case Click::kMoved_State:
297            if (index != -1) {
298                SkView::DoClickMoved(fClicks[index], x, y, modifierKeys);
299                handled = true;
300            }
301            break;
302        case Click::kUp_State:
303            if (index != -1) {
304                SkView::DoClickUp(fClicks[index], x, y, modifierKeys);
305                delete fClicks[index];
306                fClicks.remove(index);
307                handled = true;
308            }
309            break;
310        default:
311            // Do nothing
312            break;
313    }
314    return handled;
315}
316
317#if SK_SUPPORT_GPU
318
319#include "GrContext.h"
320#include "gl/GrGLInterface.h"
321#include "gl/GrGLUtil.h"
322#include "SkGr.h"
323
324sk_sp<SkSurface> SkWindow::makeGpuBackedSurface(const AttachmentInfo& attachmentInfo,
325                                                const GrGLInterface* interface,
326                                                GrContext* grContext) {
327    GrBackendRenderTargetDesc desc;
328    desc.fWidth = SkScalarRoundToInt(this->width());
329    desc.fHeight = SkScalarRoundToInt(this->height());
330    if (0 == desc.fWidth || 0 == desc.fHeight) {
331        return nullptr;
332    }
333
334    // TODO: Query the actual framebuffer for sRGB capable. However, to
335    // preserve old (fake-linear) behavior, we don't do this. Instead, rely
336    // on the flag (currently driven via 'C' mode in SampleApp).
337    //
338    // Also, we may not have real sRGB support (ANGLE, in particular), so check for
339    // that, and fall back to L32:
340    //
341    // ... and, if we're using a 10-bit/channel FB0, it doesn't do sRGB conversion on write,
342    // so pretend that it's non-sRGB 8888:
343    desc.fConfig =
344        grContext->caps()->srgbSupport() &&
345        info().colorSpace() &&
346        (attachmentInfo.fColorBits != 30)
347        ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
348    desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
349    desc.fSampleCnt = attachmentInfo.fSampleCount;
350    desc.fStencilBits = attachmentInfo.fStencilBits;
351    GrGLint buffer;
352    GR_GL_GetIntegerv(interface, GR_GL_FRAMEBUFFER_BINDING, &buffer);
353    desc.fRenderTargetHandle = buffer;
354
355    sk_sp<SkColorSpace> colorSpace =
356        grContext->caps()->srgbSupport() && info().colorSpace()
357        ? SkColorSpace::MakeSRGB() : nullptr;
358    return SkSurface::MakeFromBackendRenderTarget(grContext, desc, colorSpace, &fSurfaceProps);
359}
360
361#endif
362