void HTMLStyleElement::registerWithScopingNode(bool scoped) { // Note: We cannot rely on the 'scoped' element already being present when this method is invoked. // Therefore we cannot rely on scoped()! ASSERT(m_scopedStyleRegistrationState == NotRegistered); ASSERT(inDocument()); if (m_scopedStyleRegistrationState != NotRegistered) return; ContainerNode* scope = scoped ? parentNode() : containingShadowRoot(); if (!scope) return; if (!scope->isElementNode() && !scope->isShadowRoot()) { // DocumentFragment nodes should never be inDocument, // <style> should not be a child of Document, PI or some such. ASSERT_NOT_REACHED(); return; } scope->registerScopedHTMLStyleChild(); if (scope->isShadowRoot()) scope->shadowHost()->setNeedsStyleRecalc(); else scope->setNeedsStyleRecalc(); if (inDocument() && !document()->parsing() && document()->renderer()) document()->styleResolverChanged(DeferRecalcStyle); m_scopedStyleRegistrationState = scoped ? RegisteredAsScoped : RegisteredInShadowRoot; }
void HTMLStyleElement::registerWithScopingNode() { // Note: We cannot rely on the 'scoped' element already being present when this method is invoked. // Therefore we cannot rely on scoped()! ASSERT(!m_isRegisteredWithScopingNode); ASSERT(inDocument()); if (m_isRegisteredWithScopingNode) return; if (!ContextEnabledFeatures::styleScopedEnabled(document())) return; ContainerNode* scope = parentNode(); if (!scope) return; if (!scope->isElementNode() && !scope->isShadowRoot()) { // DocumentFragment nodes should never be inDocument, // <style> should not be a child of Document, PI or some such. ASSERT_NOT_REACHED(); return; } scope->registerScopedHTMLStyleChild(); scope->setNeedsStyleRecalc(); if (inDocument() && !document()->parsing() && document()->renderer()) document()->styleResolverChanged(DeferRecalcStyle); m_isRegisteredWithScopingNode = true; }
// FIXME: This is duplicated with StyleResolver.cpp // Perhaps this should move onto ElementResolveContext or even Element? static inline bool isAtShadowBoundary(const Element* element) { if (!element) return false; ContainerNode* parentNode = element->parentNode(); return parentNode && parentNode->isShadowRoot(); }
static ContainerNode* traverseParent(const Node* node, ShadowRootCrossing shadowRootCrossing) { if (node->isPseudoElement()) return toPseudoElement(node)->hostElement(); if (shadowRootCrossing == DontCrossShadowRoot && node->isShadowRoot()) return 0; if (nodeCanBeDistributed(node)) { if (InsertionPoint* insertionPoint = findInsertionPointOf(node)) return traverseParent(insertionPoint, shadowRootCrossing); return nullptr; } ContainerNode* parent = node->parentNode(); if (!parent) return nullptr; if (parent->isShadowRoot()) return shadowRootCrossing == CrossShadowRoot ? toShadowRoot(parent)->hostElement() : parent; if (parent->isInsertionPoint()) { const InsertionPoint* insertionPoint = toInsertionPoint(parent); if (insertionPoint->hasDistribution()) return nullptr; if (insertionPoint->isActive()) return traverseParent(parent, shadowRootCrossing); } return parent; }
static bool childAttachedAllowedWhenAttachingChildren(ContainerNode& node) { if (node.isShadowRoot()) return true; if (node.isInsertionPoint()) return true; if (node.isElementNode() && toElement(&node)->shadowRoot()) return true; return false; }
ContainerNode* FlatTreeTraversal::traverseParentOrHost(const Node& node) { ContainerNode* parent = node.parentNode(); if (!parent) return nullptr; if (!parent->isShadowRoot()) return parent; ShadowRoot* shadowRoot = toShadowRoot(parent); DCHECK(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); if (!shadowRoot->isYoungest()) return nullptr; return &shadowRoot->host(); }
NodeRenderingContext::NodeRenderingContext(Node* node) : m_location(LocationNotInTree) , m_phase(AttachStraight) , m_node(node) , m_parentNodeForRenderingAndStyle(0) , m_visualParentShadowRoot(0) , m_includer(0) , m_style(0) , m_parentFlowRenderer(0) { ContainerNode* parent = m_node->parentOrHostNode(); if (!parent) return; if (parent->isShadowRoot()) { m_location = LocationShadowChild; m_parentNodeForRenderingAndStyle = parent->shadowHost(); return; } m_location = LocationLightChild; if (parent->isElementNode()) { m_visualParentShadowRoot = toElement(parent)->shadowRoot(); if (m_visualParentShadowRoot) { if ((m_includer = m_visualParentShadowRoot->includerFor(m_node)) && m_visualParentShadowRoot->isInclusionSelectorActive()) { m_phase = AttachContentForwarded; m_parentNodeForRenderingAndStyle = NodeRenderingContext(m_includer).parentNodeForRenderingAndStyle(); return; } m_phase = AttachContentLight; m_parentNodeForRenderingAndStyle = parent; return; } if (parent->isContentElement()) { HTMLContentElement* shadowContentElement = toHTMLContentElement(parent); if (!shadowContentElement->hasInclusion()) { m_phase = AttachContentFallback; m_parentNodeForRenderingAndStyle = NodeRenderingContext(parent).parentNodeForRenderingAndStyle(); return; } } } m_parentNodeForRenderingAndStyle = parent; }
const ContainerNode* ScopedStyleResolver::scopingNodeFor(const CSSStyleSheet* sheet) { ASSERT(sheet); Document* document = sheet->ownerDocument(); if (!document) return 0; Node* ownerNode = sheet->ownerNode(); if (!ownerNode || !ownerNode->isHTMLElement() || !ownerNode->hasTagName(HTMLNames::styleTag)) return 0; HTMLStyleElement* styleElement = static_cast<HTMLStyleElement*>(ownerNode); if (!styleElement->scoped()) return styleElement->isInShadowTree() ? styleElement->containingShadowRoot() : 0; ContainerNode* parent = styleElement->parentNode(); if (!parent) return 0; return (parent->isElementNode() || parent->isShadowRoot()) ? parent : 0; }
ContainerNode* ScopedStyleResolver::scopingNodeFor(Document& document, const CSSStyleSheet* sheet) { ASSERT(sheet); Document* sheetDocument = sheet->ownerDocument(); if (!sheetDocument) return 0; Node* ownerNode = sheet->ownerNode(); if (!isHTMLStyleElement(ownerNode)) return &document; HTMLStyleElement& styleElement = toHTMLStyleElement(*ownerNode); if (!styleElement.scoped()) { if (styleElement.isInShadowTree()) return styleElement.containingShadowRoot(); return &document; } ContainerNode* parent = styleElement.parentNode(); if (!parent) return 0; return (parent->isElementNode() || parent->isShadowRoot()) ? parent : 0; }
NodeRenderingContext::NodeRenderingContext(Node* node) : m_phase(AttachingNotInTree) , m_node(node) , m_parentNodeForRenderingAndStyle(0) , m_visualParentShadow(0) , m_insertionPoint(0) , m_style(0) , m_parentFlowRenderer(0) { ContainerNode* parent = m_node->parentOrHostNode(); if (!parent) return; if (parent->isShadowRoot() && toShadowRoot(parent)->isYoungest()) { m_phase = AttachingShadowChild; m_parentNodeForRenderingAndStyle = toShadowRoot(parent)->host(); return; } if (parent->isElementNode() || parent->isShadowRoot()) { if (parent->isElementNode()) m_visualParentShadow = toElement(parent)->shadow(); else if (parent->isShadowRoot()) m_visualParentShadow = toShadowRoot(parent)->owner(); if (m_visualParentShadow) { if ((m_insertionPoint = m_visualParentShadow->insertionPointFor(m_node))) { if (m_insertionPoint->shadowRoot()->isUsedForRendering()) { m_phase = AttachingDistributed; m_parentNodeForRenderingAndStyle = NodeRenderingContext(m_insertionPoint).parentNodeForRenderingAndStyle(); return; } } m_phase = AttachingNotDistributed; m_parentNodeForRenderingAndStyle = parent; return; } if (isShadowBoundary(parent)) { if (!parent->shadowRoot()->isUsedForRendering()) { m_phase = AttachingNotDistributed; m_parentNodeForRenderingAndStyle = parent; return; } if (toInsertionPoint(parent)->hasDistribution()) m_phase = AttachingNotFallbacked; else m_phase = AttachingFallbacked; if (toInsertionPoint(parent)->isActive()) m_parentNodeForRenderingAndStyle = NodeRenderingContext(parent).parentNodeForRenderingAndStyle(); else m_parentNodeForRenderingAndStyle = parent; return; } } m_phase = AttachingStraight; m_parentNodeForRenderingAndStyle = parent; }
static inline bool isTreeScopeRoot(const ContainerNode& node) { return node.isDocumentNode() || node.isShadowRoot(); }
void SVGUseElement::buildShadowAndInstanceTree(SVGShadowTreeRootElement* shadowRoot) { struct ShadowTreeUpdateBlocker { ShadowTreeUpdateBlocker(SVGUseElement* currentUseElement) : useElement(currentUseElement) { useElement->setUpdatesBlocked(true); } ~ShadowTreeUpdateBlocker() { useElement->setUpdatesBlocked(false); } SVGUseElement* useElement; }; // When cloning the target nodes, they may decide to synchronize style and/or animated SVG attributes. // That causes calls to SVGElementInstance::updateAllInstancesOfElement(), which mark the shadow tree for recreation. // Solution: block any updates to the shadow tree while we're building it. ShadowTreeUpdateBlocker blocker(this); String id = SVGURIReference::getTarget(href()); Element* targetElement = document()->getElementById(id); if (!targetElement) { // The only time we should get here is when the use element has not been // given a resource to target. ASSERT(m_resourceId.isEmpty()); return; } // Do not build the shadow/instance tree for <use> elements living in a shadow tree. // The will be expanded soon anyway - see expandUseElementsInShadowTree(). ContainerNode* parent = parentNode(); while (parent) { if (parent->isShadowRoot()) return; parent = parent->parentNodeGuaranteedHostFree(); } SVGElement* target = 0; if (targetElement && targetElement->isSVGElement()) target = static_cast<SVGElement*>(targetElement); detachInstance(); // Do not allow self-referencing. // 'target' may be null, if it's a non SVG namespaced element. if (!target || target == this) return; // Why a seperated instance/shadow tree? SVG demands it: // The instance tree is accesable from JavaScript, and has to // expose a 1:1 copy of the referenced tree, whereas internally we need // to alter the tree for correct "use-on-symbol", "use-on-svg" support. // Build instance tree. Create root SVGElementInstance object for the first sub-tree node. // // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object // is the SVGRectElement that corresponds to the referenced 'rect' element. m_targetElementInstance = SVGElementInstance::create(this, target); // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children bool foundProblem = false; buildInstanceTree(target, m_targetElementInstance.get(), foundProblem); // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it! // Non-appearing <use> content is easier to debug, then half-appearing content. if (foundProblem) { detachInstance(); return; } // Assure instance tree building was successfull ASSERT(m_targetElementInstance); ASSERT(!m_targetElementInstance->shadowTreeElement()); ASSERT(m_targetElementInstance->correspondingUseElement() == this); ASSERT(m_targetElementInstance->correspondingElement() == target); // Build shadow tree from instance tree // This also handles the special cases: <use> on <symbol>, <use> on <svg>. buildShadowTree(shadowRoot, target, m_targetElementInstance.get()); #if ENABLE(SVG) && ENABLE(SVG_USE) // Expand all <use> elements in the shadow tree. // Expand means: replace the actual <use> element by what it references. expandUseElementsInShadowTree(shadowRoot, shadowRoot); // Expand all <symbol> elements in the shadow tree. // Expand means: replace the actual <symbol> element by the <svg> element. expandSymbolElementsInShadowTree(shadowRoot, shadowRoot); #endif // Now that the shadow tree is completly expanded, we can associate // shadow tree elements <-> instances in the instance tree. associateInstancesWithShadowTreeElements(shadowRoot->firstChild(), m_targetElementInstance.get()); // If no shadow tree element is present, this means that the reference root // element was removed, as it is disallowed (ie. <use> on <foreignObject>) // Do NOT leave an inconsistent instance tree around, instead destruct it. if (!m_targetElementInstance->shadowTreeElement()) { shadowRoot->removeAllChildren(); detachInstance(); return; } // Consistency checks - this is assumed in updateContainerOffset(). ASSERT(m_targetElementInstance->shadowTreeElement()->parentNode() == shadowRoot); // Eventually dump instance tree #ifdef DUMP_INSTANCE_TREE String text; unsigned int depth = 0; dumpInstanceTree(depth, text, m_targetElementInstance.get()); fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data()); #endif // Eventually dump shadow tree #ifdef DUMP_SHADOW_TREE ExceptionCode ec = 0; RefPtr<XMLSerializer> serializer = XMLSerializer::create(); String markup = serializer->serializeToString(shadowRoot, ec); ASSERT(!ec); fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data()); #endif // Transfer event listeners assigned to the referenced element to our shadow tree elements. transferEventListenersToShadowTree(m_targetElementInstance.get()); // Update container offset/size updateContainerOffsets(); updateContainerSizes(); // Update relative length information updateRelativeLengthsInformation(); }