Exemple #1
0
void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
{
#if ENABLE(TEMPLATE_ELEMENT)
    // When a node is to be foster parented, the last template element with no table element is below it in the stack of open elements is the foster parent element (NOT the template's parent!)
    HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
    if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
        task.parent = lastTemplateElement->element();
        return;
    }

#endif

    HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
    if (lastTableElementRecord) {
        Element* lastTableElement = lastTableElementRecord->element();
        ContainerNode* parent = lastTableElement->parentNode();
        // When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
        // and instead use the DocumentFragment as a root node. So we must treat the root node (DocumentFragment) as if it is a html element here.
        if (parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()))) {
            task.parent = parent;
            task.nextChild = lastTableElement;
            return;
        }
        task.parent = lastTableElementRecord->next()->element();
        return;
    }
    // Fragment case
    task.parent = m_openElements.rootNode(); // DocumentFragment
}
Exemple #2
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;
}
Exemple #3
0
// Step 3 of http://www.whatwg.org/specs/web-apps/current-work/multipage/apis-in-html-documents.html#insertadjacenthtml()
static Element* contextElementForInsertion(const String& where, Element* element, ExceptionCode& ec)
{
    if (equalIgnoringCase(where, "beforeBegin") || equalIgnoringCase(where, "afterEnd")) {
        ContainerNode* parent = element->parentNode();
        if (parent && !parent->isElementNode()) {
            ec = NO_MODIFICATION_ALLOWED_ERR;
            return 0;
        }
        ASSERT_WITH_SECURITY_IMPLICATION(!parent || parent->isElementNode());
        return toElement(parent);
    }
    if (equalIgnoringCase(where, "afterBegin") || equalIgnoringCase(where, "beforeEnd"))
        return element;
    ec =  SYNTAX_ERR;
    return 0;
}
Exemple #4
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;
}
Exemple #5
0
void HTMLSourceElement::removedFrom(ContainerNode& removalRoot)
{
    Element* parent = parentElement();
    if (!parent && removalRoot.isElementNode())
        parent = &toElement(removalRoot);
    if (parent && parent->isMediaElement())
        toHTMLMediaElement(parent)->sourceWasRemoved(this);
    HTMLElement::removedFrom(removalRoot);
}
Exemple #6
0
XMLDocumentParser::XMLDocumentParser(DocumentFragment* fragment, Element* parentElement, FragmentScriptingPermission scriptingPermission)
    : ScriptableDocumentParser(fragment->document())
    , m_view(0)
    , m_context(0)
    , m_pendingCallbacks(PendingCallbacks::create())
    , m_currentNode(fragment)
    , m_sawError(false)
    , m_sawCSS(false)
    , m_sawXSLTransform(false)
    , m_sawFirstElement(false)
    , m_isXHTMLDocument(false)
#if ENABLE(XHTMLMP)
    , m_isXHTMLMPDocument(false)
    , m_hasDocTypeDeclaration(false)
