/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkViewInflate.h" #include "SkView.h" #include <stdio.h> SkViewInflate::SkViewInflate() : fIDs(kMinIDStrAlloc), fStrings(kMinIDStrAlloc) { } SkViewInflate::~SkViewInflate() { } void SkViewInflate::rInflate(const SkDOM& dom, const SkDOM::Node* node, SkView* parent) { const char* str = dom.findAttr(node, "id"); if (str) fIDs.set(str, parent); const SkDOM::Node* child = dom.getFirstChild(node); while (child) { SkView* view = this->createView(dom, child); if (view) { this->rInflate(dom, child, view); parent->attachChildToFront(view)->unref(); } else { const char* name = dom.getName(child); const char* target; if (!strcmp(name, "listenTo") && (target = dom.findAttr(child, "target")) != NULL) this->addIDStr(&fListenTo, parent, target); if (!strcmp(name, "broadcastTo") && (target = dom.findAttr(child, "target")) != NULL) this->addIDStr(&fBroadcastTo, parent, target); } child = dom.getNextSibling(child); } parent->setVisibleP(true); this->inflateView(parent, dom, node); } void SkViewInflate::inflateView(SkView* view, const SkDOM& dom, const SkDOM::Node* node) { // called after all of view's children have been instantiated. // this may be overridden by a subclass, to load in layout or other helpers // they should call through to us (INHERITED) before or after their patch view->inflate(dom, node); } SkView* SkViewInflate::inflate(const SkDOM& dom, const SkDOM::Node* node, SkView* root) { fIDs.reset(); if (root == NULL) { root = this->createView(dom, node); if (root == NULL) { printf("createView returned NULL on <%s>\n", dom.getName(node)); return NULL; } } this->rInflate(dom, node, root); // resolve listeners and broadcasters { SkView* target; const IDStr* iter = fListenTo.begin(); const IDStr* stop = fListenTo.end(); for (; iter < stop; iter++) { if (fIDs.find(iter->fStr, &target)) target->addListenerID(iter->fView->getSinkID()); } iter = fBroadcastTo.begin(); stop = fBroadcastTo.end(); for (; iter < stop; iter++) { if (fIDs.find(iter->fStr, &target)) iter->fView->addListenerID(target->getSinkID()); } } // now that the tree is built, give everyone a shot at the ID dict root->postInflate(fIDs); return root; } SkView* SkViewInflate::inflate(const char xml[], size_t len, SkView* root) { SkDOM dom; const SkDOM::Node* node = dom.build(xml, len); return node ? this->inflate(dom, node, root) : NULL; } SkView* SkViewInflate::findViewByID(const char id[]) const { SkASSERT(id); SkView* view; return fIDs.find(id, &view) ? view : NULL; } SkView* SkViewInflate::createView(const SkDOM& dom, const SkDOM::Node* node) { if (!strcmp(dom.getName(node), "view")) return new SkView; return NULL; } void SkViewInflate::addIDStr(SkTDArray<IDStr>* list, SkView* view, const char* str) { size_t len = strlen(str) + 1; IDStr* pair = list->append(); pair->fView = view; pair->fStr = (char*)fStrings.alloc(len, SkChunkAlloc::kThrow_AllocFailType); memcpy(pair->fStr, str, len); } #ifdef SK_DEBUG void SkViewInflate::dump() const { const IDStr* iter = fListenTo.begin(); const IDStr* stop = fListenTo.end(); for (; iter < stop; iter++) SkDebugf("inflate: listenTo(\"%s\")\n", iter->fStr); iter = fBroadcastTo.begin(); stop = fBroadcastTo.end(); for (; iter < stop; iter++) SkDebugf("inflate: broadcastFrom(\"%s\")\n", iter->fStr); } #endif