void ScopedStyleResolver::addTreeBoundaryCrossingRules(const RuleSet& authorRules, CSSStyleSheet* parentStyleSheet, unsigned sheetIndex)
{
    bool isDocumentScope = treeScope().rootNode().isDocumentNode();
    if (authorRules.deepCombinatorOrShadowPseudoRules().isEmpty()
        && (isDocumentScope || (authorRules.contentPseudoElementRules().isEmpty() && authorRules.slottedPseudoElementRules().isEmpty())))
        return;

    if (!authorRules.deepCombinatorOrShadowPseudoRules().isEmpty())
        m_hasDeepOrShadowSelector = true;

    OwnPtrWillBeRawPtr<RuleSet> ruleSetForScope = RuleSet::create();
    addRules(ruleSetForScope.get(), authorRules.deepCombinatorOrShadowPseudoRules());

    if (!isDocumentScope) {
        addRules(ruleSetForScope.get(), authorRules.contentPseudoElementRules());
        addRules(ruleSetForScope.get(), authorRules.slottedPseudoElementRules());
    }

    if (!m_treeBoundaryCrossingRuleSet) {
        m_treeBoundaryCrossingRuleSet = adoptPtrWillBeNoop(new CSSStyleSheetRuleSubSet());
        treeScope().document().styleResolver()->addTreeBoundaryCrossingScope(treeScope().rootNode());
    }

    m_treeBoundaryCrossingRuleSet->append(RuleSubSet::create(parentStyleSheet, sheetIndex, ruleSetForScope.release()));
}
Пример #2
0
void HTMLMapElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
    // FIXME: This logic seems wrong for XML documents.
    // Either the id or name will be used depending on the order the attributes are parsed.

    if (isIdAttributeName(name) || name == nameAttr) {
        if (isIdAttributeName(name)) {
            // Call base class so that hasID bit gets set.
            HTMLElement::parseAttribute(name, value);
            if (document().isHTMLDocument())
                return;
        }
        if (inDocument())
            treeScope().removeImageMap(this);
        String mapName = value;
        if (mapName[0] == '#')
            mapName = mapName.substring(1);
        m_name = AtomicString(document().isHTMLDocument() ? mapName.lower() : mapName);
        if (inDocument())
            treeScope().addImageMap(this);

        return;
    }

    HTMLElement::parseAttribute(name, value);
}
void ScopedStyleResolver::appendCSSStyleSheet(CSSStyleSheet& cssSheet, const MediaQueryEvaluator& medium)
{
    unsigned index = m_authorStyleSheets.size();
    m_authorStyleSheets.append(&cssSheet);
    StyleSheetContents* sheet = cssSheet.contents();
    AddRuleFlags addRuleFlags = treeScope().document().securityOrigin()->canRequest(sheet->baseURL()) ? RuleHasDocumentSecurityOrigin : RuleHasNoSpecialState;
    const RuleSet& ruleSet = sheet->ensureRuleSet(medium, addRuleFlags);

    addKeyframeRules(ruleSet);
    addFontFaceRules(ruleSet);
    addTreeBoundaryCrossingRules(ruleSet, &cssSheet, index);
    treeScope().document().styleResolver()->addMediaQueryResults(ruleSet.viewportDependentMediaQueryResults());
}
Пример #4
0
// getElementById on SVGSVGElement is restricted to only the child subtree defined by the <svg> element.
// See http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGSVGElement
Element* SVGSVGElement::getElementById(const String& id)
{
    Element* element = treeScope().getElementById(id);
    if (element && element->isDescendantOf(this))
        return element;
    if (treeScope().containsMultipleElementsWithId(id)) {
        for (auto element : *treeScope().getAllElementsById(id)) {
            if (element->isDescendantOf(this))
                return element;
        }
    }
    return nullptr;
}
Пример #5
0
void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild)
{
    ASSERT(newChild);
    ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events).
    ASSERT(!newChild->isDocumentFragment());
#if ENABLE(TEMPLATE_ELEMENT)
    ASSERT(!hasTagName(HTMLNames::templateTag));
