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
12SkViewInflate::SkViewInflate() : fIDs(kMinIDStrAlloc), fStrings(kMinIDStrAlloc)
13{
14}
15
16SkViewInflate::~SkViewInflate()
17{
18}
19
20void 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
53void 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
61SkView* 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
101SkView* 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
109SkView* SkViewInflate::findViewByID(const char id[]) const
110{
111	SkASSERT(id);
112	SkView* view;
113	return fIDs.find(id, &view) ? view : NULL;
114}
115
116SkView* 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
123void 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
133void 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
147