void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target) { ASSERT(!m_targetElementInstance); ASSERT(!m_needsShadowTreeRecreation); // <use> creates a "user agent" shadow root. Do not build the shadow/instance tree for <use> // elements living in a user agent shadow tree because they will get expanded in a second // pass -- see expandUseElementsInShadowTree(). if (inUseShadowTree()) return; // Do not allow self-referencing. // 'target' may be null, if it's a non SVG namespaced element. if (!target || target == this || isDisallowedElement(target)) return; // Set up root SVG element in shadow tree. RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithoutChildren(); m_targetElementInstance = toSVGElement(newChild.get()); ShadowRoot* shadowTreeRootElement = userAgentShadowRoot(); shadowTreeRootElement->appendChild(newChild.release()); // Clone the target subtree into the shadow tree, not handling <use> and <symbol> yet. // 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 (!buildShadowTree(target, m_targetElementInstance.get(), false)) { clearShadowTree(); return; } if (instanceTreeIsLoading(m_targetElementInstance.get())) return; // Assure shadow tree building was successfull ASSERT(m_targetElementInstance); ASSERT(m_targetElementInstance->correspondingUseElement() == this); ASSERT(m_targetElementInstance->correspondingElement() == target); // Expand all <use> elements in the shadow tree. // Expand means: replace the actual <use> element by what it references. if (!expandUseElementsInShadowTree(m_targetElementInstance.get())) { clearShadowTree(); return; } // Expand all <symbol> elements in the shadow tree. // Expand means: replace the actual <symbol> element by the <svg> element. expandSymbolElementsInShadowTree(toSVGElement(shadowTreeRootElement->firstChild())); m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild()); transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement()); ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement); // Update relative length information. updateRelativeLengthsInformation(); }
void SVGTRefElement::updateReferencedText() { String textContent; if (Element* target = SVGURIReference::targetElementFromIRIString(href(), document())) textContent = target->textContent(); ASSERT(shadow()); ShadowRoot* root = shadow()->oldestShadowRoot(); if (!root->firstChild()) root->appendChild(SVGShadowText::create(document(), textContent), ASSERT_NO_EXCEPTION); else root->firstChild()->setTextContent(textContent, ASSERT_NO_EXCEPTION); }
void SVGTRefElement::updateReferencedText(Element* target) { String textContent; if (target) textContent = target->textContent(); ASSERT(shadowRoot()); ShadowRoot* root = shadowRoot(); if (!root->firstChild()) root->appendChild(Text::create(document(), textContent), ASSERT_NO_EXCEPTION); else { ASSERT(root->firstChild()->isTextNode()); root->firstChild()->setTextContent(textContent, ASSERT_NO_EXCEPTION); } }
void ShadowTree::recalcShadowTreeStyle(Node::StyleChange change) { ShadowRoot* youngest = youngestShadowRoot(); if (!youngest) return; if (needsReattachHostChildrenAndShadow()) reattachHostChildrenAndShadow(); else { StyleResolver* styleResolver = youngest->document()->styleResolver(); styleResolver->pushParentShadowRoot(youngest); for (Node* n = youngest->firstChild(); n; n = n->nextSibling()) { if (n->isElementNode()) static_cast<Element*>(n)->recalcStyle(change); else if (n->isTextNode()) toText(n)->recalcTextStyle(change); } styleResolver->popParentShadowRoot(youngest); } clearNeedsReattachHostChildrenAndShadow(); for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) { root->clearNeedsStyleRecalc(); root->clearChildNeedsStyleRecalc(); } }
static inline void getDecorationRootAndDecoratedRoot(HTMLInputElement* input, ShadowRoot*& decorationRoot, ShadowRoot*& decoratedRoot) { ShadowRoot* existingRoot = input->youngestShadowRoot(); ShadowRoot* newRoot = 0; while (existingRoot->childNodeCount() == 1 && existingRoot->firstChild()->hasTagName(shadowTag)) { newRoot = existingRoot; existingRoot = existingRoot->olderShadowRoot(); ASSERT(existingRoot); } if (newRoot) newRoot->removeChild(newRoot->firstChild()); else newRoot = ShadowRoot::create(input, ShadowRoot::UserAgentShadowRoot, ASSERT_NO_EXCEPTION).get(); decorationRoot = newRoot; decoratedRoot = existingRoot; }
SliderThumbElement* sliderThumbElementOf(Node* node) { ASSERT(node); ShadowRoot* shadow = node->toInputElement()->shadowTree()->oldestShadowRoot(); ASSERT(shadow); Node* thumb = shadow->firstChild()->firstChild()->firstChild(); ASSERT(thumb); return toSliderThumbElement(thumb); }
void HTMLPlugInImageElement::updateSnapshotInfo() { ShadowRoot* root = userAgentShadowRoot(); if (!root) return; Element* shadowContainer = toElement(root->firstChild()); shadowContainer->setAttribute(classAttr, classNameForShadowRoot(this, m_isPrimarySnapshottedPlugIn)); }
HTMLElement* sliderTrackElementOf(Node* node) { RELEASE_ASSERT(node->hasTagName(inputTag)); ShadowRoot* shadow = toHTMLInputElement(node)->userAgentShadowRoot(); ASSERT(shadow); Node* track = shadow->firstChild()->firstChild(); ASSERT(track); return toHTMLElement(track); }
TrackLimiterElement* trackLimiterElementOf(Node* node) { ASSERT(node); ShadowRoot* shadow = node->toInputElement()->shadowRoot(); ASSERT(shadow); Node* limiter = shadow->firstChild()->lastChild(); ASSERT(limiter); return static_cast<TrackLimiterElement*>(limiter); }
HTMLElement* sliderTrackElementOf(Node* node) { ASSERT(node); ShadowRoot* shadow = node->toInputElement()->userAgentShadowRoot(); ASSERT(shadow); Node* track = shadow->firstChild()->firstChild(); ASSERT(track); return toHTMLElement(track); }
static inline void getDecorationRootAndDecoratedRoot(HTMLInputElement* input, ShadowRoot*& decorationRoot, ShadowRoot*& decoratedRoot) { ShadowRoot* existingRoot = input->youngestShadowRoot(); ShadowRoot* newRoot = 0; while (existingRoot->childNodeCount() == 1 && existingRoot->firstChild()->hasTagName(shadowTag)) { newRoot = existingRoot; existingRoot = existingRoot->olderShadowRoot(); ASSERT(existingRoot); } if (newRoot) newRoot->removeChild(newRoot->firstChild()); else { // FIXME: This interacts really badly with author shadow roots because now // we can interleave user agent and author shadow roots on the element meaning // input.shadowRoot may be inaccessible if the browser has decided to decorate // the input. newRoot = input->ensureShadow()->addShadowRoot(input, ShadowRoot::UserAgentShadowRoot); } decorationRoot = newRoot; decoratedRoot = existingRoot; }
void HTMLPlugInImageElement::checkSnapshotStatus() { if (!renderer()->isSnapshottedPlugIn()) { if (displayState() == Playing) checkSizeChangeForSnapshotting(); return; } ShadowRoot* root = userAgentShadowRoot(); if (!root) return; Element* shadowContainer = toElement(root->firstChild()); shadowContainer->setAttribute(classAttr, classNameForShadowRoot(this)); }
void HTMLImageElement::destroyImageControls() { ShadowRoot* shadowRoot = userAgentShadowRoot(); if (!shadowRoot) return; if (Node* node = shadowRoot->firstChild()) { ASSERT_WITH_SECURITY_IMPLICATION(node->isImageControlsRootElement()); shadowRoot->removeChild(*node); } auto* renderObject = renderer(); if (!renderObject) return; downcast<RenderImage>(*renderObject).setHasShadowControls(false); }
void TextFieldDecorationElement::decorate(HTMLInputElement* input, bool visible) { ASSERT(input); ShadowRoot* existingRoot; ShadowRoot* decorationRoot; getDecorationRootAndDecoratedRoot(input, decorationRoot, existingRoot); ASSERT(decorationRoot); ASSERT(existingRoot); RefPtr<HTMLDivElement> box = HTMLDivElement::create(input->document()); decorationRoot->appendChild(box); box->setInlineStyleProperty(CSSPropertyDisplay, CSSValueWebkitBox); box->setInlineStyleProperty(CSSPropertyWebkitBoxAlign, CSSValueCenter); ASSERT(existingRoot->childNodeCount() == 1); toHTMLElement(existingRoot->firstChild())->setInlineStyleProperty(CSSPropertyWebkitBoxFlex, 1.0, CSSPrimitiveValue::CSS_NUMBER); box->appendChild(HTMLShadowElement::create(HTMLNames::shadowTag, input->document())); setInlineStyleProperty(CSSPropertyDisplay, visible ? CSSValueBlock : CSSValueNone); box->appendChild(this); }
bool RuleFeatureSet::invalidateStyleForClassChangeOnChildren(Element* element, Vector<AtomicString>& invalidationClasses, bool foundInvalidationSet) { bool someChildrenNeedStyleRecalc = false; for (ShadowRoot* root = element->youngestShadowRoot(); root; root = root->olderShadowRoot()) { for (Node* child = root->firstChild(); child; child = child->nextSibling()) { if (child->isElementNode()) { Element* childElement = toElement(child); bool childRecalced = invalidateStyleForClassChange(childElement, invalidationClasses, foundInvalidationSet); someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalced; } } } for (Node* child = element->firstChild(); child; child = child->nextSibling()) { if (child->isElementNode()) { Element* childElement = toElement(child); bool childRecalced = invalidateStyleForClassChange(childElement, invalidationClasses, foundInvalidationSet); someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalced; } } return someChildrenNeedStyleRecalc; }
HTMLElement* ColorInputType::shadowColorSwatch() const { ShadowRoot* shadow = element().userAgentShadowRoot(); return shadow ? downcast<HTMLElement>(shadow->firstChild()->firstChild()) : nullptr; }
HTMLSelectElement* HTMLKeygenElement::shadowSelect() const { ShadowRoot* shadow = shadowRoot(); ASSERT(shadow); return shadow ? static_cast<HTMLSelectElement*>(shadow->firstChild()) : 0; }
HTMLElement* ColorInputType::shadowColorSwatch() const { ShadowRoot* shadow = element()->userAgentShadowRoot(); return shadow ? toHTMLElement(shadow->firstChild()->firstChild()) : 0; }
HTMLSelectElement* HTMLKeygenElement::shadowSelect() const { ShadowRoot* root = userAgentShadowRoot(); return root ? toHTMLSelectElement(root->firstChild()) : 0; }
void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target) { ASSERT(!m_targetElementInstance); // Do not build the shadow/instance tree for <use> elements living in a shadow tree. // The will be expanded soon anyway - see expandUseElementsInShadowTree(). if (isInShadowTree()) return; // 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, this, target); // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children bool foundProblem = false; buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false); if (instanceTreeIsLoading(m_targetElementInstance.get())) return; // 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) { clearResourceReferences(); return; } // Assure instance tree building was successfull ASSERT(m_targetElementInstance); ASSERT(!m_targetElementInstance->shadowTreeElement()); ASSERT(m_targetElementInstance->correspondingUseElement() == this); ASSERT(m_targetElementInstance->directUseElement() == this); ASSERT(m_targetElementInstance->correspondingElement() == target); ShadowRoot* shadowTreeRootElement = shadowRoot(); ASSERT(shadowTreeRootElement); // Build shadow tree from instance tree // This also handles the special cases: <use> on <symbol>, <use> on <svg>. buildShadowTree(target, m_targetElementInstance.get()); // Expand all <use> elements in the shadow tree. // Expand means: replace the actual <use> element by what it references. expandUseElementsInShadowTree(shadowTreeRootElement); // Expand all <symbol> elements in the shadow tree. // Expand means: replace the actual <symbol> element by the <svg> element. expandSymbolElementsInShadowTree(shadowTreeRootElement); // Now that the shadow tree is completly expanded, we can associate // shadow tree elements <-> instances in the instance tree. associateInstancesWithShadowTreeElements(shadowTreeRootElement->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()) { clearResourceReferences(); return; } ASSERT(m_targetElementInstance->shadowTreeElement()->parentNode() == shadowTreeRootElement); // Transfer event listeners assigned to the referenced element to our shadow tree elements. transferEventListenersToShadowTree(m_targetElementInstance.get()); // Update relative length information. updateRelativeLengthsInformation(); // 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 RefPtr<XMLSerializer> serializer = XMLSerializer::create(); String markup = serializer->serializeToString(shadowTreeRootElement, ASSERT_NO_EXCEPTION); fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data()); #endif }