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