void SimplifyMarkupCommand::doApply()
{
    ContainerNode* rootNode = m_firstNode->parentNode();
    WillBeHeapVector<RefPtrWillBeMember<ContainerNode>> nodesToRemove;

    // Walk through the inserted nodes, to see if there are elements that could be removed
    // without affecting the style. The goal is to produce leaner markup even when starting
    // from a verbose fragment.
    // We look at inline elements as well as non top level divs that don't have attributes.
    for (Node* node = m_firstNode.get(); node && node != m_nodeAfterLast; node = NodeTraversal::next(*node)) {
        if (node->hasChildren() || (node->isTextNode() && node->nextSibling()))
            continue;

        ContainerNode* startingNode = node->parentNode();
        if (!startingNode)
            continue;
        RenderStyle* startingStyle = startingNode->renderStyle();
        if (!startingStyle)
            continue;
        ContainerNode* currentNode = startingNode;
        ContainerNode* topNodeWithStartingStyle = nullptr;
        while (currentNode != rootNode) {
            if (currentNode->parentNode() != rootNode && isRemovableBlock(currentNode))
                nodesToRemove.append(currentNode);

            currentNode = currentNode->parentNode();
            if (!currentNode)
                break;

            if (!currentNode->renderer() || !currentNode->renderer()->isRenderInline() || toRenderInline(currentNode->renderer())->alwaysCreateLineBoxes())
                continue;

            if (currentNode->firstChild() != currentNode->lastChild()) {
                topNodeWithStartingStyle = 0;
                break;
            }

            if (!currentNode->renderStyle()->visualInvalidationDiff(*startingStyle).hasDifference())
                topNodeWithStartingStyle = currentNode;

        }
        if (topNodeWithStartingStyle) {
            for (ContainerNode* node = startingNode; node != topNodeWithStartingStyle; node = node->parentNode())
                nodesToRemove.append(node);
        }
    }

    // we perform all the DOM mutations at once.
    for (size_t i = 0; i < nodesToRemove.size(); ++i) {
        // FIXME: We can do better by directly moving children from nodesToRemove[i].
        int numPrunedAncestors = pruneSubsequentAncestorsToRemove(nodesToRemove, i);
        if (numPrunedAncestors < 0)
            continue;
        removeNodePreservingChildren(nodesToRemove[i], AssumeContentIsAlwaysEditable);
        i += numPrunedAncestors;
    }
}
Exemple #2
0
bool SharedStyleFinder::canShareStyleWithElement(Element& candidate) const
{
    ASSERT(candidate.supportsStyleSharing());

    if (element() == candidate)
        return false;
    if (candidate.tagQName() != element().tagQName())
        return false;
    if (candidate.needsStyleRecalc())
        return false;
    RenderStyle* style = candidate.renderStyle();
    if (!style)
        return false;
    if (!style->isSharable())
        return false;
    ContainerNode* parent = NodeRenderingTraversal::parent(&candidate);
    if (!parent)
        return false;
    RenderStyle* parentStyle = parent->renderStyle();
    if (!parentStyle)
        return false;
    // The StyleAdjuster will change the display of the renderer depending
    // on it's parent's display.
    if (parentStyle->requiresOnlyBlockChildren() !=
        m_renderingParent->renderStyle()->requiresOnlyBlockChildren())
        return false;
    if (m_renderingParent->renderStyle()->inheritedNotEqual(parentStyle))
        return false;
    if (!sharingCandidateHasIdenticalStyleAffectingAttributes(candidate))
        return false;
    if (!sharingCandidateCanShareHostStyles(candidate))
        return false;
    if (!candidate.treeScope().hasSameStyles(element().treeScope()))
        return false;
    return true;
}
Exemple #3
0
void resolveTree(Element& current, Change change)
{
    ASSERT(change != Detach);

    if (current.hasCustomStyleResolveCallbacks()) {
        if (!current.willRecalcStyle(change))
            return;
    }

    ContainerNode* renderingParentNode = NodeRenderingTraversal::parent(&current);
    bool hasParentStyle = renderingParentNode && renderingParentNode->renderStyle();
    bool hasDirectAdjacentRules = current.childrenAffectedByDirectAdjacentRules();
    bool hasIndirectAdjacentRules = current.childrenAffectedByForwardPositionalRules();

#if PLATFORM(IOS)
    CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(current, current->renderStyle());
#endif

    if (change > NoChange || current.needsStyleRecalc())
        current.resetComputedStyle();

    if (hasParentStyle && (change >= Inherit || current.needsStyleRecalc()))
        change = resolveLocal(current, change);

    if (change != Detach) {
        StyleResolverParentPusher parentPusher(&current);

        RenderStyle* currentStyle = current.renderStyle();

        if (ShadowRoot* shadowRoot = current.shadowRoot()) {
            if (change >= Inherit || shadowRoot->childNeedsStyleRecalc() || shadowRoot->needsStyleRecalc()) {
                parentPusher.push();
                resolveShadowTree(shadowRoot, currentStyle, change);
            }
        }

        current.updateBeforePseudoElement(change);

        // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
        // For now we will just worry about the common case, since it's a lot trickier to get the second case right
        // without doing way too much re-resolution.
        bool forceCheckOfNextElementSibling = false;
        bool forceCheckOfAnyElementSibling = false;
        for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
            if (child->isTextNode()) {
                updateTextStyle(*toText(child), currentStyle, change);
                continue;
            }
            if (!child->isElementNode())
                continue;
            Element* childElement = toElement(child);
            bool childRulesChanged = childElement->needsStyleRecalc() && childElement->styleChangeType() == FullStyleChange;
            if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
                childElement->setNeedsStyleRecalc();
            if (change >= Inherit || childElement->childNeedsStyleRecalc() || childElement->needsStyleRecalc()) {
                parentPusher.push();
                resolveTree(*childElement, change);
            }
            forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
            forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
        }

        current.updateAfterPseudoElement(change);
    }

    current.clearNeedsStyleRecalc();
    current.clearChildNeedsStyleRecalc();
    
    if (current.hasCustomStyleResolveCallbacks())
        current.didRecalcStyle(change);
}