Home | History | Annotate | Download | only in views
      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 "SkView.h"
      9 #include "SkCanvas.h"
     10 #include "SkDOM.h"
     11 
     12 static inline uint32_t SkSetClearShift(uint32_t bits, bool cond, unsigned shift) {
     13     SkASSERT((int)cond == 0 || (int)cond == 1);
     14     return (bits & ~(1 << shift)) | ((int)cond << shift);
     15 }
     16 
     17 ////////////////////////////////////////////////////////////////////////
     18 
     19 SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags)) {
     20     fWidth = fHeight = 0;
     21     fLoc.set(0, 0);
     22     fParent = fFirstChild = fNextSibling = fPrevSibling = nullptr;
     23     fMatrix.setIdentity();
     24     fContainsFocus = 0;
     25 }
     26 
     27 SkView::~SkView() {
     28     this->detachAllChildren();
     29 }
     30 
     31 void SkView::setFlags(uint32_t flags) {
     32     SkASSERT((flags & ~kAllFlagMasks) == 0);
     33 
     34     uint32_t diff = fFlags ^ flags;
     35 
     36     if (diff & kVisible_Mask)
     37         this->inval(nullptr);
     38 
     39     fFlags = SkToU8(flags);
     40 
     41     if (diff & kVisible_Mask) {
     42         this->inval(nullptr);
     43     }
     44 }
     45 
     46 void SkView::setVisibleP(bool pred) {
     47     this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift));
     48 }
     49 
     50 void SkView::setEnabledP(bool pred) {
     51     this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift));
     52 }
     53 
     54 void SkView::setFocusableP(bool pred) {
     55     this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift));
     56 }
     57 
     58 void SkView::setClipToBounds(bool pred) {
     59     this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift));
     60 }
     61 
     62 void SkView::setSize(SkScalar width, SkScalar height) {
     63     width = SkMaxScalar(0, width);
     64     height = SkMaxScalar(0, height);
     65 
     66     if (fWidth != width || fHeight != height)
     67     {
     68         this->inval(nullptr);
     69         fWidth = width;
     70         fHeight = height;
     71         this->inval(nullptr);
     72         this->onSizeChange();
     73         this->invokeLayout();
     74     }
     75 }
     76 
     77 void SkView::setLoc(SkScalar x, SkScalar y) {
     78     if (fLoc.fX != x || fLoc.fY != y) {
     79         this->inval(nullptr);
     80         fLoc.set(x, y);
     81         this->inval(nullptr);
     82     }
     83 }
     84 
     85 void SkView::offset(SkScalar dx, SkScalar dy) {
     86     if (dx || dy)
     87         this->setLoc(fLoc.fX + dx, fLoc.fY + dy);
     88 }
     89 
     90 void SkView::setLocalMatrix(const SkMatrix& matrix) {
     91     this->inval(nullptr);
     92     fMatrix = matrix;
     93     this->inval(nullptr);
     94 }
     95 
     96 void SkView::draw(SkCanvas* canvas) {
     97     if (fWidth && fHeight && this->isVisible()) {
     98         SkRect    r;
     99         r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
    100         if (this->isClipToBounds() && canvas->quickReject(r)) {
    101             return;
    102         }
    103 
    104         SkAutoCanvasRestore    as(canvas, true);
    105 
    106         if (this->isClipToBounds()) {
    107             canvas->clipRect(r);
    108         }
    109 
    110         canvas->translate(fLoc.fX, fLoc.fY);
    111         canvas->concat(fMatrix);
    112 
    113         if (fParent) {
    114             fParent->beforeChild(this, canvas);
    115         }
    116 
    117         int sc = canvas->save();
    118         this->onDraw(canvas);
    119         canvas->restoreToCount(sc);
    120 
    121         if (fParent) {
    122             fParent->afterChild(this, canvas);
    123         }
    124 
    125         B2FIter    iter(this);
    126         SkView*    child;
    127 
    128         SkCanvas* childCanvas = this->beforeChildren(canvas);
    129 
    130         while ((child = iter.next()) != nullptr)
    131             child->draw(childCanvas);
    132 
    133         this->afterChildren(canvas);
    134     }
    135 }
    136 
    137 void SkView::inval(SkRect* rect) {
    138     SkView*    view = this;
    139     SkRect storage;
    140 
    141     for (;;) {
    142         if (!view->isVisible()) {
    143             return;
    144         }
    145         if (view->isClipToBounds()) {
    146             SkRect bounds;
    147             view->getLocalBounds(&bounds);
    148             if (rect && !bounds.intersect(*rect)) {
    149                 return;
    150             }
    151             storage = bounds;
    152             rect = &storage;
    153         }
    154         if (view->handleInval(rect)) {
    155             return;
    156         }
    157 
    158         SkView* parent = view->fParent;
    159         if (parent == nullptr) {
    160             return;
    161         }
    162 
    163         if (rect) {
    164             rect->offset(view->fLoc.fX, view->fLoc.fY);
    165         }
    166         view = parent;
    167     }
    168 }
    169 
    170 ////////////////////////////////////////////////////////////////////////////
    171 
    172 bool SkView::setFocusView(SkView* fv) {
    173     SkView* view = this;
    174 
    175     do {
    176         if (view->onSetFocusView(fv)) {
    177             return true;
    178         }
    179     } while ((view = view->fParent) != nullptr);
    180     return false;
    181 }
    182 
    183 SkView* SkView::getFocusView() const {
    184     SkView*         focus = nullptr;
    185     const SkView*   view = this;
    186     do {
    187         if (view->onGetFocusView(&focus)) {
    188             break;
    189         }
    190     } while ((view = view->fParent) != nullptr);
    191     return focus;
    192 }
    193 
    194 bool SkView::hasFocus() const {
    195     return this == this->getFocusView();
    196 }
    197 
    198 bool SkView::acceptFocus() {
    199     return this->isFocusable() && this->setFocusView(this);
    200 }
    201 
    202 /*
    203     Try to give focus to this view, or its children
    204 */
    205 SkView* SkView::acceptFocus(FocusDirection dir) {
    206     if (dir == kNext_FocusDirection) {
    207         if (this->acceptFocus()) {
    208             return this;
    209         }
    210         B2FIter    iter(this);
    211         SkView*    child, *focus;
    212         while ((child = iter.next()) != nullptr) {
    213             if ((focus = child->acceptFocus(dir)) != nullptr) {
    214                 return focus;
    215             }
    216         }
    217     } else { // prev
    218         F2BIter    iter(this);
    219         SkView*    child, *focus;
    220         while ((child = iter.next()) != nullptr) {
    221             if ((focus = child->acceptFocus(dir)) != nullptr) {
    222                 return focus;
    223             }
    224         }
    225         if (this->acceptFocus()) {
    226             return this;
    227         }
    228     }
    229     return nullptr;
    230 }
    231 
    232 SkView* SkView::moveFocus(FocusDirection dir) {
    233     SkView* focus = this->getFocusView();
    234 
    235     if (focus == nullptr) {    // start with the root
    236         focus = this;
    237         while (focus->fParent) {
    238             focus = focus->fParent;
    239         }
    240     }
    241 
    242     SkView* child, *parent;
    243 
    244     if (dir == kNext_FocusDirection) {
    245         parent = focus;
    246         child = focus->fFirstChild;
    247         if (child)
    248             goto FIRST_CHILD;
    249         else
    250             goto NEXT_SIB;
    251 
    252         do {
    253             while (child != parent->fFirstChild) {
    254     FIRST_CHILD:
    255                 if ((focus = child->acceptFocus(dir)) != nullptr)
    256                     return focus;
    257                 child = child->fNextSibling;
    258             }
    259     NEXT_SIB:
    260             child = parent->fNextSibling;
    261             parent = parent->fParent;
    262         } while (parent != nullptr);
    263     } else {    // prevfocus
    264         parent = focus->fParent;
    265         if (parent == nullptr) {    // we're the root
    266             return focus->acceptFocus(dir);
    267         } else {
    268             child = focus;
    269             while (parent) {
    270                 while (child != parent->fFirstChild) {
    271                     child = child->fPrevSibling;
    272                     if ((focus = child->acceptFocus(dir)) != nullptr) {
    273                         return focus;
    274                     }
    275                 }
    276                 if (parent->acceptFocus()) {
    277                     return parent;
    278                 }
    279                 child = parent;
    280                 parent = parent->fParent;
    281             }
    282         }
    283     }
    284     return nullptr;
    285 }
    286 
    287 void SkView::onFocusChange(bool gainFocusP) {
    288     this->inval(nullptr);
    289 }
    290 
    291 ////////////////////////////////////////////////////////////////////////////
    292 
    293 SkView::Click::Click(SkView* target) {
    294     SkASSERT(target);
    295     fTargetID = target->getSinkID();
    296     fType = nullptr;
    297     fWeOwnTheType = false;
    298     fOwner = nullptr;
    299 }
    300 
    301 SkView::Click::~Click() {
    302     this->resetType();
    303 }
    304 
    305 void SkView::Click::resetType() {
    306     if (fWeOwnTheType) {
    307         sk_free(fType);
    308         fWeOwnTheType = false;
    309     }
    310     fType = nullptr;
    311 }
    312 
    313 bool SkView::Click::isType(const char type[]) const {
    314     const char* t = fType;
    315 
    316     if (type == t) {
    317         return true;
    318     }
    319     if (type == nullptr) {
    320         type = "";
    321     }
    322     if (t == nullptr) {
    323         t = "";
    324     }
    325     return !strcmp(t, type);
    326 }
    327 
    328 void SkView::Click::setType(const char type[]) {
    329     this->resetType();
    330     fType = (char*)type;
    331 }
    332 
    333 void SkView::Click::copyType(const char type[]) {
    334     if (fType != type) {
    335         this->resetType();
    336         if (type) {
    337             size_t len = strlen(type) + 1;
    338             fType = (char*)sk_malloc_throw(len);
    339             memcpy(fType, type, len);
    340             fWeOwnTheType = true;
    341         }
    342     }
    343 }
    344 
    345 SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y, unsigned modi) {
    346     if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
    347         return nullptr;
    348     }
    349 
    350     if (this->onSendClickToChildren(x, y, modi)) {
    351         F2BIter    iter(this);
    352         SkView*    child;
    353 
    354         while ((child = iter.next()) != nullptr) {
    355             SkPoint p;
    356 #if 0
    357             if (!child->globalToLocal(x, y, &p)) {
    358                 continue;
    359             }
    360 #else
    361             // the above seems broken, so just respecting fLoc for now <reed>
    362             p.set(x - child->fLoc.x(), y - child->fLoc.y());
    363 #endif
    364 
    365             Click* click = child->findClickHandler(p.fX, p.fY, modi);
    366 
    367             if (click) {
    368                 return click;
    369             }
    370         }
    371     }
    372 
    373     return this->onFindClickHandler(x, y, modi);
    374 }
    375 
    376 void SkView::DoClickDown(Click* click, int x, int y, unsigned modi) {
    377     SkASSERT(click);
    378 
    379     SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
    380     if (nullptr == target) {
    381         return;
    382     }
    383 
    384     click->fIOrig.set(x, y);
    385     click->fICurr = click->fIPrev = click->fIOrig;
    386 
    387     click->fOrig.iset(x, y);
    388     if (!target->globalToLocal(&click->fOrig)) {
    389         // no history to let us recover from this failure
    390         return;
    391     }
    392     click->fPrev = click->fCurr = click->fOrig;
    393 
    394     click->fState = Click::kDown_State;
    395     click->fModifierKeys = modi;
    396     target->onClick(click);
    397 }
    398 
    399 void SkView::DoClickMoved(Click* click, int x, int y, unsigned modi) {
    400     SkASSERT(click);
    401 
    402     SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
    403     if (nullptr == target) {
    404         return;
    405     }
    406 
    407     click->fIPrev = click->fICurr;
    408     click->fICurr.set(x, y);
    409 
    410     click->fPrev = click->fCurr;
    411     click->fCurr.iset(x, y);
    412     if (!target->globalToLocal(&click->fCurr)) {
    413         // on failure pretend the mouse didn't move
    414         click->fCurr = click->fPrev;
    415     }
    416 
    417     click->fState = Click::kMoved_State;
    418     click->fModifierKeys = modi;
    419     target->onClick(click);
    420 }
    421 
    422 void SkView::DoClickUp(Click* click, int x, int y, unsigned modi) {
    423     SkASSERT(click);
    424 
    425     SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
    426     if (nullptr == target) {
    427         return;
    428     }
    429 
    430     click->fIPrev = click->fICurr;
    431     click->fICurr.set(x, y);
    432 
    433     click->fPrev = click->fCurr;
    434     click->fCurr.iset(x, y);
    435     if (!target->globalToLocal(&click->fCurr)) {
    436         // on failure pretend the mouse didn't move
    437         click->fCurr = click->fPrev;
    438     }
    439 
    440     click->fState = Click::kUp_State;
    441     click->fModifierKeys = modi;
    442     target->onClick(click);
    443 }
    444 
    445 //////////////////////////////////////////////////////////////////////
    446 
    447 void SkView::invokeLayout() {
    448     SkView::Layout* layout = this->getLayout();
    449 
    450     if (layout) {
    451         layout->layoutChildren(this);
    452     }
    453 }
    454 
    455 void SkView::onDraw(SkCanvas* canvas) {
    456     Artist* artist = this->getArtist();
    457 
    458     if (artist) {
    459         artist->draw(this, canvas);
    460     }
    461 }
    462 
    463 void SkView::onSizeChange() {}
    464 
    465 bool SkView::onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) {
    466     return true;
    467 }
    468 
    469 SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) {
    470     return nullptr;
    471 }
    472 
    473 bool SkView::onClick(Click*) {
    474     return false;
    475 }
    476 
    477 bool SkView::handleInval(const SkRect*) {
    478     return false;
    479 }
    480 
    481 //////////////////////////////////////////////////////////////////////
    482 
    483 void SkView::getLocalBounds(SkRect* bounds) const {
    484     if (bounds) {
    485         bounds->set(0, 0, fWidth, fHeight);
    486     }
    487 }
    488 
    489 //////////////////////////////////////////////////////////////////////
    490 //////////////////////////////////////////////////////////////////////
    491 
    492 void SkView::detachFromParent_NoLayout() {
    493     this->validate();
    494     if (fParent == nullptr) {
    495         return;
    496     }
    497 
    498     if (fContainsFocus) {
    499         (void)this->setFocusView(nullptr);
    500     }
    501 
    502     this->inval(nullptr);
    503 
    504     SkView* next = nullptr;
    505 
    506     if (fNextSibling != this) {   // do we have any siblings
    507         fNextSibling->fPrevSibling = fPrevSibling;
    508         fPrevSibling->fNextSibling = fNextSibling;
    509         next = fNextSibling;
    510     }
    511 
    512     if (fParent->fFirstChild == this) {
    513         fParent->fFirstChild = next;
    514     }
    515 
    516     fParent = fNextSibling = fPrevSibling = nullptr;
    517 
    518     this->validate();
    519     this->unref();
    520 }
    521 
    522 void SkView::detachFromParent() {
    523     this->validate();
    524     SkView* parent = fParent;
    525 
    526     if (parent) {
    527         this->detachFromParent_NoLayout();
    528         parent->invokeLayout();
    529     }
    530 }
    531 
    532 SkView* SkView::attachChildToBack(SkView* child) {
    533     this->validate();
    534     SkASSERT(child != this);
    535 
    536     if (child == nullptr || fFirstChild == child)
    537         goto DONE;
    538 
    539     child->ref();
    540     child->detachFromParent_NoLayout();
    541 
    542     if (fFirstChild == nullptr) {
    543         child->fNextSibling = child;
    544         child->fPrevSibling = child;
    545     } else {
    546         child->fNextSibling = fFirstChild;
    547         child->fPrevSibling = fFirstChild->fPrevSibling;
    548         fFirstChild->fPrevSibling->fNextSibling = child;
    549         fFirstChild->fPrevSibling = child;
    550     }
    551 
    552     fFirstChild = child;
    553     child->fParent = this;
    554     child->inval(nullptr);
    555 
    556     this->validate();
    557     this->invokeLayout();
    558 DONE:
    559     return child;
    560 }
    561 
    562 SkView* SkView::attachChildToFront(SkView* child) {
    563     this->validate();
    564     SkASSERT(child != this);
    565 
    566     if (child == nullptr || (fFirstChild && fFirstChild->fPrevSibling == child))
    567         goto DONE;
    568 
    569     child->ref();
    570     child->detachFromParent_NoLayout();
    571 
    572     if (fFirstChild == nullptr) {
    573         fFirstChild = child;
    574         child->fNextSibling = child;
    575         child->fPrevSibling = child;
    576     } else {
    577         child->fNextSibling = fFirstChild;
    578         child->fPrevSibling = fFirstChild->fPrevSibling;
    579         fFirstChild->fPrevSibling->fNextSibling = child;
    580         fFirstChild->fPrevSibling = child;
    581     }
    582 
    583     child->fParent = this;
    584     child->inval(nullptr);
    585 
    586     this->validate();
    587     this->invokeLayout();
    588 DONE:
    589     return child;
    590 }
    591 
    592 void SkView::detachAllChildren() {
    593     this->validate();
    594     while (fFirstChild)
    595         fFirstChild->detachFromParent_NoLayout();
    596 }
    597 
    598 void SkView::localToGlobal(SkMatrix* matrix) const {
    599     if (matrix) {
    600         matrix->reset();
    601         const SkView* view = this;
    602         while (view)
    603         {
    604             matrix->preConcat(view->getLocalMatrix());
    605             matrix->preTranslate(-view->fLoc.fX, -view->fLoc.fY);
    606             view = view->fParent;
    607         }
    608     }
    609 }
    610 
    611 bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const {
    612     if (local) {
    613         SkMatrix m;
    614         this->localToGlobal(&m);
    615         if (!m.invert(&m)) {
    616             return false;
    617         }
    618         SkPoint p;
    619         m.mapXY(x, y, &p);
    620         local->set(p.fX, p.fY);
    621     }
    622 
    623     return true;
    624 }
    625 
    626 //////////////////////////////////////////////////////////////////
    627 
    628 /*    Even if the subclass overrides onInflate, they should always be
    629     sure to call the inherited method, so that we get called.
    630 */
    631 void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node) {
    632     SkScalar x, y;
    633 
    634     x = this->locX();
    635     y = this->locY();
    636     (void)dom.findScalar(node, "x", &x);
    637     (void)dom.findScalar(node, "y", &y);
    638     this->setLoc(x, y);
    639 
    640     x = this->width();
    641     y = this->height();
    642     (void)dom.findScalar(node, "width", &x);
    643     (void)dom.findScalar(node, "height", &y);
    644     this->setSize(x, y);
    645 
    646     // inflate the flags
    647 
    648     static const char* gFlagNames[] = {
    649         "visible", "enabled", "focusable", "flexH", "flexV"
    650     };
    651     SkASSERT(SK_ARRAY_COUNT(gFlagNames) == kFlagShiftCount);
    652 
    653     bool     b;
    654     uint32_t flags = this->getFlags();
    655     for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++) {
    656         if (dom.findBool(node, gFlagNames[i], &b)) {
    657             flags = SkSetClearShift(flags, b, i);
    658         }
    659     }
    660     this->setFlags(flags);
    661 }
    662 
    663 void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node) {
    664     this->onInflate(dom, node);
    665 }
    666 
    667 //////////////////////////////////////////////////////////////////
    668 
    669 SkView* SkView::sendEventToParents(const SkEvent& evt) {
    670     SkView* parent = fParent;
    671 
    672     while (parent) {
    673         if (parent->doEvent(evt)) {
    674             return parent;
    675         }
    676         parent = parent->fParent;
    677     }
    678     return nullptr;
    679 }
    680 
    681 SkView* SkView::sendQueryToParents(SkEvent* evt) {
    682     SkView* parent = fParent;
    683 
    684     while (parent) {
    685         if (parent->doQuery(evt)) {
    686             return parent;
    687         }
    688         parent = parent->fParent;
    689     }
    690     return nullptr;
    691 }
    692 
    693 //////////////////////////////////////////////////////////////////
    694 //////////////////////////////////////////////////////////////////
    695 
    696 SkView::F2BIter::F2BIter(const SkView* parent) {
    697     fFirstChild = parent ? parent->fFirstChild : nullptr;
    698     fChild = fFirstChild ? fFirstChild->fPrevSibling : nullptr;
    699 }
    700 
    701 SkView* SkView::F2BIter::next() {
    702     SkView* curr = fChild;
    703 
    704     if (fChild) {
    705         if (fChild == fFirstChild) {
    706             fChild = nullptr;
    707         } else {
    708             fChild = fChild->fPrevSibling;
    709         }
    710     }
    711     return curr;
    712 }
    713 
    714 SkView::B2FIter::B2FIter(const SkView* parent) {
    715     fFirstChild = parent ? parent->fFirstChild : nullptr;
    716     fChild = fFirstChild;
    717 }
    718 
    719 SkView* SkView::B2FIter::next() {
    720     SkView* curr = fChild;
    721 
    722     if (fChild) {
    723         SkView* next = fChild->fNextSibling;
    724         if (next == fFirstChild)
    725             next = nullptr;
    726         fChild = next;
    727     }
    728     return curr;
    729 }
    730 
    731 //////////////////////////////////////////////////////////////////
    732 //////////////////////////////////////////////////////////////////
    733 
    734 #ifdef SK_DEBUG
    735 
    736 void SkView::validate() const {
    737 //    SkASSERT(this->getRefCnt() > 0 && this->getRefCnt() < 100);
    738     if (fParent) {
    739         SkASSERT(fNextSibling);
    740         SkASSERT(fPrevSibling);
    741     } else {
    742         bool nextNull = nullptr == fNextSibling;
    743         bool prevNull = nullptr == fNextSibling;
    744         SkASSERT(nextNull == prevNull);
    745     }
    746 }
    747 
    748 static inline void show_if_nonzero(const char name[], SkScalar value) {
    749     if (value) {
    750         SkDebugf("%s=\"%g\"", name, value/65536.);
    751     }
    752 }
    753 
    754 static void tab(int level) {
    755     for (int i = 0; i < level; i++) {
    756         SkDebugf("    ");
    757     }
    758 }
    759 
    760 static void dumpview(const SkView* view, int level, bool recurse) {
    761     tab(level);
    762 
    763     SkDebugf("<view");
    764     show_if_nonzero(" x", view->locX());
    765     show_if_nonzero(" y", view->locY());
    766     show_if_nonzero(" width", view->width());
    767     show_if_nonzero(" height", view->height());
    768 
    769     if (recurse) {
    770         SkView::B2FIter    iter(view);
    771         SkView*            child;
    772         bool            noChildren = true;
    773 
    774         while ((child = iter.next()) != nullptr) {
    775             if (noChildren) {
    776                 SkDebugf(">\n");
    777             }
    778             noChildren = false;
    779             dumpview(child, level + 1, true);
    780         }
    781 
    782         if (!noChildren) {
    783             tab(level);
    784             SkDebugf("</view>\n");
    785         } else {
    786             goto ONELINER;
    787         }
    788     } else {
    789     ONELINER:
    790         SkDebugf(" />\n");
    791     }
    792 }
    793 
    794 void SkView::dump(bool recurse) const {
    795     dumpview(this, 0, recurse);
    796 }
    797 
    798 #endif
    799