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