/*
* Copyright (C) 2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"
#include "LayoutIntegrationInlineContent.h"

#if ENABLE(LAYOUT_FORMATTING_CONTEXT)

#include "InlineIteratorBox.h"
#include "LayoutIntegrationLineLayout.h"
#include "RuntimeEnabledFeatures.h"
#include "TextPainter.h"

namespace WebCore {
namespace LayoutIntegration {

InlineContent::InlineContent(const LineLayout& lineLayout)
    : m_lineLayout(lineLayout)
{
}

bool InlineContent::hasContent() const
{
    ASSERT(boxes.isEmpty() || boxes[0].isRootInlineBox());
    return boxes.size() > 1;
};

IteratorRange<const InlineDisplay::Box*> InlineContent::boxesForRect(const LayoutRect& rect) const
{
    if (boxes.isEmpty())
        return { nullptr, nullptr };

    if (lines.first().inkOverflow().maxY() > rect.y() && lines.last().inkOverflow().y() < rect.maxY())
        return { &boxes.first(), &boxes.last() + 1 };

    // The optimization below relies on line paint bounds not exeeding those of the neighboring lines
    if (hasMultilinePaintOverlap)
        return { &boxes.first(), &boxes.last() + 1 };

    auto height = lines.last().lineBoxBottom() - lines.first().lineBoxTop();
    auto averageLineHeight = height / lines.size();

    auto approximateLine = [&](LayoutUnit y) {
        y = std::max(y, 0_lu);
        return std::min(static_cast<size_t>(y / averageLineHeight), lines.size() - 1);
    };

    auto startLine = approximateLine(rect.y());
    for (; startLine; --startLine) {
        if (lines[startLine - 1].inkOverflow().maxY() < rect.y())
            break;
    }

    auto endLine = approximateLine(rect.maxY());
    for (; endLine < lines.size() - 1; ++endLine) {
        if (lines[endLine + 1].inkOverflow().y() > rect.maxY())
            break;
    }

    auto firstBox = lines[startLine].firstBoxIndex();
    auto lastBox = lines[endLine].firstBoxIndex() + lines[endLine].boxCount() - 1;

    return { &boxes[firstBox], &boxes[lastBox] + 1 };
}

InlineContent::~InlineContent()
{
    if (RuntimeEnabledFeatures::sharedFeatures().layoutFormattingContextIntegrationEnabled()) {
        for (auto& box : boxes)
            TextPainter::removeGlyphDisplayList(box);
    }
}

const RenderObject& InlineContent::rendererForLayoutBox(const Layout::Box& layoutBox) const
{
    return lineLayout().rendererForLayoutBox(layoutBox);
}

const RenderBlockFlow& InlineContent::containingBlock() const
{
    return lineLayout().flow();
}

size_t InlineContent::indexForBox(const InlineDisplay::Box& box) const
{
    auto index = static_cast<size_t>(&box - boxes.begin());
    RELEASE_ASSERT(index < boxes.size());
    return index;
}

const InlineDisplay::Box* InlineContent::firstBoxForLayoutBox(const Layout::Box& layoutBox) const
{
    auto index = firstBoxIndexForLayoutBox(layoutBox);
    return index ? &boxes[*index] : nullptr;
}

std::optional<size_t> InlineContent::firstBoxIndexForLayoutBox(const Layout::Box& layoutBox) const
{
    constexpr auto cacheThreshold = 16;

    if (boxes.size() < cacheThreshold) {
        for (size_t i = 0; i < boxes.size(); ++i) {
            auto& box = boxes[i];
            if (&box.layoutBox() == &layoutBox)
                return i;
        }
        return { };
    }
    
    if (!m_firstBoxIndexCache) {
        m_firstBoxIndexCache = makeUnique<FirstBoxIndexCache>();
        for (size_t i = 0; i < boxes.size(); ++i) {
            auto& box = boxes[i];
            if (box.isRootInlineBox())
                continue;
            m_firstBoxIndexCache->add(box.layoutBox(), i);
        }
    }

    auto it = m_firstBoxIndexCache->find(layoutBox);
    if (it == m_firstBoxIndexCache->end())
        return { };

    return it->value;
}

const Vector<size_t>& InlineContent::nonRootInlineBoxIndexesForLayoutBox(const Layout::Box& layoutBox) const
{
    ASSERT(layoutBox.isContainerBox());

    if (!m_inlineBoxIndexCache) {
        m_inlineBoxIndexCache = makeUnique<InlineBoxIndexCache>();
        for (size_t i = 0; i < boxes.size(); ++i) {
            auto& box = boxes[i];
            if (!box.isNonRootInlineBox())
                continue;
            m_inlineBoxIndexCache->ensure(box.layoutBox(), [&] {
                return Vector<size_t> { };
            }).iterator->value.append(i);
        }
        for (auto entry : *m_inlineBoxIndexCache)
            entry.value.shrinkToFit();
    }

    auto it = m_inlineBoxIndexCache->find(layoutBox);
    if (it == m_inlineBoxIndexCache->end()) {
        static NeverDestroyed<Vector<size_t>> emptyVector;
        return emptyVector.get();
    }

    return it->value;
}

void InlineContent::clearAndDetach()
{
    for (auto& box : boxes)
        TextPainter::removeGlyphDisplayList(box);

    releaseCaches();
    boxes.clear();
    lines.clear();
    m_lineLayout = nullptr;
}

void InlineContent::releaseCaches()
{
    m_firstBoxIndexCache = { };
    m_inlineBoxIndexCache = { };
}

void InlineContent::shrinkToFit()
{
    boxes.shrinkToFit();
    lines.shrinkToFit();
}

}
}

#endif
