diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/views/SkView.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/views/SkView.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,843 @@ + +/* + * 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 "SkView.h" +#include "SkCanvas.h" + +//////////////////////////////////////////////////////////////////////// + +SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags)) +{ + fWidth = fHeight = 0; + fLoc.set(0, 0); + fParent = fFirstChild = fNextSibling = fPrevSibling = NULL; + fMatrix.setIdentity(); + fContainsFocus = 0; +} + +SkView::~SkView() +{ + this->detachAllChildren(); +} + +void SkView::setFlags(uint32_t flags) +{ + SkASSERT((flags & ~kAllFlagMasks) == 0); + + uint32_t diff = fFlags ^ flags; + + if (diff & kVisible_Mask) + this->inval(NULL); + + fFlags = SkToU8(flags); + + if (diff & kVisible_Mask) + { + this->inval(NULL); + } +} + +void SkView::setVisibleP(bool pred) +{ + this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift)); +} + +void SkView::setEnabledP(bool pred) +{ + this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift)); +} + +void SkView::setFocusableP(bool pred) +{ + this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift)); +} + +void SkView::setClipToBounds(bool pred) { + this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift)); +} + +void SkView::setSize(SkScalar width, SkScalar height) +{ + width = SkMaxScalar(0, width); + height = SkMaxScalar(0, height); + + if (fWidth != width || fHeight != height) + { + this->inval(NULL); + fWidth = width; + fHeight = height; + this->inval(NULL); + this->onSizeChange(); + this->invokeLayout(); + } +} + +void SkView::setLoc(SkScalar x, SkScalar y) +{ + if (fLoc.fX != x || fLoc.fY != y) + { + this->inval(NULL); + fLoc.set(x, y); + this->inval(NULL); + } +} + +void SkView::offset(SkScalar dx, SkScalar dy) +{ + if (dx || dy) + this->setLoc(fLoc.fX + dx, fLoc.fY + dy); +} + +void SkView::setLocalMatrix(const SkMatrix& matrix) +{ + this->inval(NULL); + fMatrix = matrix; + this->inval(NULL); +} + +void SkView::draw(SkCanvas* canvas) +{ + if (fWidth && fHeight && this->isVisible()) + { + SkRect r; + r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight); + if (this->isClipToBounds() && + canvas->quickReject(r)) { + return; + } + + SkAutoCanvasRestore as(canvas, true); + + if (this->isClipToBounds()) { + canvas->clipRect(r); + } + + canvas->translate(fLoc.fX, fLoc.fY); + canvas->concat(fMatrix); + + if (fParent) { + fParent->beforeChild(this, canvas); + } + + int sc = canvas->save(); + this->onDraw(canvas); + canvas->restoreToCount(sc); + + if (fParent) { + fParent->afterChild(this, canvas); + } + + B2FIter iter(this); + SkView* child; + + SkCanvas* childCanvas = this->beforeChildren(canvas); + + while ((child = iter.next()) != NULL) + child->draw(childCanvas); + + this->afterChildren(canvas); + } +} + +void SkView::inval(SkRect* rect) { + SkView* view = this; + SkRect storage; + + for (;;) { + if (!view->isVisible()) { + return; + } + if (view->isClipToBounds()) { + SkRect bounds; + view->getLocalBounds(&bounds); + if (rect && !bounds.intersect(*rect)) { + return; + } + storage = bounds; + rect = &storage; + } + if (view->handleInval(rect)) { + return; + } + + SkView* parent = view->fParent; + if (parent == NULL) { + return; + } + + if (rect) { + rect->offset(view->fLoc.fX, view->fLoc.fY); + } + view = parent; + } +} + +//////////////////////////////////////////////////////////////////////////// + +bool SkView::setFocusView(SkView* fv) +{ + SkView* view = this; + + do { + if (view->onSetFocusView(fv)) + return true; + } while ((view = view->fParent) != NULL); + return false; +} + +SkView* SkView::getFocusView() const +{ + SkView* focus = NULL; + const SkView* view = this; + do { + if (view->onGetFocusView(&focus)) + break; + } while ((view = view->fParent) != NULL); + return focus; +} + +bool SkView::hasFocus() const +{ + return this == this->getFocusView(); +} + +bool SkView::acceptFocus() +{ + return this->isFocusable() && this->setFocusView(this); +} + +/* + Try to give focus to this view, or its children +*/ +SkView* SkView::acceptFocus(FocusDirection dir) +{ + if (dir == kNext_FocusDirection) + { + if (this->acceptFocus()) + return this; + + B2FIter iter(this); + SkView* child, *focus; + while ((child = iter.next()) != NULL) + if ((focus = child->acceptFocus(dir)) != NULL) + return focus; + } + else // prev + { + F2BIter iter(this); + SkView* child, *focus; + while ((child = iter.next()) != NULL) + if ((focus = child->acceptFocus(dir)) != NULL) + return focus; + + if (this->acceptFocus()) + return this; + } + + return NULL; +} + +SkView* SkView::moveFocus(FocusDirection dir) +{ + SkView* focus = this->getFocusView(); + + if (focus == NULL) + { // start with the root + focus = this; + while (focus->fParent) + focus = focus->fParent; + } + + SkView* child, *parent; + + if (dir == kNext_FocusDirection) + { + parent = focus; + child = focus->fFirstChild; + if (child) + goto FIRST_CHILD; + else + goto NEXT_SIB; + + do { + while (child != parent->fFirstChild) + { + FIRST_CHILD: + if ((focus = child->acceptFocus(dir)) != NULL) + return focus; + child = child->fNextSibling; + } + NEXT_SIB: + child = parent->fNextSibling; + parent = parent->fParent; + } while (parent != NULL); + } + else // prevfocus + { + parent = focus->fParent; + if (parent == NULL) // we're the root + return focus->acceptFocus(dir); + else + { + child = focus; + while (parent) + { + while (child != parent->fFirstChild) + { + child = child->fPrevSibling; + if ((focus = child->acceptFocus(dir)) != NULL) + return focus; + } + if (parent->acceptFocus()) + return parent; + + child = parent; + parent = parent->fParent; + } + } + } + return NULL; +} + +void SkView::onFocusChange(bool gainFocusP) +{ + this->inval(NULL); +} + +//////////////////////////////////////////////////////////////////////////// + +SkView::Click::Click(SkView* target) +{ + SkASSERT(target); + fTargetID = target->getSinkID(); + fType = NULL; + fWeOwnTheType = false; + fOwner = NULL; +} + +SkView::Click::~Click() +{ + this->resetType(); +} + +void SkView::Click::resetType() +{ + if (fWeOwnTheType) + { + sk_free(fType); + fWeOwnTheType = false; + } + fType = NULL; +} + +bool SkView::Click::isType(const char type[]) const +{ + const char* t = fType; + + if (type == t) + return true; + + if (type == NULL) + type = ""; + if (t == NULL) + t = ""; + return !strcmp(t, type); +} + +void SkView::Click::setType(const char type[]) +{ + this->resetType(); + fType = (char*)type; +} + +void SkView::Click::copyType(const char type[]) +{ + if (fType != type) + { + this->resetType(); + if (type) + { + size_t len = strlen(type) + 1; + fType = (char*)sk_malloc_throw(len); + memcpy(fType, type, len); + fWeOwnTheType = true; + } + } +} + +SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y, unsigned modi) { + if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) { + return NULL; + } + + if (this->onSendClickToChildren(x, y, modi)) { + F2BIter iter(this); + SkView* child; + + while ((child = iter.next()) != NULL) + { + SkPoint p; + if (!child->globalToLocal(x, y, &p)) { + continue; + } + + Click* click = child->findClickHandler(p.fX, p.fY, modi); + + if (click) { + return click; + } + } + } + + return this->onFindClickHandler(x, y, modi); +} + +void SkView::DoClickDown(Click* click, int x, int y, unsigned modi) +{ + SkASSERT(click); + + SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID); + if (NULL == target) { + return; + } + + click->fIOrig.set(x, y); + click->fICurr = click->fIPrev = click->fIOrig; + + click->fOrig.iset(x, y); + if (!target->globalToLocal(&click->fOrig)) { + // no history to let us recover from this failure + return; + } + click->fPrev = click->fCurr = click->fOrig; + + click->fState = Click::kDown_State; + click->fModifierKeys = modi; + target->onClick(click); +} + +void SkView::DoClickMoved(Click* click, int x, int y, unsigned modi) +{ + SkASSERT(click); + + SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID); + if (NULL == target) { + return; + } + + click->fIPrev = click->fICurr; + click->fICurr.set(x, y); + + click->fPrev = click->fCurr; + click->fCurr.iset(x, y); + if (!target->globalToLocal(&click->fCurr)) { + // on failure pretend the mouse didn't move + click->fCurr = click->fPrev; + } + + click->fState = Click::kMoved_State; + click->fModifierKeys = modi; + target->onClick(click); +} + +void SkView::DoClickUp(Click* click, int x, int y, unsigned modi) +{ + SkASSERT(click); + + SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID); + if (NULL == target) { + return; + } + + click->fIPrev = click->fICurr; + click->fICurr.set(x, y); + + click->fPrev = click->fCurr; + click->fCurr.iset(x, y); + if (!target->globalToLocal(&click->fCurr)) { + // on failure pretend the mouse didn't move + click->fCurr = click->fPrev; + } + + click->fState = Click::kUp_State; + click->fModifierKeys = modi; + target->onClick(click); +} + +////////////////////////////////////////////////////////////////////// + +void SkView::invokeLayout() { + SkView::Layout* layout = this->getLayout(); + + if (layout) { + layout->layoutChildren(this); + } +} + +void SkView::onDraw(SkCanvas* canvas) { + Artist* artist = this->getArtist(); + + if (artist) { + artist->draw(this, canvas); + } +} + +void SkView::onSizeChange() {} + +bool SkView::onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) { + return true; +} + +SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) { + return NULL; +} + +bool SkView::onClick(Click*) { + return false; +} + +bool SkView::handleInval(const SkRect*) { + return false; +} + +////////////////////////////////////////////////////////////////////// + +void SkView::getLocalBounds(SkRect* bounds) const { + if (bounds) { + bounds->set(0, 0, fWidth, fHeight); + } +} + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +void SkView::detachFromParent_NoLayout() { + this->validate(); + if (fParent == NULL) { + return; + } + + if (fContainsFocus) { + (void)this->setFocusView(NULL); + } + + this->inval(NULL); + + SkView* next = NULL; + + if (fNextSibling != this) { // do we have any siblings + fNextSibling->fPrevSibling = fPrevSibling; + fPrevSibling->fNextSibling = fNextSibling; + next = fNextSibling; + } + + if (fParent->fFirstChild == this) { + fParent->fFirstChild = next; + } + + fParent = fNextSibling = fPrevSibling = NULL; + + this->validate(); + this->unref(); +} + +void SkView::detachFromParent() { + this->validate(); + SkView* parent = fParent; + + if (parent) { + this->detachFromParent_NoLayout(); + parent->invokeLayout(); + } +} + +SkView* SkView::attachChildToBack(SkView* child) { + this->validate(); + SkASSERT(child != this); + + if (child == NULL || fFirstChild == child) + goto DONE; + + child->ref(); + child->detachFromParent_NoLayout(); + + if (fFirstChild == NULL) { + child->fNextSibling = child; + child->fPrevSibling = child; + } else { + child->fNextSibling = fFirstChild; + child->fPrevSibling = fFirstChild->fPrevSibling; + fFirstChild->fPrevSibling->fNextSibling = child; + fFirstChild->fPrevSibling = child; + } + + fFirstChild = child; + child->fParent = this; + child->inval(NULL); + + this->validate(); + this->invokeLayout(); +DONE: + return child; +} + +SkView* SkView::attachChildToFront(SkView* child) { + this->validate(); + SkASSERT(child != this); + + if (child == NULL || (fFirstChild && fFirstChild->fPrevSibling == child)) + goto DONE; + + child->ref(); + child->detachFromParent_NoLayout(); + + if (fFirstChild == NULL) { + fFirstChild = child; + child->fNextSibling = child; + child->fPrevSibling = child; + } else { + child->fNextSibling = fFirstChild; + child->fPrevSibling = fFirstChild->fPrevSibling; + fFirstChild->fPrevSibling->fNextSibling = child; + fFirstChild->fPrevSibling = child; + } + + child->fParent = this; + child->inval(NULL); + + this->validate(); + this->invokeLayout(); +DONE: + return child; +} + +void SkView::detachAllChildren() { + this->validate(); + while (fFirstChild) + fFirstChild->detachFromParent_NoLayout(); +} + +void SkView::localToGlobal(SkMatrix* matrix) const { + if (matrix) { + matrix->reset(); + const SkView* view = this; + while (view) + { + matrix->preConcat(view->getLocalMatrix()); + matrix->preTranslate(-view->fLoc.fX, -view->fLoc.fY); + view = view->fParent; + } + } +} +bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const +{ + SkASSERT(this); + + if (NULL != local) { + SkMatrix m; + this->localToGlobal(&m); + if (!m.invert(&m)) { + return false; + } + SkPoint p; + m.mapXY(x, y, &p); + local->set(p.fX, p.fY); + } + + return true; +} + +////////////////////////////////////////////////////////////////// + +/* Even if the subclass overrides onInflate, they should always be + sure to call the inherited method, so that we get called. +*/ +void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node) { + SkScalar x, y; + + x = this->locX(); + y = this->locY(); + (void)dom.findScalar(node, "x", &x); + (void)dom.findScalar(node, "y", &y); + this->setLoc(x, y); + + x = this->width(); + y = this->height(); + (void)dom.findScalar(node, "width", &x); + (void)dom.findScalar(node, "height", &y); + this->setSize(x, y); + + // inflate the flags + + static const char* gFlagNames[] = { + "visible", "enabled", "focusable", "flexH", "flexV" + }; + SkASSERT(SK_ARRAY_COUNT(gFlagNames) == kFlagShiftCount); + + bool b; + uint32_t flags = this->getFlags(); + for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++) + if (dom.findBool(node, gFlagNames[i], &b)) + flags = SkSetClearShift(flags, b, i); + this->setFlags(flags); +} + +void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node) { + this->onInflate(dom, node); +} + +void SkView::onPostInflate(const SkTDict&) { + // override in subclass as needed +} + +void SkView::postInflate(const SkTDict& dict) { + this->onPostInflate(dict); + + B2FIter iter(this); + SkView* child; + while ((child = iter.next()) != NULL) + child->postInflate(dict); +} + +////////////////////////////////////////////////////////////////// + +SkView* SkView::sendEventToParents(const SkEvent& evt) { + SkView* parent = fParent; + + while (parent) { + if (parent->doEvent(evt)) { + return parent; + } + parent = parent->fParent; + } + return NULL; +} + +SkView* SkView::sendQueryToParents(SkEvent* evt) { + SkView* parent = fParent; + + while (parent) { + if (parent->doQuery(evt)) { + return parent; + } + parent = parent->fParent; + } + return NULL; +} + +////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////// + +SkView::F2BIter::F2BIter(const SkView* parent) { + fFirstChild = parent ? parent->fFirstChild : NULL; + fChild = fFirstChild ? fFirstChild->fPrevSibling : NULL; +} + +SkView* SkView::F2BIter::next() { + SkView* curr = fChild; + + if (fChild) { + if (fChild == fFirstChild) { + fChild = NULL; + } else { + fChild = fChild->fPrevSibling; + } + } + return curr; +} + +SkView::B2FIter::B2FIter(const SkView* parent) { + fFirstChild = parent ? parent->fFirstChild : NULL; + fChild = fFirstChild; +} + +SkView* SkView::B2FIter::next() { + SkView* curr = fChild; + + if (fChild) { + SkView* next = fChild->fNextSibling; + if (next == fFirstChild) + next = NULL; + fChild = next; + } + return curr; +} + +////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG + +void SkView::validate() const { +// SkASSERT(this->getRefCnt() > 0 && this->getRefCnt() < 100); + if (fParent) { + SkASSERT(fNextSibling); + SkASSERT(fPrevSibling); + } else { + bool nextNull = NULL == fNextSibling; + bool prevNull = NULL == fNextSibling; + SkASSERT(nextNull == prevNull); + } +} + +static inline void show_if_nonzero(const char name[], SkScalar value) +{ + if (value) + SkDebugf("%s=\"%g\"", name, value/65536.); +} + +static void tab(int level) +{ + for (int i = 0; i < level; i++) + SkDebugf(" "); +} + +static void dumpview(const SkView* view, int level, bool recurse) +{ + tab(level); + + SkDebugf("locX()); + show_if_nonzero(" y", view->locY()); + show_if_nonzero(" width", view->width()); + show_if_nonzero(" height", view->height()); + + if (recurse) + { + SkView::B2FIter iter(view); + SkView* child; + bool noChildren = true; + + while ((child = iter.next()) != NULL) + { + if (noChildren) + SkDebugf(">\n"); + noChildren = false; + dumpview(child, level + 1, true); + } + + if (!noChildren) + { + tab(level); + SkDebugf("\n"); + } + else + goto ONELINER; + } + else + { + ONELINER: + SkDebugf(" />\n"); + } +} + +void SkView::dump(bool recurse) const +{ + dumpview(this, 0, recurse); +} + +#endif