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 33SkSurface* SkWindow::createSurface() { 34 const SkBitmap& bm = this->getBitmap(); 35 return SkSurface::NewRasterDirect(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, SkColorProfileType pt) { 70 const SkImageInfo& info = fBitmap.info(); 71 this->resize(SkImageInfo::Make(info.width(), info.height(), ct, kPremul_SkAlphaType, pt)); 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 SkAutoTUnref<SkSurface> surface(this->createSurface()); 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 324GrRenderTarget* SkWindow::renderTarget(const AttachmentInfo& attachmentInfo, 325 const GrGLInterface* interface, GrContext* grContext) { 326 GrBackendRenderTargetDesc desc; 327 desc.fWidth = SkScalarRoundToInt(this->width()); 328 desc.fHeight = SkScalarRoundToInt(this->height()); 329 desc.fConfig = kSkia8888_GrPixelConfig; 330 desc.fOrigin = kBottomLeft_GrSurfaceOrigin; 331 desc.fSampleCnt = attachmentInfo.fSampleCount; 332 desc.fStencilBits = attachmentInfo.fStencilBits; 333 GrGLint buffer; 334 GR_GL_GetIntegerv(interface, GR_GL_FRAMEBUFFER_BINDING, &buffer); 335 desc.fRenderTargetHandle = buffer; 336 return grContext->textureProvider()->wrapBackendRenderTarget(desc); 337} 338 339#endif 340