Example #1
0
void TreeScope::setParentTreeScope(TreeScope& newParentScope)
{
    // A document node cannot be re-parented.
    ASSERT(!rootNode().isDocumentNode());

    newParentScope.guardRef();
    if (m_parentTreeScope)
        m_parentTreeScope->guardDeref();
    m_parentTreeScope = &newParentScope;
    setDocument(newParentScope.document());
}
Example #2
0
RelatedNodeRetargeter::RelatedNodeRetargeter(Node& relatedNode, Node& target)
    : m_relatedNode(relatedNode)
    , m_retargetedRelatedNode(&relatedNode)
{
    auto& targetTreeScope = target.treeScope();
    TreeScope* currentTreeScope = &m_relatedNode.treeScope();
    if (LIKELY(currentTreeScope == &targetTreeScope && target.inDocument() && m_relatedNode.inDocument()))
        return;

    if (&currentTreeScope->documentScope() != &targetTreeScope.documentScope()) {
        m_hasDifferentTreeRoot = true;
        m_retargetedRelatedNode = nullptr;
        return;
    }
    if (relatedNode.inDocument() != target.inDocument()) {
        m_hasDifferentTreeRoot = true;
        m_retargetedRelatedNode = moveOutOfAllShadowRoots(relatedNode);
        return;
    }

    collectTreeScopes();

    // FIXME: We should collect this while constructing the event path.
    Vector<TreeScope*, 8> targetTreeScopeAncestors;
    for (TreeScope* currentTreeScope = &targetTreeScope; currentTreeScope; currentTreeScope = currentTreeScope->parentTreeScope())
        targetTreeScopeAncestors.append(currentTreeScope);
    ASSERT_WITH_SECURITY_IMPLICATION(!targetTreeScopeAncestors.isEmpty());

    unsigned i = m_ancestorTreeScopes.size();
    unsigned j = targetTreeScopeAncestors.size();
    ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.last() == targetTreeScopeAncestors.last());
    while (m_ancestorTreeScopes[i - 1] == targetTreeScopeAncestors[j - 1]) {
        i--;
        j--;
        if (!i || !j)
            break;
    }

    bool lowestCommonAncestorIsDocumentScope = i + 1 == m_ancestorTreeScopes.size();
    if (lowestCommonAncestorIsDocumentScope && !relatedNode.inDocument() && !target.inDocument()) {
        Node& targetAncestorInDocumentScope = i ? *downcast<ShadowRoot>(m_ancestorTreeScopes[i - 1]->rootNode()).shadowHost() : target;
        Node& relatedNodeAncestorInDocumentScope = j ? *downcast<ShadowRoot>(targetTreeScopeAncestors[j - 1]->rootNode()).shadowHost() : relatedNode;
        if (targetAncestorInDocumentScope.rootNode() != relatedNodeAncestorInDocumentScope.rootNode()) {
            m_hasDifferentTreeRoot = true;
            m_retargetedRelatedNode = moveOutOfAllShadowRoots(relatedNode);
            return;
        }
    }

    m_lowestCommonAncestorIndex = i;
    m_retargetedRelatedNode = nodeInLowestCommonAncestor();
}
Example #3
0
void HTMLLabelElement::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
{
    if (!inDocument())
        return;

    if (oldForAttributeValue == newForAttributeValue)
        return;

    if (!oldForAttributeValue.isEmpty())
        scope.removeLabel(oldForAttributeValue, this);
    if (!newForAttributeValue.isEmpty())
        scope.addLabel(newForAttributeValue, this);
}
Example #4
0
void DocumentOrderedMap::add(const AtomicStringImpl& key, Element& element, const TreeScope& treeScope)
{
    ASSERT_WITH_SECURITY_IMPLICATION(element.isInTreeScope());
    ASSERT_WITH_SECURITY_IMPLICATION(treeScope.rootNode()->containsIncludingShadowDOM(&element));
    if (!element.isInTreeScope() || &element.document() != treeScope.documentScope())
        return;
    Map::AddResult addResult = m_map.add(&key, MapEntry(&element));
    if (addResult.isNewEntry)
        return;

    MapEntry& entry = addResult.iterator->value;
    ASSERT_WITH_SECURITY_IMPLICATION(entry.count);
    entry.element = 0;
    entry.count++;
    entry.orderedList.clear();
}
Example #5
0
void RelatedNodeRetargeter::moveToNewTreeScope(TreeScope* previousTreeScope, TreeScope& newTreeScope)
{
    if (m_hasDifferentTreeRoot)
        return;

    auto& currentRelatedNodeScope = m_retargetedRelatedNode->treeScope();
    if (previousTreeScope != &currentRelatedNodeScope) {
        // currentRelatedNode is still outside our shadow tree. New tree scope may contain currentRelatedNode
        // but there is no need to re-target it. Moving into a slot (thereby a deeper shadow tree) doesn't matter.
        return;
    }

    bool enteredSlot = newTreeScope.parentTreeScope() == previousTreeScope;
    if (enteredSlot) {
        if (m_lowestCommonAncestorIndex) {
            if (m_ancestorTreeScopes.isEmpty())
                collectTreeScopes();
            bool relatedNodeIsInSlot = m_ancestorTreeScopes[m_lowestCommonAncestorIndex - 1] == &newTreeScope;
            if (relatedNodeIsInSlot) {
                m_lowestCommonAncestorIndex--;
                m_retargetedRelatedNode = nodeInLowestCommonAncestor();
                ASSERT(&newTreeScope == &m_retargetedRelatedNode->treeScope());
            }
        } else
            ASSERT(m_retargetedRelatedNode == &m_relatedNode);
    } else {
        ASSERT(previousTreeScope->parentTreeScope() == &newTreeScope);
        m_lowestCommonAncestorIndex++;
        ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.isEmpty() || m_lowestCommonAncestorIndex < m_ancestorTreeScopes.size());
        m_retargetedRelatedNode = downcast<ShadowRoot>(currentRelatedNodeScope.rootNode()).host();
        ASSERT(&newTreeScope == &m_retargetedRelatedNode->treeScope());
    }
}
Example #6
0
void RelatedNodeRetargeter::collectTreeScopes()
{
    ASSERT(m_ancestorTreeScopes.isEmpty());
    for (TreeScope* currentTreeScope = &m_relatedNode.treeScope(); currentTreeScope; currentTreeScope = currentTreeScope->parentTreeScope())
        m_ancestorTreeScopes.append(currentTreeScope);
    ASSERT_WITH_SECURITY_IMPLICATION(!m_ancestorTreeScopes.isEmpty());
}
Example #7
0
void TreeScope::setParentTreeScope(TreeScope& newParentScope) {
  // A document node cannot be re-parented.
  DCHECK(!rootNode().isDocumentNode());

  m_parentTreeScope = &newParentScope;
  setDocument(newParentScope.document());
}
Example #8
0
void DocumentOrderedMap::add(const AtomicStringImpl& key, Element& element, const TreeScope& treeScope)
{
    UNUSED_PARAM(treeScope);
    ASSERT_WITH_SECURITY_IMPLICATION(element.isInTreeScope());
    ASSERT_WITH_SECURITY_IMPLICATION(treeScope.rootNode().containsIncludingShadowDOM(&element));

    if (!element.isInTreeScope())
        return;
    Map::AddResult addResult = m_map.ensure(&key, [&element] {
        return MapEntry(&element);
    });
    MapEntry& entry = addResult.iterator->value;

#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
    ASSERT_WITH_SECURITY_IMPLICATION(!entry.registeredElements.contains(&element));
    entry.registeredElements.add(&element);
#endif

    if (addResult.isNewEntry)
        return;

    ASSERT_WITH_SECURITY_IMPLICATION(entry.count);
    entry.element = nullptr;
    entry.count++;
    entry.orderedList.clear();
}
Example #9
0
static Position adjustPositionForStart(const Position& currentPosition, Node* endContainerNode)
{
    TreeScope* treeScope = endContainerNode->treeScope();

    ASSERT(currentPosition.containerNode()->treeScope() != treeScope);
    
    if (Node* ancestor = treeScope->ancestorInThisScope(currentPosition.containerNode())) {
        if (ancestor->contains(endContainerNode))
            return positionBeforeNode(ancestor);
        return positionAfterNode(ancestor);
    }

    if (Node* firstChild = treeScope->rootNode()->firstChild())
        return positionBeforeNode(firstChild);

    return Position();
}
TreeScopeEventContext::TreeScopeEventContext(TreeScope& treeScope)
    : m_treeScope(treeScope)
    , m_rootNode(treeScope.rootNode())
    , m_containingClosedShadowTree(nullptr)
    , m_preOrder(-1)
    , m_postOrder(-1)
{
}
Example #11
0
AtomicString SVGURIReference::fragmentIdentifierFromIRIString(
    const String& urlString,
    const TreeScope& treeScope) {
  SVGURLReferenceResolver resolver(urlString, treeScope.document());
  if (!resolver.isLocal())
    return emptyAtom;
  return resolver.fragmentIdentifier();
}
Example #12
0
void InsertionPoint::attach()
{
    TreeScope* scope = treeScope();
    if (scope->isShadowRoot()) {
        ShadowRoot* root = toShadowRoot(scope);
        if (doesSelectFromHostChildren()) {
            distributeHostChildren(root->tree());
            attachDistributedNode();
        } else if (!root->olderShadowRoot()->assignedTo()) {
            ASSERT(!root->olderShadowRoot()->attached());
            assignShadowRoot(root->olderShadowRoot());
            root->olderShadowRoot()->attach();
        }
    }

    HTMLElement::attach();
}
Example #13
0
EventTarget* EventPath::findRelatedNode(TreeScope& scope, RelatedTargetMap& relatedTargetMap)
{
    WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32> parentTreeScopes;
    EventTarget* relatedNode = 0;
    for (TreeScope* current = &scope; current; current = current->olderShadowRootOrParentTreeScope()) {
        parentTreeScopes.append(current);
        RelatedTargetMap::const_iterator iter = relatedTargetMap.find(current);
        if (iter != relatedTargetMap.end() && iter->value) {
            relatedNode = iter->value;
            break;
        }
    }
    ASSERT(relatedNode);
    for (WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32>::iterator iter = parentTreeScopes.begin(); iter < parentTreeScopes.end(); ++iter)
        relatedTargetMap.add(*iter, relatedNode);
    return relatedNode;
}
Example #14
0
void TreeScope::setParentTreeScope(TreeScope& newParentScope)
{
    // A document node cannot be re-parented.
    ASSERT(!m_rootNode.isDocumentNode());

    m_parentTreeScope = &newParentScope;
    setDocumentScope(newParentScope.documentScope());
}
Example #15
0
void ElementRuleCollector::collectMatchingRules(const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
{
    ASSERT(matchRequest.ruleSet);
    ASSERT(m_state.element());

    const StyleResolver::State& state = m_state;
    Element* element = state.element();
    const StyledElement* styledElement = state.styledElement();
    const AtomicString& pseudoId = element->shadowPseudoId();
    if (!pseudoId.isEmpty()) {
        ASSERT(styledElement);
        collectMatchingRulesForList(matchRequest.ruleSet->shadowPseudoElementRules(pseudoId.impl()), matchRequest, ruleRange);
    }

#if ENABLE(VIDEO_TRACK)
    if (element->isWebVTTElement())
        collectMatchingRulesForList(matchRequest.ruleSet->cuePseudoRules(), matchRequest, ruleRange);
#endif
    // Check whether other types of rules are applicable in the current tree scope. Criteria for this:
    // a) it's a UA rule
    // b) the tree scope allows author rules
    // c) the rules comes from a scoped style sheet within the same tree scope
    TreeScope* treeScope = element->treeScope();
    if (!MatchingUARulesScope::isMatchingUARules()
        && !treeScope->applyAuthorStyles()
        && (!matchRequest.scope || matchRequest.scope->treeScope() != treeScope)
        && m_behaviorAtBoundary == SelectorChecker::DoesNotCrossBoundary)
        return;

    // We need to collect the rules for id, class, tag, and everything else into a buffer and
    // then sort the buffer.
    if (element->hasID())
        collectMatchingRulesForList(matchRequest.ruleSet->idRules(element->idForStyleResolution().impl()), matchRequest, ruleRange);
    if (styledElement && styledElement->hasClass()) {
        for (size_t i = 0; i < styledElement->classNames().size(); ++i)
            collectMatchingRulesForList(matchRequest.ruleSet->classRules(styledElement->classNames()[i].impl()), matchRequest, ruleRange);
    }

    if (element->isLink())
        collectMatchingRulesForList(matchRequest.ruleSet->linkPseudoClassRules(), matchRequest, ruleRange);
    if (SelectorChecker::matchesFocusPseudoClass(element))
        collectMatchingRulesForList(matchRequest.ruleSet->focusPseudoClassRules(), matchRequest, ruleRange);
    collectMatchingRulesForList(matchRequest.ruleSet->tagRules(element->localName().impl()), matchRequest, ruleRange);
    collectMatchingRulesForList(matchRequest.ruleSet->universalRules(), matchRequest, ruleRange);
}
Example #16
0
Element* TreeScope::focusedElement()
{
    Document& document = m_rootNode.document();
    Element* element = document.focusedElement();

    if (!element && document.page())
        element = focusedFrameOwnerElement(document.page()->focusController().focusedFrame(), document.frame());
    if (!element)
        return nullptr;
    TreeScope* treeScope = &element->treeScope();
    while (treeScope != this && treeScope != &document) {
        element = downcast<ShadowRoot>(treeScope->rootNode()).host();
        treeScope = &element->treeScope();
    }
    if (this != treeScope)
        return nullptr;
    return element;
}
Example #17
0
Element* TreeScope::focusedElement()
{
    Document* document = rootNode()->document();
    Element* element = document->focusedElement();

    if (!element && document->page())
        element = focusedFrameOwnerElement(document->page()->focusController().focusedFrame(), document->frame());
    if (!element)
        return 0;
    TreeScope* treeScope = element->treeScope();
    while (treeScope != this && treeScope != document) {
        element = toShadowRoot(treeScope->rootNode())->hostElement();
        treeScope = element->treeScope();
    }
    if (this != treeScope)
        return 0;
    return element;
}
Example #18
0
    RelatedNodeRetargeter(Node& relatedNode, TreeScope& targetTreeScope)
        : m_relatedNode(relatedNode)
        , m_retargetedRelatedNode(&relatedNode)
    {
        TreeScope* currentTreeScope = &m_relatedNode.treeScope();
        if (LIKELY(currentTreeScope == &targetTreeScope))
            return;

        if (&currentTreeScope->documentScope() != &targetTreeScope.documentScope()) {
            m_hasDifferentTreeRoot = true;
            m_retargetedRelatedNode = nullptr;
            return;
        }
        if (relatedNode.inDocument() != targetTreeScope.rootNode().inDocument()) {
            m_hasDifferentTreeRoot = true;
            while (m_retargetedRelatedNode->isInShadowTree())
                m_retargetedRelatedNode = downcast<ShadowRoot>(m_retargetedRelatedNode->treeScope().rootNode()).host();
            return;
        }

        collectTreeScopes();

        // FIXME: We should collect this while constructing the event path.
        Vector<TreeScope*, 8> targetTreeScopeAncestors;
        for (TreeScope* currentTreeScope = &targetTreeScope; currentTreeScope; currentTreeScope = currentTreeScope->parentTreeScope())
            targetTreeScopeAncestors.append(currentTreeScope);
        ASSERT_WITH_SECURITY_IMPLICATION(!targetTreeScopeAncestors.isEmpty());

        unsigned i = m_ancestorTreeScopes.size();
        unsigned j = targetTreeScopeAncestors.size();
        ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.last() == targetTreeScopeAncestors.last());
        while (m_ancestorTreeScopes[i - 1] == targetTreeScopeAncestors[j - 1]) {
            i--;
            j--;
            if (!i || !j)
                break;
        }

        m_lowestCommonAncestorIndex = i;
        m_retargetedRelatedNode = nodeInLowestCommonAncestor();
    }
