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