Node* DOMPatchSupport::patchNode(Node* node, const String& markup, ExceptionState& exceptionState) { // Don't parse <html> as a fragment. if (node->isDocumentNode() || (node->parentNode() && node->parentNode()->isDocumentNode())) { patchDocument(markup); return 0; } Node* previousSibling = node->previousSibling(); RefPtrWillBeRawPtr<DocumentFragment> fragment = DocumentFragment::create(m_document); Node* targetNode = node->parentElementOrShadowRoot() ? node->parentElementOrShadowRoot() : m_document.documentElement(); // Use the document BODY as the context element when editing immediate shadow root children, // as it provides an equivalent parsing context. if (targetNode->isShadowRoot()) targetNode = m_document.body(); Element* targetElement = toElement(targetNode); // FIXME: This code should use one of createFragment* in markup.h if (m_document.isHTMLDocument()) fragment->parseHTML(markup, targetElement); else fragment->parseXML(markup, targetElement); // Compose the old list. ContainerNode* parentNode = node->parentNode(); Vector<OwnPtr<Digest> > oldList; for (Node* child = parentNode->firstChild(); child; child = child->nextSibling()) oldList.append(createDigest(child, 0)); // Compose the new list. String markupCopy = markup.lower(); Vector<OwnPtr<Digest> > newList; for (Node* child = parentNode->firstChild(); child != node; child = child->nextSibling()) newList.append(createDigest(child, 0)); for (Node* child = fragment->firstChild(); child; child = child->nextSibling()) { if (isHTMLHeadElement(*child) && !child->firstChild() && markupCopy.find("</head>") == kNotFound) continue; // HTML5 parser inserts empty <head> tag whenever it parses <body> if (isHTMLBodyElement(*child) && !child->firstChild() && markupCopy.find("</body>") == kNotFound) continue; // HTML5 parser inserts empty <body> tag whenever it parses </head> newList.append(createDigest(child, &m_unusedNodesMap)); } for (Node* child = node->nextSibling(); child; child = child->nextSibling()) newList.append(createDigest(child, 0)); if (!innerPatchChildren(parentNode, oldList, newList, exceptionState)) { // Fall back to total replace. if (!m_domEditor->replaceChild(parentNode, fragment.release(), node, exceptionState)) return 0; } return previousSibling ? previousSibling->nextSibling() : parentNode->firstChild(); }
bool XMLFile::BeginLoad(Deserializer& source) { unsigned dataSize = source.GetSize(); if (!dataSize && !source.GetName().Empty()) { URHO3D_LOGERROR("Zero sized XML data in " + source.GetName()); return false; } SharedArrayPtr<char> buffer(new char[dataSize]); if (source.Read(buffer.Get(), dataSize) != dataSize) return false; if (!document_->load_buffer(buffer.Get(), dataSize)) { URHO3D_LOGERROR("Could not parse XML data from " + source.GetName()); document_->reset(); return false; } XMLElement rootElem = GetRoot(); String inherit = rootElem.GetAttribute("inherit"); if (!inherit.Empty()) { // The existence of this attribute indicates this is an RFC 5261 patch file ResourceCache* cache = GetSubsystem<ResourceCache>(); // If being async loaded, GetResource() is not safe, so use GetTempResource() instead XMLFile* inheritedXMLFile = GetAsyncLoadState() == ASYNC_DONE ? cache->GetResource<XMLFile>(inherit) : cache->GetTempResource<XMLFile>(inherit); if (!inheritedXMLFile) { URHO3D_LOGERRORF("Could not find inherited XML file: %s", inherit.CString()); return false; } // Patch this XMLFile and leave the original inherited XMLFile as it is UniquePtr<pugi::xml_document> patchDocument(document_.Detach()); document_ = new pugi::xml_document(); document_->reset(*inheritedXMLFile->document_); Patch(rootElem); // Store resource dependencies so we know when to reload/repatch when the inherited resource changes cache->StoreResourceDependency(this, inherit); // Approximate patched data size dataSize += inheritedXMLFile->GetMemoryUse(); } // Note: this probably does not reflect internal data structure size accurately SetMemoryUse(dataSize); return true; }