Example #19
0
AtomicString SVGURIReference::fragmentIdentifierFromIRIString(const String& url, const TreeScope& treeScope)
{
    size_t start = url.find('#');
    if (start == kNotFound)
        return emptyAtom;

    const Document& document = treeScope.document();
    KURL base = start ? KURL(document.baseURI(), url.substring(0, start)) : document.baseURI();
    if (equalIgnoringFragmentIdentifier(base, document.url()))
        return AtomicString(url.substring(start + 1));

    return emptyAtom;
}
Example #20
0
void StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode)
{
    ASSERT(isMaster());
    ASSERT(!document().inStyleRecalc());

    if (!document().isActive())
        return;

    if (shouldUpdateDocumentStyleSheetCollection(updateMode))
        documentStyleSheetCollection()->updateActiveStyleSheets(this, updateMode);

    if (shouldUpdateShadowTreeStyleSheetCollection(updateMode)) {
        TreeScopeSet treeScopes = updateMode == FullStyleUpdate ? m_activeTreeScopes : m_dirtyTreeScopes;
        HashSet<TreeScope*> treeScopesRemoved;

        for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) {
            TreeScope* treeScope = *it;
            ASSERT(treeScope != m_document);
            ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(*treeScope));
            ASSERT(collection);
            collection->updateActiveStyleSheets(this, updateMode);
            if (!collection->hasStyleSheetCandidateNodes()) {
                treeScopesRemoved.add(treeScope);
                // When removing TreeScope from ActiveTreeScopes,
                // its resolver should be destroyed by invoking resetAuthorStyle.
                ASSERT(!treeScope->scopedStyleResolver());
            }
        }
        m_activeTreeScopes.removeAll(treeScopesRemoved);
    }

    InspectorInstrumentation::activeStyleSheetsUpdated(m_document);
    m_usesRemUnits = documentStyleSheetCollection()->usesRemUnits();

    m_dirtyTreeScopes.clear();
    m_documentScopeDirty = false;
}
Example #21
0
    Node* moveToParentOrShadowHost(Node& newTarget)
    {
        TreeScope& newTreeScope = newTarget.treeScope();
        if (&newTreeScope == m_currentTreeScope)
            return m_relatedNodeInCurrentTreeScope;

        if (m_currentTreeScope) {
            ASSERT(is<ShadowRoot>(m_currentTreeScope->rootNode()));
            ASSERT(&newTarget == downcast<ShadowRoot>(m_currentTreeScope->rootNode()).host());
            ASSERT(m_currentTreeScope->parentTreeScope() == &newTreeScope);
        }

        if (&newTreeScope == &m_relatedNodeTreeScope)
            m_relatedNodeInCurrentTreeScope = &m_relatedNode;
        else if (m_relatedNodeInCurrentTreeScope) {
            ASSERT(m_currentTreeScope);
            m_relatedNodeInCurrentTreeScope = &newTarget;
        } else {
            if (!m_currentTreeScope) {
                TreeScope* newTreeScopeAncestor = &newTreeScope;
                do {
                    m_relatedNodeInCurrentTreeScope = findHostOfTreeScopeInTargetTreeScope(m_relatedNodeTreeScope, *newTreeScopeAncestor);
                    newTreeScopeAncestor = newTreeScopeAncestor->parentTreeScope();
                    if (newTreeScopeAncestor == &m_relatedNodeTreeScope) {
                        m_relatedNodeInCurrentTreeScope = &m_relatedNode;
                        break;
                    }
                } while (newTreeScopeAncestor && !m_relatedNodeInCurrentTreeScope);
            }
            ASSERT(m_relatedNodeInCurrentTreeScope || findHostOfTreeScopeInTargetTreeScope(newTreeScope, m_relatedNodeTreeScope)
                || &newTreeScope.documentScope() != &m_relatedNodeTreeScope.documentScope());
        }

        m_currentTreeScope = &newTreeScope;

        return m_relatedNodeInCurrentTreeScope;
    }
