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
12static 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
19SkView::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
27SkView::~SkView() {
28    this->detachAllChildren();
29}
30
31void 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
46void SkView::setVisibleP(bool pred) {
47    this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift));
48}
49
50void SkView::setEnabledP(bool pred) {
51    this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift));
52}
53
54void SkView::setFocusableP(bool pred) {
55    this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift));
56}
57
58void SkView::setClipToBounds(bool pred) {
59    this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift));
60}
61
62void 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
77void 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
85void SkView::offset(SkScalar dx, SkScalar dy) {
86    if (dx || dy)
87        this->setLoc(fLoc.fX + dx, fLoc.fY + dy);
88}
89
90void SkView::setLocalMatrix(const SkMatrix& matrix) {
91    this->inval(nullptr);
92    fMatrix = matrix;
93    this->inval(nullptr);
94}
95
96void 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
137void 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
172bool 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
183SkView* 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
194bool SkView::hasFocus() const {
195    return this == this->getFocusView();
196}
197
198bool SkView::acceptFocus() {
199    return this->isFocusable() && this->setFocusView(this);
200}
201
202/*
203    Try to give focus to this view, or its children
204*/
205SkView* 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
232SkView* 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
287void SkView::onFocusChange(bool gainFocusP) {
288    this->inval(nullptr);
289}
290
291////////////////////////////////////////////////////////////////////////////
292
293SkView::Click::Click(SkView* target) {
294    SkASSERT(target);
295    fTargetID = target->getSinkID();
296    fType = nullptr;
297    fWeOwnTheType = false;
298    fOwner = nullptr;
299}
300
301SkView::Click::~Click() {
302    this->resetType();
303}
304
305void SkView::Click::resetType() {
306    if (fWeOwnTheType) {
307        sk_free(fType);
308        fWeOwnTheType = false;
309    }
310    fType = nullptr;
311}
312
313bool 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
328void SkView::Click::setType(const char type[]) {
329    this->resetType();
330    fType = (char*)type;
331}
332
333void 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
345SkView::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
376void 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
399void 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
422void 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
447void SkView::invokeLayout() {
448    SkView::Layout* layout = this->getLayout();
449
450    if (layout) {
451        layout->layoutChildren(this);
452    }
453}
454
455void SkView::onDraw(SkCanvas* canvas) {
456    Artist* artist = this->getArtist();
457
458    if (artist) {
459        artist->draw(this, canvas);
460    }
461}
462
463void SkView::onSizeChange() {}
464
465bool SkView::onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) {
466    return true;
467}
468
469SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) {
470    return nullptr;
471}
472
473bool SkView::onClick(Click*) {
474    return false;
475}
476
477bool SkView::handleInval(const SkRect*) {
478    return false;
479}
480
481//////////////////////////////////////////////////////////////////////
482
483void SkView::getLocalBounds(SkRect* bounds) const {
484    if (bounds) {
485        bounds->set(0, 0, fWidth, fHeight);
486    }
487}
488
489//////////////////////////////////////////////////////////////////////
490//////////////////////////////////////////////////////////////////////
491
492void 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
522void SkView::detachFromParent() {
523    this->validate();
524    SkView* parent = fParent;
525
526    if (parent) {
527        this->detachFromParent_NoLayout();
528        parent->invokeLayout();
529    }
530}
531
532SkView* 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();
558DONE:
559    return child;
560}
561
562SkView* 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();
588DONE:
589    return child;
590}
591
592void SkView::detachAllChildren() {
593    this->validate();
594    while (fFirstChild)
595        fFirstChild->detachFromParent_NoLayout();
596}
597
598void 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
611bool 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*/
631void 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
663void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node) {
664    this->onInflate(dom, node);
665}
666
667//////////////////////////////////////////////////////////////////
668
669SkView* 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
681SkView* 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
696SkView::F2BIter::F2BIter(const SkView* parent) {
697    fFirstChild = parent ? parent->fFirstChild : nullptr;
698    fChild = fFirstChild ? fFirstChild->fPrevSibling : nullptr;
699}
700
701SkView* 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
714SkView::B2FIter::B2FIter(const SkView* parent) {
715    fFirstChild = parent ? parent->fFirstChild : nullptr;
716    fChild = fFirstChild;
717}
718
719SkView* 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
736void 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
748static inline void show_if_nonzero(const char name[], SkScalar value) {
749    if (value) {
750        SkDebugf("%s=\"%g\"", name, value/65536.);
751    }
752}
753
754static void tab(int level) {
755    for (int i = 0; i < level; i++) {
756        SkDebugf("    ");
757    }
758}
759
760static 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
794void SkView::dump(bool recurse) const {
795    dumpview(this, 0, recurse);
796}
797
798#endif
799