void Text::reattachIfNeeded(const AttachContext& context)
{
    bool layoutObjectIsNeeded = false;
    ContainerNode* layoutParent = LayoutTreeBuilderTraversal::parent(*this);
    if (layoutParent) {
        if (LayoutObject* parentLayoutObject = layoutParent->layoutObject()) {
            if (textLayoutObjectIsNeeded(*parentLayoutObject->style(), *parentLayoutObject))
                layoutObjectIsNeeded = true;
        }
    }

    if (layoutObjectIsNeeded == !!layoutObject())
        return;

    // The following is almost the same as Node::reattach() except that we create a layoutObject only if needed.
    // Not calling reattach() to avoid repeated calls to Text::textLayoutObjectIsNeeded().
    AttachContext reattachContext(context);
    reattachContext.performingReattach = true;

    if (getStyleChangeType() < NeedsReattachStyleChange)
        detach(reattachContext);
    if (layoutObjectIsNeeded)
        LayoutTreeBuilderForText(*this, layoutParent->layoutObject()).createLayoutObject();
    CharacterData::attach(reattachContext);
}
bool HTMLFormElement::layoutObjectIsNeeded(const ComputedStyle& style)
{
    if (!m_wasDemoted)
        return HTMLElement::layoutObjectIsNeeded(style);

    ContainerNode* node = parentNode();
    if (!node || !node->layoutObject())
        return HTMLElement::layoutObjectIsNeeded(style);
    LayoutObject* parentLayoutObject = node->layoutObject();
    // FIXME: Shouldn't we also check for table caption (see |formIsTablePart| below).
    // FIXME: This check is not correct for Shadow DOM.
    bool parentIsTableElementPart = (parentLayoutObject->isTable() && isHTMLTableElement(*node))
        || (parentLayoutObject->isTableRow() && isHTMLTableRowElement(*node))
        || (parentLayoutObject->isTableSection() && node->hasTagName(tbodyTag))
        || (parentLayoutObject->isLayoutTableCol() && node->hasTagName(colTag))
        || (parentLayoutObject->isTableCell() && isHTMLTableRowElement(*node));

    if (!parentIsTableElementPart)
        return true;

    EDisplay display = style.display();
    bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
        || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
        || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
        || display == TABLE_CAPTION;

    return formIsTablePart;
}
void SVGFELightElement::svgAttributeChanged(const QualifiedName& attrName)
{
    if (attrName == SVGNames::azimuthAttr
        || attrName == SVGNames::elevationAttr
        || attrName == SVGNames::xAttr
        || attrName == SVGNames::yAttr
        || attrName == SVGNames::zAttr
        || attrName == SVGNames::pointsAtXAttr
        || attrName == SVGNames::pointsAtYAttr
        || attrName == SVGNames::pointsAtZAttr
        || attrName == SVGNames::specularExponentAttr
        || attrName == SVGNames::limitingConeAngleAttr) {
        ContainerNode* parent = parentNode();
        if (!parent)
            return;

        LayoutObject* layoutObject = parent->layoutObject();
        if (!layoutObject || !layoutObject->isSVGResourceFilterPrimitive())
            return;

        SVGElement::InvalidationGuard invalidationGuard(this);
        if (isSVGFEDiffuseLightingElement(*parent)) {
            toSVGFEDiffuseLightingElement(*parent).lightElementAttributeChanged(this, attrName);
            return;
        }
        if (isSVGFESpecularLightingElement(*parent)) {
            toSVGFESpecularLightingElement(*parent).lightElementAttributeChanged(this, attrName);
            return;
        }

        ASSERT_NOT_REACHED();
    }

    SVGElement::svgAttributeChanged(attrName);
}
void invalidateFilterPrimitiveParent(SVGElement* element)
{
    if (!element)
        return;

    ContainerNode* parent = element->parentNode();

    if (!parent)
        return;

    LayoutObject* layoutObject = parent->layoutObject();
    if (!layoutObject || !layoutObject->isSVGResourceFilterPrimitive())
        return;

    LayoutSVGResourceContainer::markForLayoutAndParentResourceInvalidation(layoutObject, false);
}
Node* StyledMarkupTraverser<Strategy>::traverse(Node* startNode, Node* pastEnd)
{
    HeapVector<Member<ContainerNode>> ancestorsToClose;
    Node* next;
    Node* lastClosed = nullptr;
    for (Node* n = startNode; n && n != pastEnd; n = next) {
        // If |n| is a selection boundary such as <input>, traverse the child
        // nodes in the DOM tree instead of the flat tree.
        if (handleSelectionBoundary<Strategy>(*n)) {
            lastClosed = StyledMarkupTraverser<EditingStrategy>(m_accumulator, m_lastClosed.get()).traverse(n, EditingStrategy::nextSkippingChildren(*n));
            next = EditingInFlatTreeStrategy::nextSkippingChildren(*n);
        } else {
            next = Strategy::next(*n);
            if (isEnclosingBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd) {
                // Don't write out empty block containers that aren't fully selected.
                continue;
            }

            if (!n->layoutObject() && !enclosingElementWithTag(firstPositionInOrBeforeNode(n), selectTag)) {
                next = Strategy::nextSkippingChildren(*n);
                // Don't skip over pastEnd.
                if (pastEnd && Strategy::isDescendantOf(*pastEnd, *n))
                    next = pastEnd;
            } else {
                // Add the node to the markup if we're not skipping the descendants
                appendStartMarkup(*n);

                // If node has no children, close the tag now.
                if (Strategy::hasChildren(*n)) {
                    ancestorsToClose.append(toContainerNode(n));
                    continue;
                }
                appendEndMarkup(*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 (Strategy::nextSibling(*n) && next != pastEnd)
            continue;

        // Close up the ancestors.
        while (!ancestorsToClose.isEmpty()) {
            ContainerNode* ancestor = ancestorsToClose.last();
            ASSERT(ancestor);
            if (next && next != pastEnd && Strategy::isDescendantOf(*next, *ancestor))
                break;
            // Not at the end of the range, close ancestors up to sibling of next node.
            appendEndMarkup(*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 ? Strategy::parent(*next) : nullptr;
        if (next == pastEnd || n == nextParent)
            continue;

        ASSERT(n);
        Node* lastAncestorClosedOrSelf = (lastClosed && Strategy::isDescendantOf(*n, *lastClosed)) ? lastClosed : n;
        for (ContainerNode* parent = Strategy::parent(*lastAncestorClosedOrSelf); parent && parent != nextParent; parent = Strategy::parent(*parent)) {
            // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered:
            if (!parent->layoutObject())
                continue;
            // or b) ancestors that we never encountered during a pre-order traversal starting at startNode:
            ASSERT(startNode);
            ASSERT(Strategy::isDescendantOf(*startNode, *parent));
            RawPtr<EditingStyle> style = createInlineStyleIfNeeded(*parent);
            wrapWithNode(*parent, style);
            lastClosed = parent;
        }
    }

    return lastClosed;
}