/*
 * This file is part of the WebKit project.
 *
 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
 *
 * 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"

#if ENABLE(SVG)
#include "SVGCharacterLayoutInfo.h"

#include "InlineFlowBox.h"
#include "InlineTextBox.h"
#include "SVGLengthList.h"
#include "SVGNumberList.h"
#include "SVGTextPositioningElement.h"
#include "RenderSVGTextPath.h"

#include <float.h>

namespace WebCore {

// Helper function
static float calculateBaselineShift(RenderObject* item)
{
    const Font& font = item->style()->font();
    const SVGRenderStyle* svgStyle = item->style()->svgStyle();

    float baselineShift = 0.0f;
    if (svgStyle->baselineShift() == BS_LENGTH) {
        CSSPrimitiveValue* primitive = static_cast<CSSPrimitiveValue*>(svgStyle->baselineShiftValue());
        baselineShift = primitive->getFloatValue();

        if (primitive->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
            baselineShift = baselineShift / 100.0f * font.pixelSize();
    } else {
        float baselineAscent = font.ascent() + font.descent();

        switch (svgStyle->baselineShift()) {
        case BS_BASELINE:
            break;
        case BS_SUB:
            baselineShift = -baselineAscent / 2.0f;
            break;
        case BS_SUPER:
            baselineShift = baselineAscent / 2.0f;
            break;
        default:
            ASSERT_NOT_REACHED();
        }
    }

    return baselineShift;
}

SVGCharacterLayoutInfo::SVGCharacterLayoutInfo(Vector<SVGChar>& chars)
    : curx(0.0f)
    , cury(0.0f)
    , angle(0.0f)
    , dx(0.0f)
    , dy(0.0f)
    , shiftx(0.0f)
    , shifty(0.0f)
    , pathExtraAdvance(0.0f)
    , pathTextLength(0.0f)
    , pathChunkLength(0.0f)
    , svgChars(chars)
    , nextDrawnSeperated(false)
    , xStackChanged(false)
    , yStackChanged(false)
    , dxStackChanged(false)
    , dyStackChanged(false)
    , angleStackChanged(false)
    , baselineShiftStackChanged(false)
    , pathLayout(false)
    , currentOffset(0.0f)
    , startOffset(0.0f)
    , layoutPathLength(0.0f)
{
}

bool SVGCharacterLayoutInfo::xValueAvailable() const
{
    return xStack.isEmpty() ? false : xStack.last().position() < xStack.last().size();
}

bool SVGCharacterLayoutInfo::yValueAvailable() const
{
    return yStack.isEmpty() ? false : yStack.last().position() < yStack.last().size();
}

bool SVGCharacterLayoutInfo::dxValueAvailable() const
{
    return dxStack.isEmpty() ? false : dxStack.last().position() < dxStack.last().size();
}

bool SVGCharacterLayoutInfo::dyValueAvailable() const
{
    return dyStack.isEmpty() ? false : dyStack.last().position() < dyStack.last().size();
}

bool SVGCharacterLayoutInfo::angleValueAvailable() const
{
    return angleStack.isEmpty() ? false : angleStack.last().position() < angleStack.last().size();
}

bool SVGCharacterLayoutInfo::baselineShiftValueAvailable() const
{
    return !baselineShiftStack.isEmpty();
}

float SVGCharacterLayoutInfo::xValueNext() const
{
    ASSERT(!xStack.isEmpty());
    return xStack.last().valueAtCurrentPosition();
}

float SVGCharacterLayoutInfo::yValueNext() const
{
    ASSERT(!yStack.isEmpty());
    return yStack.last().valueAtCurrentPosition();
}

float SVGCharacterLayoutInfo::dxValueNext() const
{
    ASSERT(!dxStack.isEmpty());
    return dxStack.last().valueAtCurrentPosition();
}

float SVGCharacterLayoutInfo::dyValueNext() const
{
    ASSERT(!dyStack.isEmpty());
    return dyStack.last().valueAtCurrentPosition();
}

float SVGCharacterLayoutInfo::angleValueNext() const
{
    ASSERT(!angleStack.isEmpty());
    return angleStack.last().valueAtCurrentPosition();
}

float SVGCharacterLayoutInfo::baselineShiftValueNext() const
{
    ASSERT(!baselineShiftStack.isEmpty());
    return baselineShiftStack.last();
}

void SVGCharacterLayoutInfo::processedSingleCharacter()
{
    xStackWalk();
    yStackWalk();
    dxStackWalk();
    dyStackWalk();
    angleStackWalk();
    baselineShiftStackWalk();
}

void SVGCharacterLayoutInfo::processedChunk(float savedShiftX, float savedShiftY)
{
    // baseline-shift doesn't span across ancestors, unlike dx/dy.
    curx += savedShiftX - shiftx;
    cury += savedShiftY - shifty;

    if (inPathLayout()) {
        shiftx = savedShiftX;
        shifty = savedShiftY;
    }

    // rotation also doesn't span
    angle = 0.0f;

    if (xStackChanged) {
        ASSERT(!xStack.isEmpty());
        xStack.removeLast();
        xStackChanged = false;
    }

    if (yStackChanged) {
        ASSERT(!yStack.isEmpty());
        yStack.removeLast();
        yStackChanged = false;
    }

    if (dxStackChanged) {
        ASSERT(!dxStack.isEmpty());
        dxStack.removeLast();
        dxStackChanged = false;
    }

    if (dyStackChanged) {
        ASSERT(!dyStack.isEmpty());
        dyStack.removeLast();
        dyStackChanged = false;
    }

    if (angleStackChanged) {
        ASSERT(!angleStack.isEmpty());
        angleStack.removeLast();
        angleStackChanged = false;
    }

    if (baselineShiftStackChanged) {
        ASSERT(!baselineShiftStack.isEmpty());
        baselineShiftStack.removeLast();
        baselineShiftStackChanged = false;
    }
}

bool SVGCharacterLayoutInfo::nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset)
{
    if (layoutPathLength <= 0.0f)
        return false;

    if (newOffset != FLT_MIN)
        currentOffset = startOffset + newOffset;

    // Respect translation along path (extraAdvance is orthogonal to the path)
    currentOffset += extraAdvance;

    float offset = currentOffset + glyphAdvance / 2.0f;
    currentOffset += glyphAdvance + pathExtraAdvance;

    if (offset < 0.0f || offset > layoutPathLength)
        return false;

    bool ok = false; 
    FloatPoint point = layoutPath.pointAtLength(offset, ok);
    ASSERT(ok);

    curx = point.x();
    cury = point.y();

    angle = layoutPath.normalAngleAtLength(offset, ok);
    ASSERT(ok);

    // fprintf(stderr, "t: %f, x: %f, y: %f, angle: %f, glyphAdvance: %f\n", currentOffset, x, y, angle, glyphAdvance);
    return true;
}

bool SVGCharacterLayoutInfo::inPathLayout() const
{
    return pathLayout;
}

void SVGCharacterLayoutInfo::setInPathLayout(bool value)
{
    pathLayout = value;

    pathExtraAdvance = 0.0f;
    pathTextLength = 0.0f;
    pathChunkLength = 0.0f;
}

void SVGCharacterLayoutInfo::addLayoutInformation(InlineFlowBox* flowBox, float textAnchorStartOffset)
{
    bool isInitialLayout = xStack.isEmpty() && yStack.isEmpty() &&
                           dxStack.isEmpty() && dyStack.isEmpty() &&
                           angleStack.isEmpty() && baselineShiftStack.isEmpty() &&
                           curx == 0.0f && cury == 0.0f;

    RenderSVGTextPath* textPath = static_cast<RenderSVGTextPath*>(flowBox->renderer());
    Path path = textPath->layoutPath();

    float baselineShift = calculateBaselineShift(textPath);

    layoutPath = path;
    layoutPathLength = path.length();

    if (layoutPathLength <= 0.0f)
        return;

    startOffset = textPath->startOffset();

    if (textPath->startOffset() >= 0.0f && textPath->startOffset() <= 1.0f)
        startOffset *= layoutPathLength;

    startOffset += textAnchorStartOffset;
    currentOffset = startOffset;

    // Only baseline-shift is handled through the normal layout system
    addStackContent(BaselineShiftStack, baselineShift);

    if (isInitialLayout) {
        xStackChanged = false;
        yStackChanged = false;
        dxStackChanged = false;
        dyStackChanged = false;
        angleStackChanged = false;
        baselineShiftStackChanged = false;
    }
}

void SVGCharacterLayoutInfo::addLayoutInformation(SVGTextPositioningElement* element)
{
    bool isInitialLayout = xStack.isEmpty() && yStack.isEmpty() &&
                           dxStack.isEmpty() && dyStack.isEmpty() &&
                           angleStack.isEmpty() && baselineShiftStack.isEmpty() &&
                           curx == 0.0f && cury == 0.0f;

    float baselineShift = calculateBaselineShift(element->renderer());

    addStackContent(XStack, element->x(), element);
    addStackContent(YStack, element->y(), element);
    addStackContent(DxStack, element->dx(), element);
    addStackContent(DyStack, element->dy(), element);
    addStackContent(AngleStack, element->rotate());
    addStackContent(BaselineShiftStack, baselineShift);

    if (isInitialLayout) {
        xStackChanged = false;
        yStackChanged = false;
        dxStackChanged = false;
        dyStackChanged = false;
        angleStackChanged = false;
        baselineShiftStackChanged = false;
    }
}

void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGNumberList* list)
{
    unsigned length = list->numberOfItems();
    if (!length)
        return;

    PositionedFloatVector newLayoutInfo;

    // TODO: Convert more efficiently!
    ExceptionCode ec = 0;
    for (unsigned i = 0; i < length; ++i) {
        float value = list->getItem(i, ec);
        ASSERT(ec == 0);

        newLayoutInfo.append(value);
    }

    addStackContent(type, newLayoutInfo);
}

void SVGCharacterLayoutInfo::addStackContent(StackType type, SVGLengthList* list, const SVGElement* context)
{
    unsigned length = list->numberOfItems();
    if (!length)
        return;

    PositionedFloatVector newLayoutInfo;

    ExceptionCode ec = 0;
    for (unsigned i = 0; i < length; ++i) {
        float value = list->getItem(i, ec).value(context);
        ASSERT(ec == 0);

        newLayoutInfo.append(value);
    }

    addStackContent(type, newLayoutInfo);
}

void SVGCharacterLayoutInfo::addStackContent(StackType type, const PositionedFloatVector& list)
{
    switch (type) {
    case XStack:
        xStackChanged = true;
        xStack.append(list);
        break;
    case YStack:
        yStackChanged = true;
        yStack.append(list);
        break;
    case DxStack:
        dxStackChanged = true;
        dxStack.append(list);
        break;
    case DyStack:
        dyStackChanged = true;
        dyStack.append(list);
        break;
    case AngleStack:
        angleStackChanged = true;
        angleStack.append(list);
        break; 
    default:
        ASSERT_NOT_REACHED();
    }
}

void SVGCharacterLayoutInfo::addStackContent(StackType type, float value)
{
    if (value == 0.0f)
        return;

    switch (type) {
    case BaselineShiftStack:
        baselineShiftStackChanged = true;
        baselineShiftStack.append(value);
        break;
    default:
        ASSERT_NOT_REACHED();
    }
}

void SVGCharacterLayoutInfo::xStackWalk()
{
    unsigned i = 1;

    while (!xStack.isEmpty()) {
        PositionedFloatVector& cur = xStack.last();
        if (i + cur.position() < cur.size()) {
            cur.advance(i);
            break;
        }

        i += cur.position();
        xStack.removeLast();
        xStackChanged = false;
    }
}

void SVGCharacterLayoutInfo::yStackWalk()
{
    unsigned i = 1;

    while (!yStack.isEmpty()) {
        PositionedFloatVector& cur = yStack.last();
        if (i + cur.position() < cur.size()) {
            cur.advance(i);
            break;
        }

        i += cur.position();
        yStack.removeLast();
        yStackChanged = false;
    }
}

void SVGCharacterLayoutInfo::dxStackWalk()
{
    unsigned i = 1;

    while (!dxStack.isEmpty()) {
        PositionedFloatVector& cur = dxStack.last();
        if (i + cur.position() < cur.size()) {
            cur.advance(i);
            break;
        }

        i += cur.position();
        dxStack.removeLast();
        dxStackChanged = false;
    }
}

void SVGCharacterLayoutInfo::dyStackWalk()
{
    unsigned i = 1;

    while (!dyStack.isEmpty()) {
        PositionedFloatVector& cur = dyStack.last();
        if (i + cur.position() < cur.size()) {
            cur.advance(i);
            break;
        }

        i += cur.position();
        dyStack.removeLast();
        dyStackChanged = false;
    }
}

void SVGCharacterLayoutInfo::angleStackWalk()
{
    unsigned i = 1;

    while (!angleStack.isEmpty()) {
        PositionedFloatVector& cur = angleStack.last();
        if (i + cur.position() < cur.size()) {
            cur.advance(i);
            break;
        }

        i += cur.position();
        angleStack.removeLast();
        angleStackChanged = false;
    }
}

void SVGCharacterLayoutInfo::baselineShiftStackWalk()
{
    if (!baselineShiftStack.isEmpty()) {
        baselineShiftStack.removeLast();
        baselineShiftStackChanged = false;
    }
}

bool SVGChar::isHidden() const
{
    return pathData && pathData->hidden;
}

TransformationMatrix SVGChar::characterTransform() const
{
    TransformationMatrix ctm;

    // Rotate character around angle, and possibly scale.
    ctm.translate(x, y);
    ctm.rotate(angle);

    if (pathData) {
        ctm.scaleNonUniform(pathData->xScale, pathData->yScale);
        ctm.translate(pathData->xShift, pathData->yShift);
        ctm.rotate(pathData->orientationAngle);
    }

    ctm.translate(orientationShiftX - x, orientationShiftY - y);
    return ctm;
}

} // namespace WebCore

#endif // ENABLE(SVG)