#endif

    if (&document() != &newChild->document())
        document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);

    {
        NoEventDispatchAssertion assertNoEventDispatch;
        // FIXME: This method should take a PassRefPtr.
        appendChildToContainer(newChild.get(), *this);
        treeScope().adoptIfNeeded(newChild.get());
    }

    newChild->updateAncestorConnectedSubframeCountForInsertion();

    ChildListMutationScope(*this).childAdded(*newChild);

    notifyChildInserted(*newChild, ChildChangeSourceParser);

    ChildNodeInsertionNotifier(*this).notify(*newChild);

    newChild->setNeedsStyleRecalc(ReconstructRenderTree);
}
Пример #6
0
void DocumentStyleSheetCollection::updateActiveStyleSheets(StyleEngine* engine, StyleResolverUpdateMode updateMode)
{
    StyleSheetCollection collection;
    ActiveDocumentStyleSheetCollector collector(collection);
    collectStyleSheets(engine, collector);

    StyleSheetChange change;
    analyzeStyleSheetChange(updateMode, collection, change);

    if (change.styleResolverUpdateType == Reconstruct) {
        engine->clearMasterResolver();
        // FIMXE: The following depends on whether StyleRuleFontFace was modified or not.
        // No need to always-clear font cache.
        engine->clearFontCache();
    } else if (StyleResolver* styleResolver = engine->resolver()) {
        if (change.styleResolverUpdateType != Additive) {
            ASSERT(change.styleResolverUpdateType == Reset);
            styleResolver->resetAuthorStyle(treeScope());
            engine->removeFontFaceRules(change.fontFaceRulesToRemove);
            styleResolver->removePendingAuthorStyleSheets(m_activeAuthorStyleSheets);
            styleResolver->lazyAppendAuthorStyleSheets(0, collection.activeAuthorStyleSheets());
        } else {
            styleResolver->lazyAppendAuthorStyleSheets(m_activeAuthorStyleSheets.size(), collection.activeAuthorStyleSheets());
        }
    }
    if (change.requiresFullStyleRecalc)
        document().setNeedsStyleRecalc(SubtreeStyleChange);

    collection.swap(*this);

    updateUsesRemUnits();
}
Пример #7
0
void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent)
{
    NodeVector children;
    getChildNodes(oldParent, children);

    if (oldParent->document()->hasMutationObserversOfType(MutationObserver::ChildList)) {
        ChildListMutationScope mutation(oldParent);
        for (unsigned i = 0; i < children.size(); ++i)
            mutation.willRemoveChild(children[i].get());
    }

    // FIXME: We need to do notifyMutationObserversNodeWillDetach() for each child,
    // probably inside removeDetachedChildrenInContainer.

    oldParent->removeDetachedChildren();

    for (unsigned i = 0; i < children.size(); ++i) {
        if (children[i]->attached())
            children[i]->detach();
        // FIXME: We need a no mutation event version of adoptNode.
        RefPtr<Node> child = document()->adoptNode(children[i].release(), ASSERT_NO_EXCEPTION);
        parserAppendChild(child.get());
        // FIXME: Together with adoptNode above, the tree scope might get updated recursively twice
        // (if the document changed or oldParent was in a shadow tree, AND *this is in a shadow tree).
        // Can we do better?
        treeScope()->adoptIfNeeded(child.get());
        if (attached() && !child->attached())
            child->attach();
    }
}
Пример #8
0
void SVGUseElement::buildPendingResource()
{
    if (inUseShadowTree())
        return;
    clearShadowTree();
    cancelShadowTreeRecreation();
    if (!referencedScope() || !inDocument())
        return;

    AtomicString id;
    Element* target = SVGURIReference::targetElementFromIRIString(hrefString(), treeScope(), &id, externalDocument());
    if (!target || !target->inDocument()) {
        // If we can't find the target of an external element, just give up.
        // We can't observe if the target somewhen enters the external document, nor should we do it.
        if (externalDocument())
            return;
        if (id.isEmpty())
            return;

        referencedScope()->document().accessSVGExtensions().addPendingResource(id, this);
        ASSERT(hasPendingResources());
        return;
    }

    if (target->isSVGElement()) {
        buildShadowAndInstanceTree(toSVGElement(target));
        invalidateDependentShadowTrees();
    }

    ASSERT(!m_needsShadowTreeRecreation);
}
void ScopedStyleResolver::collectMatchingTreeBoundaryCrossingRules(ElementRuleCollector& collector, CascadeOrder cascadeOrder)
{
    for (const auto& rules : *m_treeBoundaryCrossingRuleSet) {
        MatchRequest request(rules->m_ruleSet.get(), &treeScope().rootNode(), rules->m_parentStyleSheet, rules->m_parentIndex);
        collector.collectMatchingRules(request, cascadeOrder, true);
    }
}
Пример #10
0
String SVGElement::title() const
{
    // According to spec, we should not return titles when hovering over root <svg> elements (those
    // <title> elements are the title of the document, not a tooltip) so we instantly return.
    if (isOutermostSVGSVGElement())
        return String();

    // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.
    if (isInShadowTree()) {
        Element* shadowHostElement = toShadowRoot(treeScope().rootNode()).host();
        // At this time, SVG nodes are not allowed in non-<use> shadow trees, so any shadow root we do
        // have should be a use. The assert and following test is here to catch future shadow DOM changes
        // that do enable SVG in a shadow tree.
        ASSERT(!shadowHostElement || isSVGUseElement(*shadowHostElement));
        if (isSVGUseElement(shadowHostElement)) {
            SVGUseElement& useElement = toSVGUseElement(*shadowHostElement);

            // If the <use> title is not empty we found the title to use.
            String useTitle(useElement.title());
            if (!useTitle.isEmpty())
                return useTitle;
        }
    }

    // If we aren't an instance in a <use> or the <use> title was not found, then find the first
    // <title> child of this element.
    // If a title child was found, return the text contents.
    if (Element* titleElement = Traversal<SVGTitleElement>::firstChild(*this))
        return titleElement->innerText();

    // Otherwise return a null/empty string.
    return String();
}
void ScopedStyleResolver::addFontFaceRules(const RuleSet& ruleSet)
{
    // FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for the moment.
    if (!treeScope().rootNode().isDocumentNode())
        return;

    Document& document = treeScope().document();
    CSSFontSelector* cssFontSelector = document.styleEngine().fontSelector();
    const WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace>> fontFaceRules = ruleSet.fontFaceRules();
    for (auto& fontFaceRule : fontFaceRules) {
        if (RefPtrWillBeRawPtr<FontFace> fontFace = FontFace::create(&document, fontFaceRule))
            cssFontSelector->fontFaceCache()->add(cssFontSelector, fontFaceRule, fontFace);
    }
    if (fontFaceRules.size())
        document.styleResolver()->invalidateMatchedPropertiesCache();
}
Пример #12
0
void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild)
{
    ASSERT(newChild);
    ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events).
    ASSERT(!newChild->isDocumentFragment());
    ASSERT(!hasTagName(HTMLNames::templateTag));

    if (document() != newChild->document())
        document()->adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);

    Node* last = m_lastChild;
    {
        NoEventDispatchAssertion assertNoEventDispatch;
        // FIXME: This method should take a PassRefPtr.
        appendChildToContainer(newChild.get(), this);
        treeScope()->adoptIfNeeded(newChild.get());
    }

    newChild->updateAncestorConnectedSubframeCountForInsertion();

    ChildListMutationScope(this).childAdded(newChild.get());

    childrenChanged(true, last, 0, 1);
    ChildNodeInsertionNotifier(this).notify(newChild.get());
}
Пример #13
0
void HTMLElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
    if (isIdAttributeName(name) || name == classAttr || name == styleAttr)
        return Element::parseAttribute(name, value);

    if (name == dirAttr)
        dirAttributeChanged(value);
    else if (name == tabindexAttr) {
        int tabindex = 0;
        if (value.isEmpty()) {
            clearTabIndexExplicitlyIfNeeded();
            if (treeScope().adjustedFocusedElement() == this) {
                // We might want to call blur(), but it's dangerous to dispatch
                // events here.
                document().setNeedsFocusedElementCheck();
            }
        } else if (parseHTMLInteger(value, tabindex)) {
            // Clamp tabindex to the range of 'short' to match Firefox's behavior.
            setTabIndexExplicitly(max(static_cast<int>(std::numeric_limits<short>::min()), min(tabindex, static_cast<int>(std::numeric_limits<short>::max()))));
        }
    } else {
        const AtomicString& eventName = eventNameForAttributeName(name);
        if (!eventName.isNull())
            setAttributeEventListener(eventName, createAttributeEventListener(this, name, value));
    }
}
inline SVGElement* SVGSMILElement::eventBaseFor(const Condition& condition)
{
    Element* eventBase = condition.baseID().isEmpty() ? targetElement() : treeScope().getElementById(AtomicString(condition.baseID()));
    if (eventBase && eventBase->isSVGElement())
        return toSVGElement(eventBase);
    return nullptr;
}
void ScopedStyleResolver::collectMatchingTreeBoundaryCrossingRules(ElementRuleCollector& collector, bool includeEmptyRules, CascadeOrder cascadeOrder)
{
    RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange();
    for (const auto& rules : *m_treeBoundaryCrossingRuleSet) {
        MatchRequest request(rules->m_ruleSet.get(), includeEmptyRules, &treeScope().rootNode(), rules->m_parentStyleSheet, rules->m_parentIndex);
        collector.collectMatchingRules(request, ruleRange, cascadeOrder, true);
    }
}
Пример #16
0
bool Element::affectedByAttributeSelector(const AtomicString& attributeName) const
{
    if (attributeName.isEmpty())
        return false;
    if (treeScope().scopedStyleResolver().hasSelectorForAttribute(attributeName))
        return true;
    return false;
}
Пример #17
0
bool Element::affectedByIdSelector(const AtomicString& idValue) const
{
    if (idValue.isEmpty())
        return false;
    if (treeScope().scopedStyleResolver().hasSelectorForId(idValue))
        return true;
    return false;
}
Пример #18
0
bool HTMLShadowElement::doesSelectFromHostChildren() const
{
    TreeScope* scope = treeScope();

    if (scope->isShadowRoot())
        return toShadowRoot(scope)->isOldest();
    return false;
}
ScopedStyleResolver* ScopedStyleResolver::parent() const
{
    for (TreeScope* scope = treeScope().parentTreeScope(); scope; scope = scope->parentTreeScope()) {
        if (ScopedStyleResolver* resolver = scope->scopedStyleResolver())
            return resolver;
    }
    return nullptr;
}
Пример #20
0
void SVGTRefElement::updateReferencedText()
{
    Element* target = treeScope()->getElementById(SVGURIReference::getTarget(href()));
    String textContent;
    if (target && target->isSVGElement())
        textContent = static_cast<SVGElement*>(target)->textContent();
    ExceptionCode ignore = 0;
    setTextContent(textContent, ignore);
}
Пример #21
0
bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, AttachBehavior attachBehavior)
{
    RefPtr<ContainerNode> protect(this);

    // Check that this node is not "floating".
    // If it is, it can be deleted as a side effect of sending mutation events.
    ASSERT(refCount() || parentOrShadowHostNode());

    ec = 0;

    // Make sure adding the new child is ok
    if (!checkAddChild(this, newChild.get(), ec))
        return false;

    if (newChild == m_lastChild) // nothing to do
        return newChild;

    NodeVector targets;
    collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec);
    if (ec)
        return false;

    if (targets.isEmpty())
        return true;

    // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
    if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec))
        return false;

    InspectorInstrumentation::willInsertDOMNode(document(), this);

    // Now actually add the child(ren)
    ChildListMutationScope mutation(this);
    for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
        Node* child = it->get();

        // If the child has a parent again, just stop what we're doing, because
        // that means someone is doing something with DOM mutation -- can't re-parent
        // a child that already has a parent.
        if (child->parentNode())
            break;

        treeScope()->adoptIfNeeded(child);

        // Append child to the end of the list
        {
            NoEventDispatchAssertion assertNoEventDispatch;
            appendChildToContainer(child, this);
        }

        updateTreeAfterInsertion(this, child, attachBehavior);
    }

    dispatchSubtreeModifiedEvent();
    return true;
}
void ScopedStyleResolver::addTreeBoundaryCrossingRules(const RuleSet& authorRules, CSSStyleSheet* parentStyleSheet, unsigned sheetIndex)
{
    bool isDocumentScope = treeScope().rootNode().isDocumentNode();
    if (authorRules.treeBoundaryCrossingRules().isEmpty() && (isDocumentScope || authorRules.shadowDistributedRules().isEmpty()))
        return;

    OwnPtrWillBeRawPtr<RuleSet> ruleSetForScope = RuleSet::create();
    addRules(ruleSetForScope.get(), authorRules.treeBoundaryCrossingRules());

    if (!isDocumentScope)
        addRules(ruleSetForScope.get(), authorRules.shadowDistributedRules());

    if (!m_treeBoundaryCrossingRuleSet) {
        m_treeBoundaryCrossingRuleSet = adoptPtrWillBeNoop(new CSSStyleSheetRuleSubSet());
        treeScope().document().styleResolver()->addTreeBoundaryCrossingScope(treeScope().rootNode());
    }

    m_treeBoundaryCrossingRuleSet->append(RuleSubSet::create(parentStyleSheet, sheetIndex, ruleSetForScope.release()));
}
Пример #23
0
void Element::removedFrom(ContainerNode* insertionPoint)
{
    if (insertionPoint->isInTreeScope() && treeScope() == document()) {
        const AtomicString& idValue = getIdAttribute();
        if (!idValue.isNull())
            updateId(insertionPoint->treeScope(), idValue, nullAtom);
    }

    ContainerNode::removedFrom(insertionPoint);
}
Пример #24
0
inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
{
    if (!isInTreeScope())
        return;

    if (oldId == newId)
        return;

    updateId(treeScope(), oldId, newId);
}
PassRefPtrWillBeRawPtr<FilterEffect> SVGFEImageElement::build(SVGFilterBuilder*, Filter* filter)
{
    if (m_cachedImage) {
        // Don't use the broken image icon on image loading errors.
        RefPtr<Image> image = m_cachedImage->errorOccurred() ?
            nullptr : m_cachedImage->image();
        return FEImage::createWithImage(filter, image, m_preserveAspectRatio->currentValue());
    }

    return FEImage::createWithIRIReference(filter, treeScope(), hrefString(), m_preserveAspectRatio->currentValue());
}
Пример #26
0
ShadowRoot* InsertionPoint::assignedFrom() const
{
    TreeScope* scope = treeScope();
    if (!scope->isShadowRoot())
        return 0;

    ShadowRoot* olderShadowRoot = toShadowRoot(scope)->olderShadowRoot();
    if (olderShadowRoot && olderShadowRoot->assignedTo() == this)
        return olderShadowRoot;
    return 0;
}
Пример #27
0
HTMLMenuElement* HTMLElement::contextMenu() const
{
    const AtomicString& contextMenuId(fastGetAttribute(contextmenuAttr));
    if (contextMenuId.isNull())
        return nullptr;

    Element* element = treeScope().getElementById(contextMenuId);
    // Not checking if the menu element is of type "popup".
    // Ignoring menu element type attribute is intentional according to the standard.
    return isHTMLMenuElement(element) ? toHTMLMenuElement(element) : nullptr;
}
Пример #28
0
ShadowRoot* InsertionPoint::assignedFrom() const
{
    Node* treeScopeRoot = treeScope()->rootNode();
    if (!treeScopeRoot->isShadowRoot())
        return 0;

    ShadowRoot* olderShadowRoot = toShadowRoot(treeScopeRoot)->olderShadowRoot();
    if (olderShadowRoot && olderShadowRoot->assignedTo() == this)
        return olderShadowRoot;
    return 0;
}
Пример #29
0
// getElementById on SVGSVGElement is restricted to only the child subtree defined by the <svg> element.
// See http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGSVGElement
Element* SVGSVGElement::getElementById(const AtomicString& id)
{
    Element* element = treeScope().getElementById(id);
    if (element && element->isDescendantOf(this))
        return element;

    // Fall back to traversing our subtree. Duplicate ids are allowed, the first found will
    // be returned.
    for (auto& element : descendantsOfType<Element>(*this)) {
        if (element.getIdAttribute() == id)
            return &element;
    }
    return 0;
}
Пример #30
0
Element* DocumentFragment::getElementById(const AtomicString& id) const
{
    // Fast path for ShadowRoot, where we are both a DocumentFragment and a TreeScope.
    if (isTreeScope())
        return treeScope().getElementById(id);

    // Otherwise, fall back to iterating all of the element descendants.
    for (auto& element : elementDescendants(*this)) {
        if (element.getIdAttribute() == id)
            return const_cast<Element*>(&element);
    }

    return nullptr;
}