Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
// 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;
}
Ejemplo n.º 5
0
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();
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
0
static inline bool isTreeScopeRoot(const ContainerNode& node)
{
    return node.isDocumentNode() || node.isShadowRoot();
}
Ejemplo n.º 12
0
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();
}