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 "SkViewInflate.h"
9 #include "SkView.h"
10 #include <stdio.h>
11 
SkViewInflate()12 SkViewInflate::SkViewInflate() : fIDs(kMinIDStrAlloc), fStrings(kMinIDStrAlloc)
13 {
14 }
15 
~SkViewInflate()16 SkViewInflate::~SkViewInflate()
17 {
18 }
19 
rInflate(const SkDOM & dom,const SkDOM::Node * node,SkView * parent)20 void SkViewInflate::rInflate(const SkDOM& dom, const SkDOM::Node* node, SkView* parent)
21 {
22     const char* str = dom.findAttr(node, "id");
23     if (str)
24         fIDs.set(str, parent);
25 
26     const SkDOM::Node* child = dom.getFirstChild(node);
27     while (child)
28     {
29         SkView* view = this->createView(dom, child);
30         if (view)
31         {
32             this->rInflate(dom, child, view);
33             parent->attachChildToFront(view)->unref();
34         }
35         else
36         {
37             const char* name = dom.getName(child);
38             const char* target;
39 
40             if (!strcmp(name, "listenTo") && (target = dom.findAttr(child, "target")) != NULL)
41                 this->addIDStr(&fListenTo, parent, target);
42 
43             if (!strcmp(name, "broadcastTo") && (target = dom.findAttr(child, "target")) != NULL)
44                 this->addIDStr(&fBroadcastTo, parent, target);
45         }
46         child = dom.getNextSibling(child);
47     }
48 
49     parent->setVisibleP(true);
50     this->inflateView(parent, dom, node);
51 }
52 
inflateView(SkView * view,const SkDOM & dom,const SkDOM::Node * node)53 void SkViewInflate::inflateView(SkView* view, const SkDOM& dom, const SkDOM::Node* node)
54 {
55     // called after all of view's children have been instantiated.
56     // this may be overridden by a subclass, to load in layout or other helpers
57     // they should call through to us (INHERITED) before or after their patch
58     view->inflate(dom, node);
59 }
60 
inflate(const SkDOM & dom,const SkDOM::Node * node,SkView * root)61 SkView* SkViewInflate::inflate(const SkDOM& dom, const SkDOM::Node* node, SkView* root)
62 {
63     fIDs.reset();
64 
65     if (root == NULL)
66     {
67         root = this->createView(dom, node);
68         if (root == NULL)
69         {
70             printf("createView returned NULL on <%s>\n", dom.getName(node));
71             return NULL;
72         }
73     }
74     this->rInflate(dom, node, root);
75 
76     // resolve listeners and broadcasters
77     {
78         SkView*            target;
79         const IDStr*    iter = fListenTo.begin();
80         const IDStr*    stop = fListenTo.end();
81         for (; iter < stop; iter++)
82         {
83             if (fIDs.find(iter->fStr, &target))
84                 target->addListenerID(iter->fView->getSinkID());
85         }
86 
87         iter = fBroadcastTo.begin();
88         stop = fBroadcastTo.end();
89         for (; iter < stop; iter++)
90         {
91             if (fIDs.find(iter->fStr, &target))
92                 iter->fView->addListenerID(target->getSinkID());
93         }
94     }
95 
96     // now that the tree is built, give everyone a shot at the ID dict
97     root->postInflate(fIDs);
98     return root;
99 }
100 
inflate(const char xml[],size_t len,SkView * root)101 SkView* SkViewInflate::inflate(const char xml[], size_t len, SkView* root)
102 {
103     SkDOM                dom;
104     const SkDOM::Node*    node = dom.build(xml, len);
105 
106     return node ? this->inflate(dom, node, root) : NULL;
107 }
108 
findViewByID(const char id[]) const109 SkView* SkViewInflate::findViewByID(const char id[]) const
110 {
111     SkASSERT(id);
112     SkView* view;
113     return fIDs.find(id, &view) ? view : NULL;
114 }
115 
createView(const SkDOM & dom,const SkDOM::Node * node)116 SkView* SkViewInflate::createView(const SkDOM& dom, const SkDOM::Node* node)
117 {
118     if (!strcmp(dom.getName(node), "view"))
119         return new SkView;
120     return NULL;
121 }
122 
addIDStr(SkTDArray<IDStr> * list,SkView * view,const char * str)123 void SkViewInflate::addIDStr(SkTDArray<IDStr>* list, SkView* view, const char* str)
124 {
125     size_t len = strlen(str) + 1;
126     IDStr* pair = list->append();
127     pair->fView = view;
128     pair->fStr = (char*)fStrings.alloc(len, SkChunkAlloc::kThrow_AllocFailType);
129     memcpy(pair->fStr, str, len);
130 }
131 
132 #ifdef SK_DEBUG
dump() const133 void SkViewInflate::dump() const
134 {
135     const IDStr* iter = fListenTo.begin();
136     const IDStr* stop = fListenTo.end();
137     for (; iter < stop; iter++)
138         SkDebugf("inflate: listenTo(\"%s\")\n", iter->fStr);
139 
140     iter = fBroadcastTo.begin();
141     stop = fBroadcastTo.end();
142     for (; iter < stop; iter++)
143         SkDebugf("inflate: broadcastFrom(\"%s\")\n", iter->fStr);
144 }
145 #endif
146