/*
 * Copyright (C) 2011 Google Inc. All rights reserved.
 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
 *
 * 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.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "GestureTapHighlighter.h"

#include "Element.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "GraphicsTypes.h"
#include "Node.h"
#include "Page.h"
#include "RenderBoxModelObject.h"
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderObject.h"

namespace WebCore {

namespace {

inline LayoutPoint ownerFrameToMainFrameOffset(const RenderObject* o)
{
    ASSERT(o->node());
    Frame* containingFrame = o->frame();
    if (!containingFrame)
        return LayoutPoint();

    Frame* mainFrame = containingFrame->page()->mainFrame();

    LayoutPoint mainFramePoint = mainFrame->view()->windowToContents(containingFrame->view()->contentsToWindow(IntPoint()));
    return mainFramePoint;
}

AffineTransform localToAbsoluteTransform(const RenderObject* o)
{
    AffineTransform transform;
    LayoutPoint referencePoint;

    while (o) {
        RenderObject* nextContainer = o->container();
        if (!nextContainer)
            break;

        LayoutSize containerOffset = o->offsetFromContainer(nextContainer, referencePoint);
        TransformationMatrix t;
        o->getTransformFromContainer(nextContainer, containerOffset, t);

        transform = t.toAffineTransform() * transform;
        referencePoint.move(containerOffset);
        o = nextContainer;
    }

    return transform;
}

inline bool contains(const LayoutRect& rect, int x)
{
    return !rect.isEmpty() && x >= rect.x() && x <= rect.maxX();
}

inline bool strikes(const LayoutRect& a, const LayoutRect& b)
{
    return !a.isEmpty() && !b.isEmpty()
        && a.x() <= b.maxX() && b.x() <= a.maxX()
        && a.y() <= b.maxY() && b.y() <= a.maxY();
}

inline void shiftXEdgesToContainIfStrikes(LayoutRect& rect, LayoutRect& other, bool isFirst)
{
    if (rect.isEmpty())
        return;

    if (other.isEmpty() || !strikes(rect, other))
        return;

    LayoutUnit leftSide = std::min(rect.x(), other.x());
    LayoutUnit rightSide = std::max(rect.maxX(), other.maxX());

    rect.shiftXEdgeTo(leftSide);
    rect.shiftMaxXEdgeTo(rightSide);

    if (isFirst)
        other.shiftMaxXEdgeTo(rightSide);
    else
        other.shiftXEdgeTo(leftSide);
}

inline void addHighlightRect(Path& path, const LayoutRect& rect, const LayoutRect& prev, const LayoutRect& next)
{
    // The rounding check depends on the rects not intersecting eachother,
    // or being contained for that matter.
    ASSERT(!rect.intersects(prev));
    ASSERT(!rect.intersects(next));

    if (rect.isEmpty())
        return;

    const int rounding = 4;

    FloatRect copy(rect);
    copy.inflateX(rounding);
    copy.inflateY(rounding / 2);

    FloatSize rounded(rounding * 1.8, rounding * 1.8);
    FloatSize squared(0, 0);

    path.addBeziersForRoundedRect(copy,
            contains(prev, rect.x()) ? squared : rounded,
            contains(prev, rect.maxX()) ? squared : rounded,
            contains(next, rect.x()) ? squared : rounded,
            contains(next, rect.maxX()) ? squared : rounded);
}

Path absolutePathForRenderer(RenderObject* const o)
{
    ASSERT(o);

    Vector<IntRect> rects;
    LayoutPoint frameOffset = ownerFrameToMainFrameOffset(o);
    o->addFocusRingRects(rects, frameOffset);

    if (rects.isEmpty())
        return Path();

    // The basic idea is to allow up to three different boxes in order to highlight
    // text with line breaks more nicer than using a bounding box.

    // Merge all center boxes (all but the first and the last).
    LayoutRect mid;

    // Set the end value to integer. It ensures that no unsigned int overflow occurs
    // in the test expression, in case of empty rects vector.
    int end = rects.size() - 1;
    for (int i = 1; i < end; ++i)
        mid.uniteIfNonZero(rects.at(i));

    LayoutRect first;
    LayoutRect last;

    // Add the first box, but merge it with the center boxes if it intersects or if the center box is empty.
    if (rects.size() && !rects.first().isEmpty()) {
        // If the mid box is empty at this point, unite it with the first box. This allows the first box to be
        // united with the last box if they intersect in the following check for last. Not uniting them would
        // trigger in assert in addHighlighRect due to the first and the last box intersecting, but being passed
        // as two separate boxes.
        if (mid.isEmpty() || mid.intersects(rects.first()))
            mid.unite(rects.first());
        else {
            first = rects.first();
            shiftXEdgesToContainIfStrikes(mid, first, /* isFirst */ true);
        }
    }

    // Add the last box, but merge it with the center boxes if it intersects.
    if (rects.size() > 1 && !rects.last().isEmpty()) {
        // Adjust center boxes to boundary of last
        if (mid.intersects(rects.last()))
            mid.unite(rects.last());
        else {
            last = rects.last();
            shiftXEdgesToContainIfStrikes(mid, last, /* isFirst */ false);
        }
    }

    Vector<LayoutRect> drawableRects;
    if (!first.isEmpty())
        drawableRects.append(first);
    if (!mid.isEmpty())
        drawableRects.append(mid);
    if (!last.isEmpty())
        drawableRects.append(last);

    // Clip the overflow rects if needed, before the ring path is formed to
    // ensure rounded highlight rects. This clipping has the problem with nested
    // divs with transforms, which could be resolved by proper Path::intersecting.
    for (int i = drawableRects.size() - 1; i >= 0; --i) {
        LayoutRect& ringRect = drawableRects.at(i);
        LayoutPoint ringRectLocation = ringRect.location();

        ringRect.moveBy(-frameOffset);

        RenderLayer* layer = o->enclosingLayer();
        RenderObject* currentRenderer = o;

        // Check ancestor layers for overflow clip and intersect them.
        for (; layer; layer = layer->parent()) {
            RenderLayerModelObject* layerRenderer = layer->renderer();

            if (layerRenderer->hasOverflowClip() && layerRenderer != currentRenderer) {
                bool containerSkipped = false;
                // Skip ancestor layers that are not containers for the current renderer.
                currentRenderer->container(layerRenderer, &containerSkipped);
                if (containerSkipped)
                    continue;
                ringRect.move(currentRenderer->offsetFromAncestorContainer(layerRenderer));
                currentRenderer = layerRenderer;

                ASSERT(layerRenderer->isBox());
                ringRect.intersect(toRenderBox(layerRenderer)->borderBoxRect());

                if (ringRect.isEmpty())
                    break;
            }
        }

        if (ringRect.isEmpty()) {
            drawableRects.remove(i);
            continue;
        }
        // After clipping, reset the original position so that parents' transforms apply correctly.
        ringRect.setLocation(ringRectLocation);
    }

    Path path;
    for (size_t i = 0; i < drawableRects.size(); ++i) {
        LayoutRect prev = i ? drawableRects.at(i - 1) : LayoutRect();
        LayoutRect next = i < (drawableRects.size() - 1) ? drawableRects.at(i + 1) : LayoutRect();
        addHighlightRect(path, drawableRects.at(i), prev, next);
    }

    path.transform(localToAbsoluteTransform(o));
    return path;
}

} // anonymous namespace

namespace GestureTapHighlighter {

Path pathForNodeHighlight(const Node* node)
{
    RenderObject* renderer = node->renderer();

    if (!renderer || (!renderer->isBox() && !renderer->isRenderInline()))
        return Path();

    return absolutePathForRenderer(renderer);
}

} // namespace GestureTapHighlighter

} // namespace WebCore