#endif
    , m_parserPaused(false)
    , m_requestingScript(false)
    , m_finishCalled(false)
    , m_errorCount(0)
    , m_lastErrorPosition(TextPosition1::belowRangePosition())
    , m_pendingScript(0)
    , m_scriptStartPosition(TextPosition1::belowRangePosition())
    , m_parsingFragment(true)
    , m_scriptingPermission(scriptingPermission)
{
    fragment->ref();

    // Add namespaces based on the parent node
    Vector<Element*> elemStack;
    while (parentElement) {
        elemStack.append(parentElement);

        ContainerNode* n = parentElement->parentNode();
        if (!n || !n->isElementNode())
            break;
        parentElement = static_cast<Element*>(n);
    }

    if (elemStack.isEmpty())
        return;

    for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) {
        if (NamedNodeMap* attrs = element->attributes()) {
            for (unsigned i = 0; i < attrs->length(); i++) {
                Attribute* attr = attrs->attributeItem(i);
                if (attr->localName() == xmlnsAtom)
                    m_defaultNamespaceURI = attr->value();
                else if (attr->prefix() == xmlnsAtom)
                    m_prefixToNamespaceMap.set(attr->localName(), attr->value());
            }
        }
    }

    // If the parent element is not in document tree, there may be no xmlns attribute; just default to the parent's namespace.
    if (m_defaultNamespaceURI.isNull() && !parentElement->inDocument())
        m_defaultNamespaceURI = parentElement->namespaceURI();
}
Exemple #7
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;
}
void SelectorDataList::executeSlowTraversingShadowTree(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
{
    for (ContainerNode* node = firstWithinTraversingShadowTree(rootNode); node; node = nextTraversingShadowTree(*node, &rootNode)) {
        if (!node->isElementNode())
            continue;
        Element* element = toElement(node);
        if (selectorListMatches<SelectorQueryTrait>(rootNode, *element, output) && SelectorQueryTrait::shouldOnlyMatchFirstElement)
            return;
    }
}
inline bool ancestorHasClassName(ContainerNode& rootNode, const AtomicString& className)
{
    if (!rootNode.isElementNode())
        return false;

    for (Element* element = &toElement(rootNode); element; element = element->parentElement()) {
        if (element->hasClass() && element->classNames().contains(className))
            return true;
    }
    return false;
}
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;
}
Exemple #11
0
Element* HTMLStyleElement::scopingElement() const
{
    if (!scoped())
        return 0;

    // FIXME: This probably needs to be refined for scoped stylesheets within shadow DOM.
    // As written, such a stylesheet could style the host element, as well as children of the host.
    // OTOH, this paves the way for a :bound-element implementation.
    ContainerNode* parentOrHost = parentOrHostNode();
    if (!parentOrHost || !parentOrHost->isElementNode())
        return 0;

    return toElement(parentOrHost);
}
// Step 3 of http://www.whatwg.org/specs/web-apps/current-work/multipage/apis-in-html-documents.html#insertadjacenthtml()
static Element* contextElementForInsertion(const String& where, Element* element, ExceptionState& es)
{
    if (equalIgnoringCase(where, "beforeBegin") || equalIgnoringCase(where, "afterEnd")) {
        ContainerNode* parent = element->parentNode();
        if (parent && !parent->isElementNode()) {
            es.throwDOMException(NoModificationAllowedError);
            return 0;
        }
        return toElement(parent);
    }
    if (equalIgnoringCase(where, "afterBegin") || equalIgnoringCase(where, "beforeEnd"))
        return element;
    es.throwDOMException(SyntaxError);
    return 0;
}
Exemple #13
0
// Step 1 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
static Element* contextElementForInsertion(const String& where, Element* element, ExceptionState& exceptionState)
{
    if (equalIgnoringCase(where, "beforeBegin") || equalIgnoringCase(where, "afterEnd")) {
        ContainerNode* parent = element->parentNode();
        if (!parent || !parent->isElementNode()) {
            exceptionState.throwDOMException(NoModificationAllowedError, "The element has no parent.");
            return 0;
        }
        return toElement(parent);
    }
    if (equalIgnoringCase(where, "afterBegin") || equalIgnoringCase(where, "beforeEnd"))
        return element;
    exceptionState.throwDOMException(SyntaxError, "The value provided ('" + where + "') is not one of 'beforeBegin', 'afterBegin', 'beforeEnd', or 'afterEnd'.");
    return 0;
}
Exemple #14
0
void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
{
    HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
    if (lastTableElementRecord) {
        Element* lastTableElement = lastTableElementRecord->element();
        ContainerNode* parent = lastTableElement->parentNode();
        // When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
        // and instead use the DocumentFragment as a root node. So we must treat the root node (DocumentFragment) as if it is a html element here.
        if (parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()))) {
            task.parent = parent;
            task.nextChild = lastTableElement;
            return;
        }
        task.parent = lastTableElementRecord->next()->element();
        return;
    }
    // Fragment case
    task.parent = m_openElements.rootNode(); // DocumentFragment
}
XMLTreeBuilder::XMLTreeBuilder(NewXMLDocumentParser* parser, DocumentFragment* fragment, Element* parent)
    : m_document(fragment->document())
    , m_parser(parser)
    , m_isXHTML(false)
    , m_sawFirstElement(true)
{
    NodeStackItem stackItem(fragment);

    // Figure out namespaces
    Vector<Element*> nodeStack;
    while (parent) {
        nodeStack.append(parent);

        ContainerNode* node = parent->parentNode();
        if (!node || !node->isElementNode())
            break;
        parent = static_cast<Element*>(node);
    }

    if (nodeStack.isEmpty()) {
        m_currentNodeStack.append(stackItem);
        return;
    }

    for (Element* element; !nodeStack.isEmpty(); nodeStack.removeLast()) {
        element = nodeStack.last();
        if (element->hasAttributes()) {
            for (size_t i = 0; i < element->attributeCount(); ++i) {
                Attribute* attr = element->attributeItem(i);
                if (attr->localName() == xmlnsAtom)
                    stackItem.setNamespaceURI(attr->value());
                else if (attr->prefix() == xmlnsAtom)
                    stackItem.setNamespaceURI(attr->localName(), attr->value());
            }
        }
    }

    // If the parent element is not in document tree, there may be no xmlns attribute; just default to the parent's namespace.
    if (stackItem.namespaceURI().isNull() && !parent->inDocument())
        stackItem.setNamespaceURI(parent->namespaceURI());

    m_currentNodeStack.append(stackItem);
}
void StyledMarkupTraverser<Strategy>::wrapWithNode(ContainerNode& node, RawPtr<EditingStyle> style)
{
    if (!m_accumulator)
        return;
    StringBuilder markup;
    if (node.isDocumentNode()) {
        MarkupFormatter::appendXMLDeclaration(markup, toDocument(node));
        m_accumulator->pushMarkup(markup.toString());
        return;
    }
    if (!node.isElementNode())
        return;
    Element& element = toElement(node);
    if (shouldApplyWrappingStyle(element) || needsInlineStyle(element))
        m_accumulator->appendElementWithInlineStyle(markup, element, style);
    else
        m_accumulator->appendElement(markup, element);
    m_accumulator->pushMarkup(markup.toString());
    m_accumulator->appendEndTag(toElement(node));
}
Node* previousSiblingSlow(const Node* node)
{
    ASSERT(!node->isShadowRoot());

    Node* previousSibling = 0;
    if (node->isAfterPseudoElement()) {
        ContainerNode* parent = traverseParent(node, CrossShadowRoot);
        previousSibling = traverseLastChild(parent, CrossShadowRoot);
    } else
        previousSibling = traversePreviousSibling(node);

    if (previousSibling || node->isBeforePseudoElement())
        return previousSibling;

    ContainerNode* parent = traverseParent(node, CrossShadowRoot);
    if (parent && parent->isElementNode())
        return toElement(parent)->beforePseudoElement();

    return 0;
}
Exemple #18
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;
}
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;
}
Exemple #21
0
Node* StyledMarkupAccumulator::traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode traversalMode)
{
    const bool shouldEmit = traversalMode == EmitString;
    Vector<RawPtr<ContainerNode> > ancestorsToClose;
    Node* next;
    Node* lastClosed = 0;
    for (Node* n = startNode; n != pastEnd; n = next) {
        // According to <rdar://problem/5730668>, it is possible for n to blow
        // past pastEnd and become null here. This shouldn't be possible.
        // This null check will prevent crashes (but create too much markup)
        // and the ASSERT will hopefully lead us to understanding the problem.
        ASSERT(n);
        if (!n)
            break;

        next = NodeTraversal::next(*n);
        bool openedTag = false;

        if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd)
            // Don't write out empty block containers that aren't fully selected.
            continue;

        if (!n->renderer() && m_shouldAnnotate != AnnotateForNavigationTransition) {
            next = NodeTraversal::nextSkippingChildren(*n);
            // Don't skip over pastEnd.
            if (pastEnd && pastEnd->isDescendantOf(n))
                next = pastEnd;
        } else {
            // Add the node to the markup if we're not skipping the descendants
            if (shouldEmit)
                appendStartTag(*n);

            // If node has no children, close the tag now.
            if (n->isContainerNode() && toContainerNode(n)->hasChildren()) {
                openedTag = true;
                ancestorsToClose.append(toContainerNode(n));
            } else {
                if (shouldEmit && n->isElementNode())
                    appendEndTag(toElement(*n));
                lastClosed = n;
            }
        }

        // If we didn't insert open tag and there's no more siblings or we're at the end of the traversal, take care of ancestors.
        // FIXME: What happens if we just inserted open tag and reached the end?
        if (!openedTag && (!n->nextSibling() || next == pastEnd)) {
            // Close up the ancestors.
            while (!ancestorsToClose.isEmpty()) {
                ContainerNode* ancestor = ancestorsToClose.last();
                ASSERT(ancestor);
                if (next != pastEnd && next->isDescendantOf(ancestor))
                    break;
                // Not at the end of the range, close ancestors up to sibling of next node.
                if (shouldEmit && ancestor->isElementNode())
                    appendEndTag(toElement(*ancestor));
                lastClosed = ancestor;
                ancestorsToClose.removeLast();
            }

            // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors.
            ContainerNode* nextParent = next ? next->parentNode() : 0;
            if (next != pastEnd && n != nextParent) {
                Node* lastAncestorClosedOrSelf = n->isDescendantOf(lastClosed) ? lastClosed : n;
                for (ContainerNode* parent = lastAncestorClosedOrSelf->parentNode(); parent && parent != nextParent; parent = parent->parentNode()) {
                    // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered:
                    if (!parent->renderer())
                        continue;
                    // or b) ancestors that we never encountered during a pre-order traversal starting at startNode:
                    ASSERT(startNode->isDescendantOf(parent));
                    if (shouldEmit)
                        wrapWithNode(*parent);
                    lastClosed = parent;
                }
            }
        }
    }

    return lastClosed;
}