/*
 * Copyright (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
 * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

#include "config.h"
#include "RenderCounter.h"

#include "CounterNode.h"
#include "Document.h"
#include "Element.h"
#include "ElementInlines.h"
#include "ElementTraversal.h"
#include "HTMLNames.h"
#include "HTMLOListElement.h"
#include "PseudoElement.h"
#include "RenderListItem.h"
#include "RenderListMarker.h"
#include "RenderStyle.h"
#include "RenderView.h"
#include <wtf/IsoMallocInlines.h>
#include <wtf/StdLibExtras.h>

#if ENABLE(TREE_DEBUGGING)
#include <stdio.h>
#endif

namespace WebCore {

using namespace HTMLNames;

WTF_MAKE_ISO_ALLOCATED_IMPL(RenderCounter);

using CounterMap = HashMap<AtomString, Ref<CounterNode>>;
using CounterMaps = HashMap<const RenderElement*, std::unique_ptr<CounterMap>>;

static CounterNode* makeCounterNode(RenderElement&, const AtomString& identifier, bool alwaysCreateCounter);

static CounterMaps& counterMaps()
{
    static NeverDestroyed<CounterMaps> staticCounterMaps;
    return staticCounterMaps;
}

static Element* ancestorStyleContainmentObject(const Element& element)
{
    Element* ancestor = is<PseudoElement>(element) ? downcast<PseudoElement>(element).hostElement() : element.parentElement();
    while (ancestor) {
        if (auto* style = ancestor->existingComputedStyle()) {
            if (style->containsStyle())
                break;
        }
        // FIXME: this should use parentInComposedTree but for now matches the rest of RenderCounter.
        ancestor = ancestor->parentElement();
    }
    return ancestor;
}

// This function processes the renderer tree in the order of the DOM tree
// including pseudo elements as defined in CSS 2.1.
static RenderElement* previousInPreOrder(const RenderElement& renderer)
{
    ASSERT(renderer.element());
    Element* previous = ElementTraversal::previousIncludingPseudo(*renderer.element());
    Element* styleContainAncestor = ancestorStyleContainmentObject(*renderer.element());

    while (previous && !previous->renderer())
        previous = ElementTraversal::previousIncludingPseudo(*previous, styleContainAncestor);
    if (!previous)
        return nullptr;
    return previous->renderer();
}

static inline Element* parentOrPseudoHostElement(const RenderElement& renderer)
{
    if (renderer.isPseudoElement())
        return renderer.generatingElement();
    return renderer.element() ? renderer.element()->parentElement() : nullptr;
}

static Element* previousSiblingOrParentElement(const Element& element)
{
    if (auto* previous = ElementTraversal::pseudoAwarePreviousSibling(element)) {
        while (previous && !previous->renderer())
            previous = ElementTraversal::pseudoAwarePreviousSibling(*previous);

        if (previous)
            return previous;
    }

    if (is<PseudoElement>(element)) {
        auto* hostElement = downcast<PseudoElement>(element).hostElement();
        ASSERT(hostElement);
        if (hostElement->renderer())
            return hostElement;
        return previousSiblingOrParentElement(*hostElement);
    }
    
    auto* parent = element.parentElement();
    if (parent && !parent->renderer())
        parent = previousSiblingOrParentElement(*parent);
    if (parent && parent->renderer() && parent->renderer()->style().containsStyle())
        return nullptr;
    return parent;
}

// This function processes the renderer tree in the order of the DOM tree
// including pseudo elements as defined in CSS 2.1.
static RenderElement* previousSiblingOrParent(const RenderElement& renderer)
{
    ASSERT(renderer.element());

    auto* previous = previousSiblingOrParentElement(*renderer.element());
    return previous ? previous->renderer() : nullptr;
}

static inline bool areRenderersElementsSiblings(const RenderElement& first, const RenderElement& second)
{
    return parentOrPseudoHostElement(first) == parentOrPseudoHostElement(second);
}

// This function processes the renderer tree in the order of the DOM tree
// including pseudo elements as defined in CSS 2.1.
static RenderElement* nextInPreOrder(const RenderElement& renderer, const Element* stayWithin, bool skipDescendants = false)
{
    ASSERT(renderer.element());
    Element& self = *renderer.element();
    Element* next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(self, stayWithin) : ElementTraversal::nextIncludingPseudo(self, stayWithin);
    while (next && !next->renderer())
        next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(*next, stayWithin) : ElementTraversal::nextIncludingPseudo(*next, stayWithin);
    return next ? next->renderer() : nullptr;
}

static CounterDirectives listItemCounterDirectives(RenderElement& renderer)
{
    if (is<RenderListItem>(renderer)) {
        auto& item = downcast<RenderListItem>(renderer);
        if (auto explicitValue = item.explicitValue())
            return { *explicitValue, std::nullopt };
        return { std::nullopt, item.isInReversedOrderedList() ? -1 : 1 };
    }
    if (auto element = renderer.element()) {
        if (is<HTMLOListElement>(*element)) {
            auto& list = downcast<HTMLOListElement>(*element);
            return { list.start(), list.isReversed() ? 1 : -1 };
        }
        if (isHTMLListElement(*element))
            return { 0, std::nullopt };
    }
    return { };
}

struct CounterPlan {
    bool isReset;
    int value;
};

static std::optional<CounterPlan> planCounter(RenderElement& renderer, const AtomString& identifier)
{
    // We must have a generating node or else we cannot have a counter.
    Element* generatingElement = renderer.generatingElement();
    if (!generatingElement)
        return std::nullopt;

    auto& style = renderer.style();

    switch (style.styleType()) {
    case PseudoId::None:
        // Sometimes elements have more then one renderer. Only the first one gets the counter
        // LayoutTests/http/tests/css/counter-crash.html
        if (generatingElement->renderer() != &renderer)
            return std::nullopt;
        break;
    case PseudoId::Before:
    case PseudoId::After:
        break;
    default:
        return std::nullopt; // Counters are forbidden from all other pseudo elements.
    }

    CounterDirectives directives;

    if (auto map = style.counterDirectives())
        directives = map->get(identifier);

    if (identifier == "list-item") {
        auto itemDirectives = listItemCounterDirectives(renderer);
        if (!directives.resetValue)
            directives.resetValue = itemDirectives.resetValue;
        if (!directives.incrementValue)
            directives.incrementValue = itemDirectives.incrementValue;
    }

    if (directives.resetValue)
        return CounterPlan { true, saturatedSum<int>(*directives.resetValue, directives.incrementValue.value_or(0)) };
    if (directives.incrementValue)
        return CounterPlan { false, *directives.incrementValue };
    return std::nullopt;
}

// - Finds the insertion point for the counter described by counterOwner, isReset and 
// identifier in the CounterNode tree for identifier and sets parent and
// previousSibling accordingly.
// - The function returns true if the counter whose insertion point is searched is NOT
// the root of the tree.
// - The root of the tree is a counter reference that is not in the scope of any other
// counter with the same identifier.
// - All the counter references with the same identifier as this one that are in
// children or subsequent siblings of the renderer that owns the root of the tree
// form the rest of of the nodes of the tree.
// - The root of the tree is always a reset type reference.
// - A subtree rooted at any reset node in the tree is equivalent to all counter 
// references that are in the scope of the counter or nested counter defined by that
// reset node.
// - Non-reset CounterNodes cannot have descendants.

struct CounterInsertionPoint {
    RefPtr<CounterNode> parent;
    RefPtr<CounterNode> previousSibling;
};

static CounterInsertionPoint findPlaceForCounter(RenderElement& counterOwner, const AtomString& identifier, bool isReset)
{
    // We cannot stop searching for counters with the same identifier before we also
    // check this renderer, because it may affect the positioning in the tree of our counter.
    RenderElement* searchEndRenderer = previousSiblingOrParent(counterOwner);
    // We check renderers in preOrder from the renderer that our counter is attached to
    // towards the begining of the document for counters with the same identifier as the one
    // we are trying to find a place for. This is the next renderer to be checked.
    RenderElement* currentRenderer = previousInPreOrder(counterOwner);
    RefPtr<CounterNode> previousSibling;

    while (currentRenderer) {
        auto currentCounter = makeCounterNode(*currentRenderer, identifier, false);
        if (searchEndRenderer == currentRenderer) {
            // We may be at the end of our search.
            if (currentCounter) {
                // We have a suitable counter on the EndSearchRenderer.
                if (previousSibling) {
                    // But we already found another counter that we come after.
                    if (currentCounter->actsAsReset()) {
                        // We found a reset counter that is on a renderer that is a sibling of ours or a parent.
                        if (isReset && areRenderersElementsSiblings(*currentRenderer, counterOwner)) {
                            // We are also a reset counter and the previous reset was on a sibling renderer
                            // hence we are the next sibling of that counter if that reset is not a root or
                            // we are a root node if that reset is a root.
                            auto* parent = currentCounter->parent();
                            return { parent, parent ? currentCounter : nullptr };
                        }
                        // We are not a reset node or the previous reset must be on an ancestor of our owner renderer
                        // hence we must be a child of that reset counter.
                        // In some cases renders can be reparented (ex. nodes inside a table but not in a column or row).
                        // In these cases the identified previousSibling will be invalid as its parent is different from
                        // our identified parent.
                        if (previousSibling->parent() != currentCounter)
                            previousSibling = nullptr;
                        return { currentCounter, WTFMove(previousSibling) };
                    }
                    // CurrentCounter, the counter at the EndSearchRenderer, is not reset.
                    if (!isReset || !areRenderersElementsSiblings(*currentRenderer, counterOwner)) {
                        // If the node we are placing is not reset or we have found a counter that is attached
                        // to an ancestor of the placed counter's owner renderer we know we are a sibling of that node.
                        if (currentCounter->parent() != previousSibling->parent())
                            return { };
                        return { currentCounter->parent(), WTFMove(previousSibling) };
                    }
                } else { 
                    // We are at the potential end of the search, but we had no previous sibling candidate
                    // In this case we follow pretty much the same logic as above but no ASSERTs about 
                    // previousSibling, and when we are a sibling of the end counter we must set previousSibling
                    // to currentCounter.
                    if (currentCounter->actsAsReset()) {
                        if (isReset && areRenderersElementsSiblings(*currentRenderer, counterOwner))
                            return { currentCounter->parent(), currentCounter };
                        return { currentCounter, WTFMove(previousSibling) };
                    }
                    if (!isReset || !areRenderersElementsSiblings(*currentRenderer, counterOwner))
                        return { currentCounter->parent(), currentCounter };
                    previousSibling = currentCounter;
                }
            }
            // We come here if the previous sibling or parent of our owner renderer had no
            // good counter, or we are a reset node and the counter on the previous sibling
            // of our owner renderer was not a reset counter.
            // Set a new goal for the end of the search.
            searchEndRenderer = previousSiblingOrParent(*currentRenderer);
        } else {
            // We are searching descendants of a previous sibling of the renderer that the
            // counter being placed is attached to.
            if (currentCounter) {
                // We found a suitable counter.
                if (previousSibling) {
                    // Since we had a suitable previous counter before, we should only consider this one as our 
                    // previousSibling if it is a reset counter and hence the current previousSibling is its child.
                    if (currentCounter->actsAsReset()) {
                        previousSibling = currentCounter;
                        // We are no longer interested in previous siblings of the currentRenderer or their children
                        // as counters they may have attached cannot be the previous sibling of the counter we are placing.
                        auto* parent = parentOrPseudoHostElement(*currentRenderer);
                        currentRenderer = parent ? parent->renderer() : nullptr;
                        continue;
                    }
                } else
                    previousSibling = currentCounter;
                currentRenderer = previousSiblingOrParent(*currentRenderer);
                continue;
            }
        }
        // This function is designed so that the same test is not done twice in an iteration, except for this one
        // which may be done twice in some cases. Rearranging the decision points though, to accommodate this 
        // performance improvement would create more code duplication than is worthwhile in my oppinion and may further
        // impede the readability of this already complex algorithm.
        if (previousSibling)
            currentRenderer = previousSiblingOrParent(*currentRenderer);
        else
            currentRenderer = previousInPreOrder(*currentRenderer);
    }
    return { };
}

static CounterNode* makeCounterNode(RenderElement& renderer, const AtomString& identifier, bool alwaysCreateCounter)
{
    if (renderer.hasCounterNodeMap()) {
        ASSERT(counterMaps().contains(&renderer));
        if (auto* node = counterMaps().find(&renderer)->value->get(identifier))
            return node;
    }

    auto plan = planCounter(renderer, identifier);
    if (!plan && !alwaysCreateCounter)
        return nullptr;

    auto& maps = counterMaps();

    auto newNode = CounterNode::create(renderer, plan && plan->isReset, plan ? plan->value : 0);

    auto place = findPlaceForCounter(renderer, identifier, plan && plan->isReset);
    if (place.parent)
        place.parent->insertAfter(newNode, place.previousSibling.get(), identifier);

    maps.add(&renderer, makeUnique<CounterMap>()).iterator->value->add(identifier, newNode.copyRef());
    renderer.setHasCounterNodeMap(true);

    if (newNode->parent() || shouldApplyStyleContainment(renderer))
        return newNode.ptr();

    // Check if some nodes that were previously root nodes should become children of this node now.
    auto* currentRenderer = &renderer;
    auto* stayWithin = parentOrPseudoHostElement(renderer);
    bool skipDescendants = false;
    while ((currentRenderer = nextInPreOrder(*currentRenderer, stayWithin, skipDescendants))) {
        skipDescendants = shouldApplyStyleContainment(*currentRenderer);
        if (!currentRenderer->hasCounterNodeMap())
            continue;
        auto* currentCounter = maps.find(currentRenderer)->value->get(identifier);
        if (!currentCounter)
            continue;
        skipDescendants = true;
        if (currentCounter->parent())
            continue;
        if (stayWithin == parentOrPseudoHostElement(*currentRenderer) && currentCounter->hasResetType())
            break;
        newNode->insertAfter(*currentCounter, newNode->lastChild(), identifier);
    }

    return newNode.ptr();
}

RenderCounter::RenderCounter(Document& document, const CounterContent& counter)
    : RenderText(document, emptyString())
    , m_counter(counter)
{
    view().addRenderCounter();
}

RenderCounter::~RenderCounter()
{
    // Do not add any code here. Add it to willBeDestroyed() instead.
}

void RenderCounter::willBeDestroyed()
{
    view().removeRenderCounter();

    if (m_counterNode) {
        m_counterNode->removeRenderer(*this);
        ASSERT(!m_counterNode);
    }
    
    RenderText::willBeDestroyed();
}

const char* RenderCounter::renderName() const
{
    return "RenderCounter";
}

bool RenderCounter::isCounter() const
{
    return true;
}

String RenderCounter::originalText() const
{
    if (!m_counterNode) {
        RenderElement* beforeAfterContainer = parent();
        while (true) {
            if (!beforeAfterContainer)
                return String();
            if (!beforeAfterContainer->isAnonymous() && !beforeAfterContainer->isPseudoElement())
                return String(); // RenderCounters are restricted to before and after pseudo elements
            PseudoId containerStyle = beforeAfterContainer->style().styleType();
            if ((containerStyle == PseudoId::Before) || (containerStyle == PseudoId::After))
                break;
            beforeAfterContainer = beforeAfterContainer->parent();
        }
        makeCounterNode(*beforeAfterContainer, m_counter.identifier(), true)->addRenderer(const_cast<RenderCounter&>(*this));
        ASSERT(m_counterNode);
    }
    CounterNode* child = m_counterNode;
    int value = child->actsAsReset() ? child->value() : child->countInParent();

    String text = listMarkerText(m_counter.listStyle(), value);

    if (!m_counter.separator().isNull()) {
        if (!child->actsAsReset())
            child = child->parent();
        while (CounterNode* parent = child->parent()) {
            text = listMarkerText(m_counter.listStyle(), child->countInParent())
                + m_counter.separator() + text;
            child = parent;
        }
    }

    return text;
}

void RenderCounter::updateCounter()
{
    computePreferredLogicalWidths(0);
}

void RenderCounter::computePreferredLogicalWidths(float lead)
{
    // FIXME: We shouldn't be modifying the tree in computePreferredLogicalWidths.
    // Instead, we should properly hook the appropriate changes in the DOM and modify
    // the render tree then. When that's done, we also won't need to override
    // computePreferredLogicalWidths at all.
    // https://bugs.webkit.org/show_bug.cgi?id=104829
    SetLayoutNeededForbiddenScope layoutForbiddenScope(*this, false);

    setRenderedText(originalText());

    RenderText::computePreferredLogicalWidths(lead);
}

static void destroyCounterNodeWithoutMapRemoval(const AtomString& identifier, CounterNode& node)
{
    RefPtr<CounterNode> previous;
    for (RefPtr<CounterNode> child = node.lastDescendant(); child && child != &node; child = WTFMove(previous)) {
        previous = child->previousInPreOrder();
        child->parent()->removeChild(*child);
        ASSERT(counterMaps().find(&child->owner())->value->get(identifier) == child);
        counterMaps().find(&child->owner())->value->remove(identifier);
    }
    if (auto* parent = node.parent())
        parent->removeChild(node);
}

void RenderCounter::destroyCounterNodes(RenderElement& owner)
{
    ASSERT(owner.hasCounterNodeMap());
    auto& maps = counterMaps();
    ASSERT(maps.contains(&owner));
    auto counterMap = maps.take(&owner);
    for (auto& counterMapEntry : *counterMap)
        destroyCounterNodeWithoutMapRemoval(counterMapEntry.key, counterMapEntry.value);
    owner.setHasCounterNodeMap(false);
}

void RenderCounter::destroyCounterNode(RenderElement& owner, const AtomString& identifier)
{
    auto map = counterMaps().find(&owner);
    if (map == counterMaps().end())
        return;
    auto node = map->value->take(identifier);
    if (!node)
        return;
    destroyCounterNodeWithoutMapRemoval(identifier, *node);
    // We do not delete the map here even if it is now empty because we expect to
    // reuse it. In order for a renderer to lose all its counters permanently,
    // a style change for the renderer involving removal of all counter
    // directives must occur, in which case, RenderCounter::destroyCounterNodes()
    // will be called.
}

void RenderCounter::rendererRemovedFromTree(RenderElement& renderer)
{
    if (!renderer.view().hasRenderCounters())
        return;
    RenderObject* currentRenderer = renderer.lastLeafChild();
    if (!currentRenderer)
        currentRenderer = &renderer;
    while (true) {
        if (is<RenderElement>(*currentRenderer)) {
            auto& counterNodeRenderer = downcast<RenderElement>(*currentRenderer);
            if (counterNodeRenderer.hasCounterNodeMap())
                destroyCounterNodes(counterNodeRenderer);
        }
        if (currentRenderer == &renderer)
            break;
        currentRenderer = currentRenderer->previousInPreOrder();
    }
}

static void updateCounters(RenderElement& renderer)
{
    auto* directiveMap = renderer.style().counterDirectives();
    if (!directiveMap)
        return;
    if (!renderer.hasCounterNodeMap()) {
        for (auto& key : directiveMap->keys())
            makeCounterNode(renderer, key, false);
        return;
    }
    ASSERT(counterMaps().contains(&renderer));
    auto* counterMap = counterMaps().find(&renderer)->value.get();
    for (auto& key : directiveMap->keys()) {
        RefPtr<CounterNode> node = counterMap->get(key);
        if (!node) {
            makeCounterNode(renderer, key, false);
            continue;
        }
        auto place = findPlaceForCounter(renderer, key, node->hasResetType());
        if (node != counterMap->get(key))
            continue;
        CounterNode* parent = node->parent();
        if (place.parent == parent && place.previousSibling == node->previousSibling())
            continue;
        if (parent)
            parent->removeChild(*node);
        if (place.parent)
            place.parent->insertAfter(*node, place.previousSibling.get(), key);
    }
}

void RenderCounter::rendererSubtreeAttached(RenderElement& renderer)
{
    if (!renderer.view().hasRenderCounters())
        return;
    Element* element = renderer.element();
    if (element && !element->isPseudoElement())
        element = element->parentElement();
    else
        element = renderer.generatingElement();
    if (element && !element->renderer())
        return; // No need to update if the parent is not attached yet
    bool crossedStyleContainmentBoundary = false;
    for (RenderObject* descendant = &renderer; descendant; descendant = descendant->nextInPreOrder(&renderer)) {
        crossedStyleContainmentBoundary = crossedStyleContainmentBoundary || shouldApplyStyleContainment(*descendant);
        if (crossedStyleContainmentBoundary && is<RenderElement>(*descendant))
            updateCounters(downcast<RenderElement>(*descendant));
    }
}

void RenderCounter::rendererStyleChangedSlowCase(RenderElement& renderer, const RenderStyle* oldStyle, const RenderStyle& newStyle)
{
    Element* element = renderer.generatingElement();
    if (!element || !element->renderer())
        return; // cannot have generated content or if it can have, it will be handled during attaching

    const CounterDirectiveMap* oldCounterDirectives;
    if (oldStyle && (oldCounterDirectives = oldStyle->counterDirectives())) {
        if (auto* newCounterDirectives = newStyle.counterDirectives()) {
            for (auto& keyValue : *newCounterDirectives) {
                auto existingEntry = oldCounterDirectives->find(keyValue.key);
                if (existingEntry != oldCounterDirectives->end()) {
                    if (existingEntry->value == keyValue.value)
                        continue;
                    RenderCounter::destroyCounterNode(renderer, keyValue.key);
                }
                // We must create this node here, because the changed node may be a node with no display such as
                // as those created by the increment or reset directives and the re-layout that will happen will
                // not catch the change if the node had no children.
                makeCounterNode(renderer, keyValue.key, false);
            }
            // Destroying old counters that do not exist in the new counterDirective map.
            for (auto& key : oldCounterDirectives->keys()) {
                if (!newCounterDirectives->contains(key))
                    RenderCounter::destroyCounterNode(renderer, key);
            }
        } else {
            if (renderer.hasCounterNodeMap())
                RenderCounter::destroyCounterNodes(renderer);
        }
    } else {
        if (auto* newCounterDirectives = newStyle.counterDirectives()) {
            for (auto& key : newCounterDirectives->keys()) {
                // We must create this node here, because the added node may be a node with no display such as
                // as those created by the increment or reset directives and the re-layout that will happen will
                // not catch the change if the node had no children.
                makeCounterNode(renderer, key, false);
            }
        }
    }
}

} // namespace WebCore

#if ENABLE(TREE_DEBUGGING)

void showCounterRendererTree(const WebCore::RenderObject* renderer, const char* counterName)
{
    if (!renderer)
        return;
    auto* root = renderer;
    while (root->parent())
        root = root->parent();

    AtomString identifier(counterName);
    for (auto* current = root; current; current = current->nextInPreOrder()) {
        if (!is<WebCore::RenderElement>(*current))
            continue;
        fprintf(stderr, "%c", (current == renderer) ? '*' : ' ');
        for (auto* ancestor = current; ancestor && ancestor != root; ancestor = ancestor->parent())
            fprintf(stderr, "    ");
        fprintf(stderr, "%p N:%p P:%p PS:%p NS:%p C:%p\n",
            current, current->node(), current->parent(), current->previousSibling(),
            current->nextSibling(), downcast<WebCore::RenderElement>(*current).hasCounterNodeMap() ?
            counterName ? WebCore::counterMaps().find(downcast<WebCore::RenderElement>(current))->value->get(identifier) : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0);
    }
    fflush(stderr);
}

#endif // NDEBUG
