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