blob: d06d6bb9eb4a3b6bf250f7f2946b51239ea83ae9 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
reed0397e9f2014-09-18 11:29:01 -07007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkWindow.h"
9#include "SkCanvas.h"
10#include "SkOSMenu.h"
reed0397e9f2014-09-18 11:29:01 -070011#include "SkSurface.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkSystemEventTypes.h"
13#include "SkTime.h"
14
15#define SK_EventDelayInval "\xd" "n" "\xa" "l"
16
reed4302ae92014-10-06 12:29:56 -070017SkWindow::SkWindow()
18 : fSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)
halcanary96fcdcc2015-08-27 07:41:13 -070019 , fFocusView(nullptr)
reed4302ae92014-10-06 12:29:56 -070020{
Scroggod3aed392011-06-22 13:26:56 +000021 fClicks.reset();
22 fWaitingOnInval = false;
reed@android.comf2b98d62010-12-20 18:26:13 +000023 fMatrix.reset();
reeda34be682016-02-15 07:48:35 -080024
25 fBitmap.allocN32Pixels(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000026}
27
tfarina@chromium.org658650c2014-01-25 18:45:45 +000028SkWindow::~SkWindow() {
Scroggod3aed392011-06-22 13:26:56 +000029 fClicks.deleteAll();
30 fMenus.deleteAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000031}
32
reed0397e9f2014-09-18 11:29:01 -070033SkSurface* SkWindow::createSurface() {
34 const SkBitmap& bm = this->getBitmap();
reede8f30622016-03-23 18:59:25 -070035 return SkSurface::MakeRasterDirect(bm.info(), bm.getPixels(), bm.rowBytes(),
36 &fSurfaceProps).release();
reed@google.com5957f472012-10-01 20:31:56 +000037}
38
reed@android.comf2b98d62010-12-20 18:26:13 +000039void SkWindow::setMatrix(const SkMatrix& matrix) {
40 if (fMatrix != matrix) {
41 fMatrix = matrix;
halcanary96fcdcc2015-08-27 07:41:13 -070042 this->inval(nullptr);
reed@android.comf2b98d62010-12-20 18:26:13 +000043 }
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
reeda34be682016-02-15 07:48:35 -080058void SkWindow::resize(const SkImageInfo& info) {
59 if (fBitmap.info() != info) {
60 fBitmap.allocPixels(info);
halcanary96fcdcc2015-08-27 07:41:13 -070061 this->inval(nullptr);
rmistry@google.comd6176b02012-08-23 18:14:13 +000062 }
reeda34be682016-02-15 07:48:35 -080063 this->setSize(SkIntToScalar(fBitmap.width()), SkIntToScalar(fBitmap.height()));
64}
65
66void SkWindow::resize(int width, int height) {
67 this->resize(fBitmap.info().makeWH(width, height));
68}
69
70void SkWindow::setColorType(SkColorType ct, SkColorProfileType pt) {
71 const SkImageInfo& info = fBitmap.info();
72 this->resize(SkImageInfo::Make(info.width(), info.height(), ct, kPremul_SkAlphaType, pt));
brianosman898235c2016-04-06 07:38:23 -070073
74 // Set the global flag that enables or disables "legacy" mode, depending on our format.
75 // With sRGB 32-bit or linear FP 16, we turn on gamma-correct handling of inputs:
76 SkSurfaceProps props = this->getSurfaceProps();
brianosmanb461d342016-04-13 13:10:14 -070077 uint32_t flags = (props.flags() & ~SkSurfaceProps::kGammaCorrect_Flag) |
78 (SkColorAndProfileAreGammaCorrect(ct, pt) ? SkSurfaceProps::kGammaCorrect_Flag : 0);
brianosman898235c2016-04-06 07:38:23 -070079 this->setSurfaceProps(SkSurfaceProps(flags, props.pixelGeometry()));
reed@android.com8a1c16f2008-12-17 15:59:43 +000080}
81
tfarina@chromium.org658650c2014-01-25 18:45:45 +000082bool SkWindow::handleInval(const SkRect* localR) {
83 SkIRect ir;
reed@android.com8a1c16f2008-12-17 15:59:43 +000084
reed@android.comf2b98d62010-12-20 18:26:13 +000085 if (localR) {
86 SkRect devR;
87 SkMatrix inverse;
88 if (!fMatrix.invert(&inverse)) {
89 return false;
90 }
91 fMatrix.mapRect(&devR, *localR);
92 devR.round(&ir);
93 } else {
reed@google.comf9bb7a82011-03-01 15:15:13 +000094 ir.set(0, 0,
reed@google.come1ca7052013-12-17 19:22:07 +000095 SkScalarRoundToInt(this->width()),
96 SkScalarRoundToInt(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +000097 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000098 fDirtyRgn.op(ir, SkRegion::kUnion_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +000099
rmistry@google.comd6176b02012-08-23 18:14:13 +0000100 this->onHandleInval(ir);
101 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102}
103
reed@android.comf2b98d62010-12-20 18:26:13 +0000104void SkWindow::forceInvalAll() {
reed@google.com261b8e22011-04-14 17:53:24 +0000105 fDirtyRgn.setRect(0, 0,
reed@google.come1ca7052013-12-17 19:22:07 +0000106 SkScalarCeilToInt(this->width()),
107 SkScalarCeilToInt(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000108}
109
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110#ifdef SK_SIMULATE_FAILED_MALLOC
111extern bool gEnableControlledThrow;
112#endif
113
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000114bool SkWindow::update(SkIRect* updateArea) {
115 if (!fDirtyRgn.isEmpty()) {
reed0397e9f2014-09-18 11:29:01 -0700116 SkAutoTUnref<SkSurface> surface(this->createSurface());
117 SkCanvas* canvas = surface->getCanvas();
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000118
119 canvas->clipRegion(fDirtyRgn);
joshualitt030dc842015-06-12 12:51:44 -0700120 if (updateArea) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000121 *updateArea = fDirtyRgn.getBounds();
joshualitt030dc842015-06-12 12:51:44 -0700122 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000124 SkAutoCanvasRestore acr(canvas, true);
125 canvas->concat(fMatrix);
reed@android.comf2b98d62010-12-20 18:26:13 +0000126
rmistry@google.comd6176b02012-08-23 18:14:13 +0000127 // empty this now, so we can correctly record any inval calls that
128 // might be made during the draw call.
129 fDirtyRgn.setEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000132 gEnableControlledThrow = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133#endif
134#ifdef SK_BUILD_FOR_WIN32
rmistry@google.comd6176b02012-08-23 18:14:13 +0000135 //try {
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000136 this->draw(canvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000137 //}
138 //catch (...) {
139 //}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140#else
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000141 this->draw(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142#endif
143#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000144 gEnableControlledThrow = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146
rmistry@google.comd6176b02012-08-23 18:14:13 +0000147 return true;
148 }
149 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150}
151
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000152bool SkWindow::handleChar(SkUnichar uni) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000153 if (this->onHandleChar(uni))
154 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155
rmistry@google.comd6176b02012-08-23 18:14:13 +0000156 SkView* focus = this->getFocusView();
halcanary96fcdcc2015-08-27 07:41:13 -0700157 if (focus == nullptr)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000158 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159
rmistry@google.comd6176b02012-08-23 18:14:13 +0000160 SkEvent evt(SK_EventType_Unichar);
161 evt.setFast32(uni);
162 return focus->doEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163}
164
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000165bool SkWindow::handleKey(SkKey key) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000166 if (key == kNONE_SkKey)
167 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168
rmistry@google.comd6176b02012-08-23 18:14:13 +0000169 if (this->onHandleKey(key))
170 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171
rmistry@google.comd6176b02012-08-23 18:14:13 +0000172 // send an event to the focus-view
173 {
174 SkView* focus = this->getFocusView();
halcanary96fcdcc2015-08-27 07:41:13 -0700175 if (focus == nullptr)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000176 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
rmistry@google.comd6176b02012-08-23 18:14:13 +0000178 SkEvent evt(SK_EventType_Key);
179 evt.setFast32(key);
180 if (focus->doEvent(evt))
181 return true;
182 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000184 if (key == kUp_SkKey || key == kDown_SkKey) {
halcanary96fcdcc2015-08-27 07:41:13 -0700185 if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == nullptr)
186 this->onSetFocusView(nullptr);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000187 return true;
188 }
189 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190}
191
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000192bool SkWindow::handleKeyUp(SkKey key) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 if (key == kNONE_SkKey)
194 return false;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000195
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 if (this->onHandleKeyUp(key))
197 return true;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000198
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 //send an event to the focus-view
200 {
201 SkView* focus = this->getFocusView();
halcanary96fcdcc2015-08-27 07:41:13 -0700202 if (focus == nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 focus = this;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000204
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 //should this one be the same?
206 SkEvent evt(SK_EventType_KeyUp);
207 evt.setFast32(key);
208 if (focus->doEvent(evt))
209 return true;
210 }
211 return false;
212}
213
yangsu@google.com654d72f2011-08-01 17:27:33 +0000214void SkWindow::addMenu(SkOSMenu* menu) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000215 *fMenus.append() = menu;
216 this->onAddMenu(menu);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217}
218
reed@android.com0ae6b242008-12-23 16:49:54 +0000219void SkWindow::setTitle(const char title[]) {
halcanary96fcdcc2015-08-27 07:41:13 -0700220 if (nullptr == title) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 title = "";
reed@android.com0ae6b242008-12-23 16:49:54 +0000222 }
223 fTitle.set(title);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 this->onSetTitle(title);
225}
226
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000227bool SkWindow::onEvent(const SkEvent& evt) {
228 if (evt.isType(SK_EventDelayInval)) {
229 for (SkRegion::Iterator iter(fDirtyRgn); !iter.done(); iter.next())
rmistry@google.comd6176b02012-08-23 18:14:13 +0000230 this->onHandleInval(iter.rect());
231 fWaitingOnInval = false;
232 return true;
233 }
234 return this->INHERITED::onEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235}
236
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000237bool SkWindow::onGetFocusView(SkView** focus) const {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000238 if (focus)
239 *focus = fFocusView;
240 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241}
242
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000243bool SkWindow::onSetFocusView(SkView* focus) {
244 if (fFocusView != focus) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000245 if (fFocusView)
246 fFocusView->onFocusChange(false);
247 fFocusView = focus;
248 if (focus)
249 focus->onFocusChange(true);
250 }
251 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252}
253
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000254void SkWindow::onHandleInval(const SkIRect&) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255}
256
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000257bool SkWindow::onHandleChar(SkUnichar) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000258 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259}
260
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000261bool SkWindow::onHandleKey(SkKey) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000262 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263}
264
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000265bool SkWindow::onHandleKeyUp(SkKey) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 return false;
267}
268
reed@google.com4d5c26d2013-01-08 16:17:50 +0000269bool SkWindow::handleClick(int x, int y, Click::State state, void *owner,
270 unsigned modifierKeys) {
271 return this->onDispatchClick(x, y, state, owner, modifierKeys);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000272}
273
Scroggod3aed392011-06-22 13:26:56 +0000274bool SkWindow::onDispatchClick(int x, int y, Click::State state,
reed@google.com4d5c26d2013-01-08 16:17:50 +0000275 void* owner, unsigned modifierKeys) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000276 bool handled = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277
Scroggod3aed392011-06-22 13:26:56 +0000278 // First, attempt to find an existing click with this owner.
279 int index = -1;
280 for (int i = 0; i < fClicks.count(); i++) {
281 if (owner == fClicks[i]->fOwner) {
282 index = i;
283 break;
284 }
285 }
286
rmistry@google.comd6176b02012-08-23 18:14:13 +0000287 switch (state) {
Scroggod3aed392011-06-22 13:26:56 +0000288 case Click::kDown_State: {
289 if (index != -1) {
290 delete fClicks[index];
291 fClicks.remove(index);
292 }
293 Click* click = this->findClickHandler(SkIntToScalar(x),
reed@google.com4d5c26d2013-01-08 16:17:50 +0000294 SkIntToScalar(y), modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000295
296 if (click) {
297 click->fOwner = owner;
298 *fClicks.append() = click;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000299 SkView::DoClickDown(click, x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000300 handled = true;
301 }
302 break;
303 }
304 case Click::kMoved_State:
305 if (index != -1) {
reed@google.com4d5c26d2013-01-08 16:17:50 +0000306 SkView::DoClickMoved(fClicks[index], x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000307 handled = true;
308 }
309 break;
310 case Click::kUp_State:
311 if (index != -1) {
reed@google.com4d5c26d2013-01-08 16:17:50 +0000312 SkView::DoClickUp(fClicks[index], x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000313 delete fClicks[index];
314 fClicks.remove(index);
315 handled = true;
316 }
317 break;
318 default:
319 // Do nothing
320 break;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000321 }
322 return handled;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323}
caryclarkc8fcafb2015-01-30 12:37:02 -0800324
325#if SK_SUPPORT_GPU
326
Brian Salomon8b3eca92015-10-09 16:54:48 -0400327#include "GrContext.h"
caryclarkc8fcafb2015-01-30 12:37:02 -0800328#include "gl/GrGLInterface.h"
329#include "gl/GrGLUtil.h"
330#include "SkGr.h"
331
332GrRenderTarget* SkWindow::renderTarget(const AttachmentInfo& attachmentInfo,
333 const GrGLInterface* interface, GrContext* grContext) {
334 GrBackendRenderTargetDesc desc;
335 desc.fWidth = SkScalarRoundToInt(this->width());
336 desc.fHeight = SkScalarRoundToInt(this->height());
brianosman856cc172016-03-01 07:19:11 -0800337 // TODO: Query the actual framebuffer for sRGB capable. However, to
338 // preserve old (fake-linear) behavior, we don't do this. Instead, rely
339 // on the flag (currently driven via 'C' mode in SampleApp).
brianosmana6359362016-03-21 06:55:37 -0700340 //
341 // Also, we may not have real sRGB support (ANGLE, in particular), so check for
342 // that, and fall back to L32:
brianosman2d1ee792016-05-05 12:24:31 -0700343 //
344 // ... and, if we're using a 10-bit/channel FB0, it doesn't do sRGB conversion on write,
345 // so pretend that it's non-sRGB 8888:
346 desc.fConfig =
347 grContext->caps()->srgbSupport() &&
348 SkImageInfoIsGammaCorrect(info()) &&
349 (attachmentInfo.fColorBits != 30)
350 ? kSkiaGamma8888_GrPixelConfig : kSkia8888_GrPixelConfig;
caryclarkc8fcafb2015-01-30 12:37:02 -0800351 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
352 desc.fSampleCnt = attachmentInfo.fSampleCount;
353 desc.fStencilBits = attachmentInfo.fStencilBits;
354 GrGLint buffer;
355 GR_GL_GetIntegerv(interface, GR_GL_FRAMEBUFFER_BINDING, &buffer);
356 desc.fRenderTargetHandle = buffer;
bsalomond309e7a2015-04-30 14:18:54 -0700357 return grContext->textureProvider()->wrapBackendRenderTarget(desc);
caryclarkc8fcafb2015-01-30 12:37:02 -0800358}
359
360#endif