Example #22
0
void ScopedStyleResolver::keyframesRulesAdded(const TreeScope& treeScope) {
  // Called when @keyframes rules are about to be added/removed from a
  // TreeScope. @keyframes rules may apply to animations on elements in the
  // same TreeScope as the stylesheet, or the host element in the parent
  // TreeScope if the TreeScope is a shadow tree.

  ScopedStyleResolver* resolver = treeScope.scopedStyleResolver();
  ScopedStyleResolver* parentResolver =
      treeScope.parentTreeScope()
          ? treeScope.parentTreeScope()->scopedStyleResolver()
          : nullptr;

  bool hadUnresolvedKeyframes = false;
  if (resolver && resolver->m_hasUnresolvedKeyframesRule) {
    resolver->m_hasUnresolvedKeyframesRule = false;
    hadUnresolvedKeyframes = true;
  }
  if (parentResolver && parentResolver->m_hasUnresolvedKeyframesRule) {
    parentResolver->m_hasUnresolvedKeyframesRule = false;
    hadUnresolvedKeyframes = true;
  }

  if (hadUnresolvedKeyframes) {
    // If an animation ended up not being started because no @keyframes
    // rules were found for the animation-name, we need to recalculate style
    // for the elements in the scope, including its shadow host if
    // applicable.
    invalidationRootForTreeScope(treeScope).setNeedsStyleRecalc(
        SubtreeStyleChange, StyleChangeReasonForTracing::create(
                                StyleChangeReason::StyleSheetChange));
    return;
  }

  // If we have animations running, added/removed @keyframes may affect these.
  treeScope.document().timeline().invalidateKeyframeEffects(treeScope);
}
Example #23
0
static inline KURL urlFromIRIStringWithFragmentIdentifier(const String& url, const TreeScope& treeScope, AtomicString& fragmentIdentifier)
{
    size_t startOfFragmentIdentifier = url.find('#');
    if (startOfFragmentIdentifier == kNotFound)
        return KURL();

    const Document& document = treeScope.document();

    // Exclude the '#' character when determining the fragmentIdentifier.
    fragmentIdentifier = AtomicString(url.substring(startOfFragmentIdentifier + 1));
    if (startOfFragmentIdentifier) {
        KURL base(document.baseURI(), url.substring(0, startOfFragmentIdentifier));
        return KURL(base, url.substring(startOfFragmentIdentifier));
    }

    return KURL(document.baseURI(), url.substring(startOfFragmentIdentifier));
}
Example #24
0
Node* HTMLCollection::namedItem(const AtomicString& name) const
{
    // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp
    // This method first searches for an object with a matching id
    // attribute. If a match is not found, the method then searches for an
    // object with a matching name attribute, but only on those elements
    // that are allowed a name attribute.

    ContainerNode* root = rootContainerNode();
    if (name.isEmpty() || !root)
        return 0;

    if (!overridesItemAfter() && root->isInTreeScope()) {
        TreeScope* treeScope = root->treeScope();
        Element* candidate = 0;
        if (treeScope->hasElementWithId(name.impl())) {
            if (!treeScope->containsMultipleElementsWithId(name))
                candidate = treeScope->getElementById(name);
        } else if (treeScope->hasElementWithName(name.impl())) {
            if (!treeScope->containsMultipleElementsWithName(name)) {
                candidate = treeScope->getElementByName(name);
                if (candidate && type() == DocAll && (!candidate->isHTMLElement() || !nameShouldBeVisibleInDocumentAll(toHTMLElement(candidate))))
                    candidate = 0;
            }
        } else
            return 0;

        if (candidate
            && isMatchingElement(this, candidate)
            && (shouldOnlyIncludeDirectChildren() ? candidate->parentNode() == root : candidate->isDescendantOf(root)))
            return candidate;
    }

    // The pathological case. We need to walk the entire subtree.
    updateNameCache();

    if (Vector<Element*>* idResults = idCache(name)) {
        if (idResults->size())
            return idResults->at(0);
    }

    if (Vector<Element*>* nameResults = nameCache(name)) {
        if (nameResults->size())
            return nameResults->at(0);
    }

    return 0;
}
PassRefPtrWillBeRawPtr<ShadowRoot> createShadowRootForElementWithIDAndSetInnerHTML(TreeScope& scope, const char* hostElementID, const char* shadowRootContent)
{
    RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = scope.getElementById(AtomicString::fromUTF8(hostElementID))->createShadowRoot(ASSERT_NO_EXCEPTION);
    shadowRoot->setInnerHTML(String::fromUTF8(shadowRootContent), ASSERT_NO_EXCEPTION);
    return shadowRoot.release();
}
DocumentStyleSheetCollection::DocumentStyleSheetCollection(TreeScope& treeScope)
    : TreeScopeStyleSheetCollection(treeScope)
{
    ASSERT(treeScope.rootNode() == treeScope.rootNode().document());
}
PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, RenderObject* renderer, FilterEffect* previousEffect, const ReferenceFilterOperation* filterOperation)
{
    if (!renderer)
        return nullptr;

    TreeScope* treeScope = &renderer->node()->treeScope();

    if (DocumentResourceReference* documentResourceRef = documentResourceReference(filterOperation)) {
        DocumentResource* cachedSVGDocument = documentResourceRef->document();

        // If we have an SVG document, this is an external reference. Otherwise
        // we look up the referenced node in the current document.
        if (cachedSVGDocument)
            treeScope = cachedSVGDocument->document();
    }

    if (!treeScope)
        return nullptr;

    Element* filter = treeScope->getElementById(filterOperation->fragment());

    if (!filter) {
        // Although we did not find the referenced filter, it might exist later
        // in the document.
        treeScope->document().accessSVGExtensions().addPendingResource(filterOperation->fragment(), toElement(renderer->node()));
        return nullptr;
    }

    if (!isSVGFilterElement(*filter))
        return nullptr;

    SVGFilterElement& filterElement = toSVGFilterElement(*filter);

    // FIXME: Figure out what to do with SourceAlpha. Right now, we're
    // using the alpha of the original input layer, which is obviously
    // wrong. We should probably be extracting the alpha from the
    // previousEffect, but this requires some more processing.
    // This may need a spec clarification.
    RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(previousEffect, SourceAlpha::create(parentFilter));

    ColorSpace filterColorSpace = ColorSpaceDeviceRGB;
    bool useFilterColorSpace = getSVGElementColorSpace(&filterElement, filterColorSpace);

    for (SVGElement* element = Traversal<SVGElement>::firstChild(filterElement); element; element = Traversal<SVGElement>::nextSibling(*element)) {
        if (!element->isFilterEffect())
            continue;

        SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element);

        RefPtr<FilterEffect> effect = effectElement->build(builder.get(), parentFilter);
        if (!effect)
            continue;

        effectElement->setStandardAttributes(effect.get());
        effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement.primitiveUnits()->currentValue()->enumValue(), parentFilter->sourceImageRect()));
        ColorSpace colorSpace = filterColorSpace;
        if (useFilterColorSpace || getSVGElementColorSpace(effectElement, colorSpace))
            effect->setOperatingColorSpace(colorSpace);
        builder->add(AtomicString(effectElement->result()->currentValue()->value()), effect);
    }
    return builder->lastEffect();
}