blob: 9165c08ebe04831818b81c08deccf82a7e6a6a2d [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
brianosmanb109b8c2016-06-16 13:03:24 -070070void SkWindow::setColorType(SkColorType ct, sk_sp<SkColorSpace> cs) {
reeda34be682016-02-15 07:48:35 -080071 const SkImageInfo& info = fBitmap.info();
brianosmanb109b8c2016-06-16 13:03:24 -070072 this->resize(SkImageInfo::Make(info.width(), info.height(), ct, kPremul_SkAlphaType, cs));
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) |
brianosmanb109b8c2016-06-16 13:03:24 -070078 (SkColorAndColorSpaceAreGammaCorrect(ct, cs.get())
79 ? SkSurfaceProps::kGammaCorrect_Flag : 0);
brianosman898235c2016-04-06 07:38:23 -070080 this->setSurfaceProps(SkSurfaceProps(flags, props.pixelGeometry()));
reed@android.com8a1c16f2008-12-17 15:59:43 +000081}
82
tfarina@chromium.org658650c2014-01-25 18:45:45 +000083bool SkWindow::handleInval(const SkRect* localR) {
84 SkIRect ir;
reed@android.com8a1c16f2008-12-17 15:59:43 +000085
reed@android.comf2b98d62010-12-20 18:26:13 +000086 if (localR) {
87 SkRect devR;
88 SkMatrix inverse;
89 if (!fMatrix.invert(&inverse)) {
90 return false;
91 }
92 fMatrix.mapRect(&devR, *localR);
93 devR.round(&ir);
94 } else {
reed@google.comf9bb7a82011-03-01 15:15:13 +000095 ir.set(0, 0,
reed@google.come1ca7052013-12-17 19:22:07 +000096 SkScalarRoundToInt(this->width()),
97 SkScalarRoundToInt(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +000098 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000099 fDirtyRgn.op(ir, SkRegion::kUnion_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100
rmistry@google.comd6176b02012-08-23 18:14:13 +0000101 this->onHandleInval(ir);
102 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103}
104
reed@android.comf2b98d62010-12-20 18:26:13 +0000105void SkWindow::forceInvalAll() {
reed@google.com261b8e22011-04-14 17:53:24 +0000106 fDirtyRgn.setRect(0, 0,
reed@google.come1ca7052013-12-17 19:22:07 +0000107 SkScalarCeilToInt(this->width()),
108 SkScalarCeilToInt(this->height()));
reed@android.comf2b98d62010-12-20 18:26:13 +0000109}
110
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111#ifdef SK_SIMULATE_FAILED_MALLOC
112extern bool gEnableControlledThrow;
113#endif
114
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000115bool SkWindow::update(SkIRect* updateArea) {
116 if (!fDirtyRgn.isEmpty()) {
reed0397e9f2014-09-18 11:29:01 -0700117 SkAutoTUnref<SkSurface> surface(this->createSurface());
118 SkCanvas* canvas = surface->getCanvas();
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000119
120 canvas->clipRegion(fDirtyRgn);
joshualitt030dc842015-06-12 12:51:44 -0700121 if (updateArea) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000122 *updateArea = fDirtyRgn.getBounds();
joshualitt030dc842015-06-12 12:51:44 -0700123 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000125 SkAutoCanvasRestore acr(canvas, true);
126 canvas->concat(fMatrix);
reed@android.comf2b98d62010-12-20 18:26:13 +0000127
rmistry@google.comd6176b02012-08-23 18:14:13 +0000128 // empty this now, so we can correctly record any inval calls that
129 // might be made during the draw call.
130 fDirtyRgn.setEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000133 gEnableControlledThrow = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134#endif
135#ifdef SK_BUILD_FOR_WIN32
rmistry@google.comd6176b02012-08-23 18:14:13 +0000136 //try {
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000137 this->draw(canvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000138 //}
139 //catch (...) {
140 //}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141#else
robertphillips@google.comce9dce02012-10-02 12:32:22 +0000142 this->draw(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143#endif
144#ifdef SK_SIMULATE_FAILED_MALLOC
rmistry@google.comd6176b02012-08-23 18:14:13 +0000145 gEnableControlledThrow = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147
rmistry@google.comd6176b02012-08-23 18:14:13 +0000148 return true;
149 }
150 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151}
152
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000153bool SkWindow::handleChar(SkUnichar uni) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000154 if (this->onHandleChar(uni))
155 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156
rmistry@google.comd6176b02012-08-23 18:14:13 +0000157 SkView* focus = this->getFocusView();
halcanary96fcdcc2015-08-27 07:41:13 -0700158 if (focus == nullptr)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000159 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160
rmistry@google.comd6176b02012-08-23 18:14:13 +0000161 SkEvent evt(SK_EventType_Unichar);
162 evt.setFast32(uni);
163 return focus->doEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164}
165
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000166bool SkWindow::handleKey(SkKey key) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000167 if (key == kNONE_SkKey)
168 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
rmistry@google.comd6176b02012-08-23 18:14:13 +0000170 if (this->onHandleKey(key))
171 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172
rmistry@google.comd6176b02012-08-23 18:14:13 +0000173 // send an event to the focus-view
174 {
175 SkView* focus = this->getFocusView();
halcanary96fcdcc2015-08-27 07:41:13 -0700176 if (focus == nullptr)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000177 focus = this;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
rmistry@google.comd6176b02012-08-23 18:14:13 +0000179 SkEvent evt(SK_EventType_Key);
180 evt.setFast32(key);
181 if (focus->doEvent(evt))
182 return true;
183 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000185 if (key == kUp_SkKey || key == kDown_SkKey) {
halcanary96fcdcc2015-08-27 07:41:13 -0700186 if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == nullptr)
187 this->onSetFocusView(nullptr);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000188 return true;
189 }
190 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191}
192
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000193bool SkWindow::handleKeyUp(SkKey key) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 if (key == kNONE_SkKey)
195 return false;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000196
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 if (this->onHandleKeyUp(key))
198 return true;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000199
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 //send an event to the focus-view
201 {
202 SkView* focus = this->getFocusView();
halcanary96fcdcc2015-08-27 07:41:13 -0700203 if (focus == nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 focus = this;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000205
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 //should this one be the same?
207 SkEvent evt(SK_EventType_KeyUp);
208 evt.setFast32(key);
209 if (focus->doEvent(evt))
210 return true;
211 }
212 return false;
213}
214
yangsu@google.com654d72f2011-08-01 17:27:33 +0000215void SkWindow::addMenu(SkOSMenu* menu) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000216 *fMenus.append() = menu;
217 this->onAddMenu(menu);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218}
219
reed@android.com0ae6b242008-12-23 16:49:54 +0000220void SkWindow::setTitle(const char title[]) {
halcanary96fcdcc2015-08-27 07:41:13 -0700221 if (nullptr == title) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 title = "";
reed@android.com0ae6b242008-12-23 16:49:54 +0000223 }
224 fTitle.set(title);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 this->onSetTitle(title);
226}
227
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000228bool SkWindow::onEvent(const SkEvent& evt) {
229 if (evt.isType(SK_EventDelayInval)) {
230 for (SkRegion::Iterator iter(fDirtyRgn); !iter.done(); iter.next())
rmistry@google.comd6176b02012-08-23 18:14:13 +0000231 this->onHandleInval(iter.rect());
232 fWaitingOnInval = false;
233 return true;
234 }
235 return this->INHERITED::onEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236}
237
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000238bool SkWindow::onGetFocusView(SkView** focus) const {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000239 if (focus)
240 *focus = fFocusView;
241 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242}
243
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000244bool SkWindow::onSetFocusView(SkView* focus) {
245 if (fFocusView != focus) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000246 if (fFocusView)
247 fFocusView->onFocusChange(false);
248 fFocusView = focus;
249 if (focus)
250 focus->onFocusChange(true);
251 }
252 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253}
254
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000255void SkWindow::onHandleInval(const SkIRect&) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256}
257
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000258bool SkWindow::onHandleChar(SkUnichar) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000259 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260}
261
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000262bool SkWindow::onHandleKey(SkKey) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000263 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264}
265
tfarina@chromium.org658650c2014-01-25 18:45:45 +0000266bool SkWindow::onHandleKeyUp(SkKey) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 return false;
268}
269
reed@google.com4d5c26d2013-01-08 16:17:50 +0000270bool SkWindow::handleClick(int x, int y, Click::State state, void *owner,
271 unsigned modifierKeys) {
272 return this->onDispatchClick(x, y, state, owner, modifierKeys);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000273}
274
Scroggod3aed392011-06-22 13:26:56 +0000275bool SkWindow::onDispatchClick(int x, int y, Click::State state,
reed@google.com4d5c26d2013-01-08 16:17:50 +0000276 void* owner, unsigned modifierKeys) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000277 bool handled = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278
Scroggod3aed392011-06-22 13:26:56 +0000279 // First, attempt to find an existing click with this owner.
280 int index = -1;
281 for (int i = 0; i < fClicks.count(); i++) {
282 if (owner == fClicks[i]->fOwner) {
283 index = i;
284 break;
285 }
286 }
287
rmistry@google.comd6176b02012-08-23 18:14:13 +0000288 switch (state) {
Scroggod3aed392011-06-22 13:26:56 +0000289 case Click::kDown_State: {
290 if (index != -1) {
291 delete fClicks[index];
292 fClicks.remove(index);
293 }
294 Click* click = this->findClickHandler(SkIntToScalar(x),
reed@google.com4d5c26d2013-01-08 16:17:50 +0000295 SkIntToScalar(y), modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000296
297 if (click) {
298 click->fOwner = owner;
299 *fClicks.append() = click;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000300 SkView::DoClickDown(click, x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000301 handled = true;
302 }
303 break;
304 }
305 case Click::kMoved_State:
306 if (index != -1) {
reed@google.com4d5c26d2013-01-08 16:17:50 +0000307 SkView::DoClickMoved(fClicks[index], x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000308 handled = true;
309 }
310 break;
311 case Click::kUp_State:
312 if (index != -1) {
reed@google.com4d5c26d2013-01-08 16:17:50 +0000313 SkView::DoClickUp(fClicks[index], x, y, modifierKeys);
Scroggod3aed392011-06-22 13:26:56 +0000314 delete fClicks[index];
315 fClicks.remove(index);
316 handled = true;
317 }
318 break;
319 default:
320 // Do nothing
321 break;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000322 }
323 return handled;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324}
caryclarkc8fcafb2015-01-30 12:37:02 -0800325
326#if SK_SUPPORT_GPU
327
Brian Salomon8b3eca92015-10-09 16:54:48 -0400328#include "GrContext.h"
caryclarkc8fcafb2015-01-30 12:37:02 -0800329#include "gl/GrGLInterface.h"
330#include "gl/GrGLUtil.h"
331#include "SkGr.h"
332
333GrRenderTarget* SkWindow::renderTarget(const AttachmentInfo& attachmentInfo,
334 const GrGLInterface* interface, GrContext* grContext) {
335 GrBackendRenderTargetDesc desc;
336 desc.fWidth = SkScalarRoundToInt(this->width());
337 desc.fHeight = SkScalarRoundToInt(this->height());
brianosman856cc172016-03-01 07:19:11 -0800338 // TODO: Query the actual framebuffer for sRGB capable. However, to
339 // preserve old (fake-linear) behavior, we don't do this. Instead, rely
340 // on the flag (currently driven via 'C' mode in SampleApp).
brianosmana6359362016-03-21 06:55:37 -0700341 //
342 // Also, we may not have real sRGB support (ANGLE, in particular), so check for
343 // that, and fall back to L32:
brianosman2d1ee792016-05-05 12:24:31 -0700344 //
345 // ... and, if we're using a 10-bit/channel FB0, it doesn't do sRGB conversion on write,
346 // so pretend that it's non-sRGB 8888:
347 desc.fConfig =
348 grContext->caps()->srgbSupport() &&
349 SkImageInfoIsGammaCorrect(info()) &&
350 (attachmentInfo.fColorBits != 30)
351 ? kSkiaGamma8888_GrPixelConfig : kSkia8888_GrPixelConfig;
caryclarkc8fcafb2015-01-30 12:37:02 -0800352 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
353 desc.fSampleCnt = attachmentInfo.fSampleCount;
354 desc.fStencilBits = attachmentInfo.fStencilBits;
355 GrGLint buffer;
356 GR_GL_GetIntegerv(interface, GR_GL_FRAMEBUFFER_BINDING, &buffer);
357 desc.fRenderTargetHandle = buffer;
bsalomond309e7a2015-04-30 14:18:54 -0700358 return grContext->textureProvider()->wrapBackendRenderTarget(desc);
caryclarkc8fcafb2015-01-30 12:37:02 -0800359}
360
361#endif