1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkViewInflate.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkView.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <stdio.h>
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkViewInflate::SkViewInflate() : fIDs(kMinIDStrAlloc), fStrings(kMinIDStrAlloc)
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkViewInflate::~SkViewInflate()
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkViewInflate::rInflate(const SkDOM& dom, const SkDOM::Node* node, SkView* parent)
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
22d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    const char* str = dom.findAttr(node, "id");
23d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    if (str)
24d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        fIDs.set(str, parent);
25d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
26d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    const SkDOM::Node* child = dom.getFirstChild(node);
27d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    while (child)
28d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    {
29d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        SkView* view = this->createView(dom, child);
30d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        if (view)
31d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        {
32d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            this->rInflate(dom, child, view);
33d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            parent->attachChildToFront(view)->unref();
34d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        }
35d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        else
36d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        {
37d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            const char* name = dom.getName(child);
38d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            const char* target;
39d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
40d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            if (!strcmp(name, "listenTo") && (target = dom.findAttr(child, "target")) != NULL)
41d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                this->addIDStr(&fListenTo, parent, target);
42d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
43d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            if (!strcmp(name, "broadcastTo") && (target = dom.findAttr(child, "target")) != NULL)
44d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                this->addIDStr(&fBroadcastTo, parent, target);
45d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        }
46d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        child = dom.getNextSibling(child);
47d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    }
48d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
49d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    parent->setVisibleP(true);
50d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    this->inflateView(parent, dom, node);
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkViewInflate::inflateView(SkView* view, const SkDOM& dom, const SkDOM::Node* node)
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
55d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // called after all of view's children have been instantiated.
56d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // this may be overridden by a subclass, to load in layout or other helpers
57d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // they should call through to us (INHERITED) before or after their patch
58d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    view->inflate(dom, node);
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkView* SkViewInflate::inflate(const SkDOM& dom, const SkDOM::Node* node, SkView* root)
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
63d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    fIDs.reset();
64d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
65d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    if (root == NULL)
66d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    {
67d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        root = this->createView(dom, node);
68d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        if (root == NULL)
69d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        {
70d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            printf("createView returned NULL on <%s>\n", dom.getName(node));
71d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            return NULL;
72d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        }
73d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    }
74d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    this->rInflate(dom, node, root);
75d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
76d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // resolve listeners and broadcasters
77d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    {
78d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        SkView*            target;
79d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        const IDStr*    iter = fListenTo.begin();
80d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        const IDStr*    stop = fListenTo.end();
81d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        for (; iter < stop; iter++)
82d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        {
83d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            if (fIDs.find(iter->fStr, &target))
84d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                target->addListenerID(iter->fView->getSinkID());
85d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        }
86d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
87d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        iter = fBroadcastTo.begin();
88d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        stop = fBroadcastTo.end();
89d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        for (; iter < stop; iter++)
90d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        {
91d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            if (fIDs.find(iter->fStr, &target))
92d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                iter->fView->addListenerID(target->getSinkID());
93d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        }
94d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    }
95d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
96d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // now that the tree is built, give everyone a shot at the ID dict
97d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    root->postInflate(fIDs);
98d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    return root;
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkView* SkViewInflate::inflate(const char xml[], size_t len, SkView* root)
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
103d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    SkDOM                dom;
104d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    const SkDOM::Node*    node = dom.build(xml, len);
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
106d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    return node ? this->inflate(dom, node, root) : NULL;
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkView* SkViewInflate::findViewByID(const char id[]) const
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
111d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    SkASSERT(id);
112d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    SkView* view;
113d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    return fIDs.find(id, &view) ? view : NULL;
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkView* SkViewInflate::createView(const SkDOM& dom, const SkDOM::Node* node)
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
118d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    if (!strcmp(dom.getName(node), "view"))
119d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        return new SkView;
120d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    return NULL;
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkViewInflate::addIDStr(SkTDArray<IDStr>* list, SkView* view, const char* str)
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
125d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    size_t len = strlen(str) + 1;
126d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    IDStr* pair = list->append();
127d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    pair->fView = view;
128d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    pair->fStr = (char*)fStrings.alloc(len, SkChunkAlloc::kThrow_AllocFailType);
129d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    memcpy(pair->fStr, str, len);
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkViewInflate::dump() const
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
135d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    const IDStr* iter = fListenTo.begin();
136d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    const IDStr* stop = fListenTo.end();
137d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    for (; iter < stop; iter++)
138d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        SkDebugf("inflate: listenTo(\"%s\")\n", iter->fStr);
139d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
140d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    iter = fBroadcastTo.begin();
141d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    stop = fBroadcastTo.end();
142d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    for (; iter < stop; iter++)
143d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        SkDebugf("inflate: broadcastFrom(\"%s\")\n", iter->fStr);
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
146