|  |  | 
|  | /* | 
|  | * Copyright 2011 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #include "SkWindow.h" | 
|  | #include "SkCanvas.h" | 
|  | #include "SkDevice.h" | 
|  | #include "SkOSMenu.h" | 
|  | #include "SkSystemEventTypes.h" | 
|  | #include "SkTime.h" | 
|  |  | 
|  | #define SK_EventDelayInval "\xd" "n" "\xa" "l" | 
|  |  | 
|  | SkWindow::SkWindow() : fFocusView(NULL) { | 
|  | fClicks.reset(); | 
|  | fWaitingOnInval = false; | 
|  |  | 
|  | #ifdef SK_BUILD_FOR_WINCE | 
|  | fColorType = kRGB_565_SkColorType; | 
|  | #else | 
|  | fColorType = kN32_SkColorType; | 
|  | #endif | 
|  |  | 
|  | fMatrix.reset(); | 
|  | } | 
|  |  | 
|  | SkWindow::~SkWindow() { | 
|  | fClicks.deleteAll(); | 
|  | fMenus.deleteAll(); | 
|  | } | 
|  |  | 
|  | SkCanvas* SkWindow::createCanvas() { | 
|  | return new SkCanvas(this->getBitmap()); | 
|  | } | 
|  |  | 
|  | void SkWindow::setMatrix(const SkMatrix& matrix) { | 
|  | if (fMatrix != matrix) { | 
|  | fMatrix = matrix; | 
|  | this->inval(NULL); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkWindow::preConcat(const SkMatrix& matrix) { | 
|  | SkMatrix m; | 
|  | m.setConcat(fMatrix, matrix); | 
|  | this->setMatrix(m); | 
|  | } | 
|  |  | 
|  | void SkWindow::postConcat(const SkMatrix& matrix) { | 
|  | SkMatrix m; | 
|  | m.setConcat(matrix, fMatrix); | 
|  | this->setMatrix(m); | 
|  | } | 
|  |  | 
|  | void SkWindow::setColorType(SkColorType ct) { | 
|  | this->resize(fBitmap.width(), fBitmap.height(), ct); | 
|  | } | 
|  |  | 
|  | void SkWindow::resize(int width, int height, SkColorType ct) { | 
|  | if (ct == kUnknown_SkColorType) | 
|  | ct = fColorType; | 
|  |  | 
|  | if (width != fBitmap.width() || height != fBitmap.height() || ct != fColorType) { | 
|  | fColorType = ct; | 
|  | fBitmap.allocPixels(SkImageInfo::Make(width, height, | 
|  | ct, kPremul_SkAlphaType)); | 
|  |  | 
|  | this->setSize(SkIntToScalar(width), SkIntToScalar(height)); | 
|  | this->inval(NULL); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool SkWindow::handleInval(const SkRect* localR) { | 
|  | SkIRect ir; | 
|  |  | 
|  | if (localR) { | 
|  | SkRect devR; | 
|  | SkMatrix inverse; | 
|  | if (!fMatrix.invert(&inverse)) { | 
|  | return false; | 
|  | } | 
|  | fMatrix.mapRect(&devR, *localR); | 
|  | devR.round(&ir); | 
|  | } else { | 
|  | ir.set(0, 0, | 
|  | SkScalarRoundToInt(this->width()), | 
|  | SkScalarRoundToInt(this->height())); | 
|  | } | 
|  | fDirtyRgn.op(ir, SkRegion::kUnion_Op); | 
|  |  | 
|  | this->onHandleInval(ir); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void SkWindow::forceInvalAll() { | 
|  | fDirtyRgn.setRect(0, 0, | 
|  | SkScalarCeilToInt(this->width()), | 
|  | SkScalarCeilToInt(this->height())); | 
|  | } | 
|  |  | 
|  | #if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN) | 
|  | #include <windows.h> | 
|  | #include <gx.h> | 
|  | extern GXDisplayProperties gDisplayProps; | 
|  | #endif | 
|  |  | 
|  | #ifdef SK_SIMULATE_FAILED_MALLOC | 
|  | extern bool gEnableControlledThrow; | 
|  | #endif | 
|  |  | 
|  | bool SkWindow::update(SkIRect* updateArea) { | 
|  | if (!fDirtyRgn.isEmpty()) { | 
|  | SkBitmap bm = this->getBitmap(); | 
|  |  | 
|  | #if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN) | 
|  | char* buffer = (char*)GXBeginDraw(); | 
|  | SkASSERT(buffer); | 
|  |  | 
|  | RECT    rect; | 
|  | GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect); | 
|  | buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch; | 
|  |  | 
|  | bm.setPixels(buffer); | 
|  | #endif | 
|  |  | 
|  | SkAutoTUnref<SkCanvas> canvas(this->createCanvas()); | 
|  |  | 
|  | canvas->clipRegion(fDirtyRgn); | 
|  | if (updateArea) | 
|  | *updateArea = fDirtyRgn.getBounds(); | 
|  |  | 
|  | SkAutoCanvasRestore acr(canvas, true); | 
|  | canvas->concat(fMatrix); | 
|  |  | 
|  | // empty this now, so we can correctly record any inval calls that | 
|  | // might be made during the draw call. | 
|  | fDirtyRgn.setEmpty(); | 
|  |  | 
|  | #ifdef SK_SIMULATE_FAILED_MALLOC | 
|  | gEnableControlledThrow = true; | 
|  | #endif | 
|  | #ifdef SK_BUILD_FOR_WIN32 | 
|  | //try { | 
|  | this->draw(canvas); | 
|  | //} | 
|  | //catch (...) { | 
|  | //} | 
|  | #else | 
|  | this->draw(canvas); | 
|  | #endif | 
|  | #ifdef SK_SIMULATE_FAILED_MALLOC | 
|  | gEnableControlledThrow = false; | 
|  | #endif | 
|  |  | 
|  | #if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN) | 
|  | GXEndDraw(); | 
|  | #endif | 
|  |  | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SkWindow::handleChar(SkUnichar uni) { | 
|  | if (this->onHandleChar(uni)) | 
|  | return true; | 
|  |  | 
|  | SkView* focus = this->getFocusView(); | 
|  | if (focus == NULL) | 
|  | focus = this; | 
|  |  | 
|  | SkEvent evt(SK_EventType_Unichar); | 
|  | evt.setFast32(uni); | 
|  | return focus->doEvent(evt); | 
|  | } | 
|  |  | 
|  | bool SkWindow::handleKey(SkKey key) { | 
|  | if (key == kNONE_SkKey) | 
|  | return false; | 
|  |  | 
|  | if (this->onHandleKey(key)) | 
|  | return true; | 
|  |  | 
|  | // send an event to the focus-view | 
|  | { | 
|  | SkView* focus = this->getFocusView(); | 
|  | if (focus == NULL) | 
|  | focus = this; | 
|  |  | 
|  | SkEvent evt(SK_EventType_Key); | 
|  | evt.setFast32(key); | 
|  | if (focus->doEvent(evt)) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | if (key == kUp_SkKey || key == kDown_SkKey) { | 
|  | if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL) | 
|  | this->onSetFocusView(NULL); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SkWindow::handleKeyUp(SkKey key) { | 
|  | if (key == kNONE_SkKey) | 
|  | return false; | 
|  |  | 
|  | if (this->onHandleKeyUp(key)) | 
|  | return true; | 
|  |  | 
|  | //send an event to the focus-view | 
|  | { | 
|  | SkView* focus = this->getFocusView(); | 
|  | if (focus == NULL) | 
|  | focus = this; | 
|  |  | 
|  | //should this one be the same? | 
|  | SkEvent evt(SK_EventType_KeyUp); | 
|  | evt.setFast32(key); | 
|  | if (focus->doEvent(evt)) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void SkWindow::addMenu(SkOSMenu* menu) { | 
|  | *fMenus.append() = menu; | 
|  | this->onAddMenu(menu); | 
|  | } | 
|  |  | 
|  | void SkWindow::setTitle(const char title[]) { | 
|  | if (NULL == title) { | 
|  | title = ""; | 
|  | } | 
|  | fTitle.set(title); | 
|  | this->onSetTitle(title); | 
|  | } | 
|  |  | 
|  | bool SkWindow::onEvent(const SkEvent& evt) { | 
|  | if (evt.isType(SK_EventDelayInval)) { | 
|  | for (SkRegion::Iterator iter(fDirtyRgn); !iter.done(); iter.next()) | 
|  | this->onHandleInval(iter.rect()); | 
|  | fWaitingOnInval = false; | 
|  | return true; | 
|  | } | 
|  | return this->INHERITED::onEvent(evt); | 
|  | } | 
|  |  | 
|  | bool SkWindow::onGetFocusView(SkView** focus) const { | 
|  | if (focus) | 
|  | *focus = fFocusView; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool SkWindow::onSetFocusView(SkView* focus) { | 
|  | if (fFocusView != focus) { | 
|  | if (fFocusView) | 
|  | fFocusView->onFocusChange(false); | 
|  | fFocusView = focus; | 
|  | if (focus) | 
|  | focus->onFocusChange(true); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void SkWindow::onHandleInval(const SkIRect&) { | 
|  | } | 
|  |  | 
|  | bool SkWindow::onHandleChar(SkUnichar) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SkWindow::onHandleKey(SkKey) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SkWindow::onHandleKeyUp(SkKey) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SkWindow::handleClick(int x, int y, Click::State state, void *owner, | 
|  | unsigned modifierKeys) { | 
|  | return this->onDispatchClick(x, y, state, owner, modifierKeys); | 
|  | } | 
|  |  | 
|  | bool SkWindow::onDispatchClick(int x, int y, Click::State state, | 
|  | void* owner, unsigned modifierKeys) { | 
|  | bool handled = false; | 
|  |  | 
|  | // First, attempt to find an existing click with this owner. | 
|  | int index = -1; | 
|  | for (int i = 0; i < fClicks.count(); i++) { | 
|  | if (owner == fClicks[i]->fOwner) { | 
|  | index = i; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | switch (state) { | 
|  | case Click::kDown_State: { | 
|  | if (index != -1) { | 
|  | delete fClicks[index]; | 
|  | fClicks.remove(index); | 
|  | } | 
|  | Click* click = this->findClickHandler(SkIntToScalar(x), | 
|  | SkIntToScalar(y), modifierKeys); | 
|  |  | 
|  | if (click) { | 
|  | click->fOwner = owner; | 
|  | *fClicks.append() = click; | 
|  | SkView::DoClickDown(click, x, y, modifierKeys); | 
|  | handled = true; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case Click::kMoved_State: | 
|  | if (index != -1) { | 
|  | SkView::DoClickMoved(fClicks[index], x, y, modifierKeys); | 
|  | handled = true; | 
|  | } | 
|  | break; | 
|  | case Click::kUp_State: | 
|  | if (index != -1) { | 
|  | SkView::DoClickUp(fClicks[index], x, y, modifierKeys); | 
|  | delete fClicks[index]; | 
|  | fClicks.remove(index); | 
|  | handled = true; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | // Do nothing | 
|  | break; | 
|  | } | 
|  | return handled; | 
|  | } |