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 402880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (!strcmp(name, "listenTo") && (target = dom.findAttr(child, "target")) != nullptr) 41d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com this->addIDStr(&fListenTo, parent, target); 42d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 432880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (!strcmp(name, "broadcastTo") && (target = dom.findAttr(child, "target")) != nullptr) 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 652880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (root == nullptr) 66d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com { 67d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com root = this->createView(dom, node); 682880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (root == nullptr) 69d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com { 702880df2609eba09b555ca37be04b6ad89290c765Tom Hudson printf("createView returned nullptr on <%s>\n", dom.getName(node)); 712880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return nullptr; 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 1062880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return node ? this->inflate(dom, node, root) : nullptr; 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; 1132880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return fIDs.find(id, &view) ? view : nullptr; 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; 1202880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return nullptr; 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