/*
 * Copyright (C) Research In Motion Limited 2010-2012. 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 "core/layout/svg/SVGTextQuery.h"

#include "core/layout/LayoutBlockFlow.h"
#include "core/layout/LayoutInline.h"
#include "core/layout/api/LineLayoutSVGInlineText.h"
#include "core/layout/line/InlineFlowBox.h"
#include "core/layout/svg/LayoutSVGInlineText.h"
#include "core/layout/svg/SVGTextFragment.h"
#include "core/layout/svg/SVGTextMetrics.h"
#include "core/layout/svg/line/SVGInlineTextBox.h"
#include "wtf/MathExtras.h"
#include "wtf/Vector.h"
#include <algorithm>

namespace blink {

// Base structure for callback user data
struct QueryData {
  QueryData()
      : isVerticalText(false),
        currentOffset(0),
        textLineLayout(nullptr),
        textBox(nullptr) {}

  bool isVerticalText;
  unsigned currentOffset;
  LineLayoutSVGInlineText textLineLayout;
  const SVGInlineTextBox* textBox;
};

static inline InlineFlowBox* flowBoxForLayoutObject(
    LayoutObject* layoutObject) {
  if (!layoutObject)
    return nullptr;

  if (layoutObject->isLayoutBlock()) {
    // If we're given a block element, it has to be a LayoutSVGText.
    ASSERT(layoutObject->isSVGText());
    LayoutBlockFlow* layoutBlockFlow = toLayoutBlockFlow(layoutObject);

    // LayoutSVGText only ever contains a single line box.
    InlineFlowBox* flowBox = layoutBlockFlow->firstLineBox();
    ASSERT(flowBox == layoutBlockFlow->lastLineBox());
    return flowBox;
  }

  if (layoutObject->isLayoutInline()) {
    // We're given a LayoutSVGInline or objects that derive from it
    // (LayoutSVGTSpan / LayoutSVGTextPath)
    LayoutInline* layoutInline = toLayoutInline(layoutObject);

    // LayoutSVGInline only ever contains a single line box.
    InlineFlowBox* flowBox = layoutInline->firstLineBox();
    ASSERT(flowBox == layoutInline->lastLineBox());
    return flowBox;
  }

  ASSERT_NOT_REACHED();
  return nullptr;
}

static void collectTextBoxesInFlowBox(InlineFlowBox* flowBox,
                                      Vector<SVGInlineTextBox*>& textBoxes) {
  if (!flowBox)
    return;

  for (InlineBox* child = flowBox->firstChild(); child;
       child = child->nextOnLine()) {
    if (child->isInlineFlowBox()) {
      // Skip generated content.
      if (!child->getLineLayoutItem().node())
        continue;

      collectTextBoxesInFlowBox(toInlineFlowBox(child), textBoxes);
      continue;
    }

    if (child->isSVGInlineTextBox())
      textBoxes.append(toSVGInlineTextBox(child));
  }
}

typedef bool ProcessTextFragmentCallback(QueryData*, const SVGTextFragment&);

static bool queryTextBox(QueryData* queryData,
                         const SVGInlineTextBox* textBox,
                         ProcessTextFragmentCallback fragmentCallback) {
  queryData->textBox = textBox;
  queryData->textLineLayout =
      LineLayoutSVGInlineText(textBox->getLineLayoutItem());

  queryData->isVerticalText =
      !queryData->textLineLayout.style()->isHorizontalWritingMode();

  // Loop over all text fragments in this text box, firing a callback for each.
  for (const SVGTextFragment& fragment : textBox->textFragments()) {
    if (fragmentCallback(queryData, fragment))
      return true;
  }
  return false;
}

// Execute a query in "spatial" order starting at |queryRoot|. This means
// walking the lines boxes in the order they would get painted.
static void spatialQuery(LayoutObject* queryRoot,
                         QueryData* queryData,
                         ProcessTextFragmentCallback fragmentCallback) {
  Vector<SVGInlineTextBox*> textBoxes;
  collectTextBoxesInFlowBox(flowBoxForLayoutObject(queryRoot), textBoxes);

  // Loop over all text boxes
  for (const SVGInlineTextBox* textBox : textBoxes) {
    if (queryTextBox(queryData, textBox, fragmentCallback))
      return;
  }
}

static void collectTextBoxesInLogicalOrder(
    LineLayoutSVGInlineText textLineLayout,
    Vector<SVGInlineTextBox*>& textBoxes) {
  textBoxes.shrink(0);
  for (InlineTextBox* textBox = textLineLayout.firstTextBox(); textBox;
       textBox = textBox->nextTextBox())
    textBoxes.append(toSVGInlineTextBox(textBox));
  std::sort(textBoxes.begin(), textBoxes.end(), InlineTextBox::compareByStart);
}

// Execute a query in "logical" order starting at |queryRoot|. This means
// walking the lines boxes for each layout object in layout tree (pre)order.
static void logicalQuery(LayoutObject* queryRoot,
                         QueryData* queryData,
                         ProcessTextFragmentCallback fragmentCallback) {
  if (!queryRoot)
    return;

  // Walk the layout tree in pre-order, starting at the specified root, and
  // run the query for each text node.
  Vector<SVGInlineTextBox*> textBoxes;
  for (LayoutObject* layoutObject = queryRoot->slowFirstChild(); layoutObject;
       layoutObject = layoutObject->nextInPreOrder(queryRoot)) {
    if (!layoutObject->isSVGInlineText())
      continue;

    LineLayoutSVGInlineText textLineLayout =
        LineLayoutSVGInlineText(toLayoutSVGInlineText(layoutObject));
    ASSERT(textLineLayout.style());

    // TODO(fs): Allow filtering the search earlier, since we should be
    // able to trivially reject (prune) at least some of the queries.
    collectTextBoxesInLogicalOrder(textLineLayout, textBoxes);

    for (const SVGInlineTextBox* textBox : textBoxes) {
      if (queryTextBox(queryData, textBox, fragmentCallback))
        return;
      queryData->currentOffset += textBox->len();
    }
  }
}

static bool mapStartEndPositionsIntoFragmentCoordinates(
    const QueryData* queryData,
    const SVGTextFragment& fragment,
    int& startPosition,
    int& endPosition) {
  unsigned boxStart = queryData->currentOffset;

  // Make <startPosition, endPosition> offsets relative to the current text box.
  startPosition -= boxStart;
  endPosition -= boxStart;

  // Reuse the same logic used for text selection & painting, to map our
  // query start/length into start/endPositions of the current text fragment.
  return queryData->textBox->mapStartEndPositionsIntoFragmentCoordinates(
      fragment, startPosition, endPosition);
}

// numberOfCharacters() implementation
static bool numberOfCharactersCallback(QueryData*, const SVGTextFragment&) {
  // no-op
  return false;
}

unsigned SVGTextQuery::numberOfCharacters() const {
  QueryData data;
  logicalQuery(m_queryRootLayoutObject, &data, numberOfCharactersCallback);
  return data.currentOffset;
}

// textLength() implementation
struct TextLengthData : QueryData {
  TextLengthData() : textLength(0) {}

  float textLength;
};

static bool textLengthCallback(QueryData* queryData,
                               const SVGTextFragment& fragment) {
  TextLengthData* data = static_cast<TextLengthData*>(queryData);
  data->textLength +=
      queryData->isVerticalText ? fragment.height : fragment.width;
  return false;
}

float SVGTextQuery::textLength() const {
  TextLengthData data;
  logicalQuery(m_queryRootLayoutObject, &data, textLengthCallback);
  return data.textLength;
}

using MetricsList = Vector<SVGTextMetrics>;

MetricsList::const_iterator findMetricsForCharacter(
    const MetricsList& metricsList,
    const SVGTextFragment& fragment,
    unsigned startInFragment) {
  // Find the text metrics cell that starts at or contains the character at
  // |startInFragment|.
  MetricsList::const_iterator metrics =
      metricsList.begin() + fragment.metricsListOffset;
  unsigned fragmentOffset = 0;
  while (fragmentOffset < fragment.length) {
    fragmentOffset += metrics->length();
    if (startInFragment < fragmentOffset)
      break;
    ++metrics;
  }
  ASSERT(metrics <= metricsList.end());
  return metrics;
}

static float calculateGlyphRange(const QueryData* queryData,
                                 const SVGTextFragment& fragment,
                                 unsigned start,
                                 unsigned end) {
  const MetricsList& metricsList = queryData->textLineLayout.metricsList();
  auto metrics = findMetricsForCharacter(metricsList, fragment, start);
  auto endMetrics = findMetricsForCharacter(metricsList, fragment, end);
  float glyphRange = 0;
  for (; metrics != endMetrics; ++metrics)
    glyphRange +=
        queryData->isVerticalText ? metrics->height() : metrics->width();
  return glyphRange;
}

// subStringLength() implementation
struct SubStringLengthData : QueryData {
  SubStringLengthData(unsigned queryStartPosition, unsigned queryLength)
      : startPosition(queryStartPosition),
        length(queryLength),
        subStringLength(0) {}

  unsigned startPosition;
  unsigned length;

  float subStringLength;
};

static bool subStringLengthCallback(QueryData* queryData,
                                    const SVGTextFragment& fragment) {
  SubStringLengthData* data = static_cast<SubStringLengthData*>(queryData);

  int startPosition = data->startPosition;
  int endPosition = startPosition + data->length;
  if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment,
                                                   startPosition, endPosition))
    return false;

  data->subStringLength +=
      calculateGlyphRange(queryData, fragment, startPosition, endPosition);
  return false;
}

float SVGTextQuery::subStringLength(unsigned startPosition,
                                    unsigned length) const {
  SubStringLengthData data(startPosition, length);
  logicalQuery(m_queryRootLayoutObject, &data, subStringLengthCallback);
  return data.subStringLength;
}

// startPositionOfCharacter() implementation
struct StartPositionOfCharacterData : QueryData {
  StartPositionOfCharacterData(unsigned queryPosition)
      : position(queryPosition) {}

  unsigned position;
  FloatPoint startPosition;
};

static FloatPoint logicalGlyphPositionToPhysical(
    const QueryData* queryData,
    const SVGTextFragment& fragment,
    float logicalGlyphOffset) {
  float physicalGlyphOffset = logicalGlyphOffset;
  if (!queryData->textBox->isLeftToRightDirection()) {
    float fragmentExtent =
        queryData->isVerticalText ? fragment.height : fragment.width;
    physicalGlyphOffset = fragmentExtent - logicalGlyphOffset;
  }

  FloatPoint glyphPosition(fragment.x, fragment.y);
  if (queryData->isVerticalText)
    glyphPosition.move(0, physicalGlyphOffset);
  else
    glyphPosition.move(physicalGlyphOffset, 0);

  return glyphPosition;
}

static FloatPoint calculateGlyphPosition(const QueryData* queryData,
                                         const SVGTextFragment& fragment,
                                         unsigned offsetInFragment) {
  float glyphOffsetInDirection =
      calculateGlyphRange(queryData, fragment, 0, offsetInFragment);
  FloatPoint glyphPosition = logicalGlyphPositionToPhysical(
      queryData, fragment, glyphOffsetInDirection);
  if (fragment.isTransformed()) {
    AffineTransform fragmentTransform = fragment.buildFragmentTransform(
        SVGTextFragment::TransformIgnoringTextLength);
    glyphPosition = fragmentTransform.mapPoint(glyphPosition);
  }
  return glyphPosition;
}

static bool startPositionOfCharacterCallback(QueryData* queryData,
                                             const SVGTextFragment& fragment) {
  StartPositionOfCharacterData* data =
      static_cast<StartPositionOfCharacterData*>(queryData);

  int startPosition = data->position;
  int endPosition = startPosition + 1;
  if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment,
                                                   startPosition, endPosition))
    return false;

  data->startPosition =
      calculateGlyphPosition(queryData, fragment, startPosition);
  return true;
}

FloatPoint SVGTextQuery::startPositionOfCharacter(unsigned position) const {
  StartPositionOfCharacterData data(position);
  logicalQuery(m_queryRootLayoutObject, &data,
               startPositionOfCharacterCallback);
  return data.startPosition;
}

// endPositionOfCharacter() implementation
struct EndPositionOfCharacterData : QueryData {
  EndPositionOfCharacterData(unsigned queryPosition)
      : position(queryPosition) {}

  unsigned position;
  FloatPoint endPosition;
};

static bool endPositionOfCharacterCallback(QueryData* queryData,
                                           const SVGTextFragment& fragment) {
  EndPositionOfCharacterData* data =
      static_cast<EndPositionOfCharacterData*>(queryData);

  int startPosition = data->position;
  int endPosition = startPosition + 1;
  if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment,
                                                   startPosition, endPosition))
    return false;

  data->endPosition = calculateGlyphPosition(queryData, fragment, endPosition);
  return true;
}

FloatPoint SVGTextQuery::endPositionOfCharacter(unsigned position) const {
  EndPositionOfCharacterData data(position);
  logicalQuery(m_queryRootLayoutObject, &data, endPositionOfCharacterCallback);
  return data.endPosition;
}

// rotationOfCharacter() implementation
struct RotationOfCharacterData : QueryData {
  RotationOfCharacterData(unsigned queryPosition)
      : position(queryPosition), rotation(0) {}

  unsigned position;
  float rotation;
};

static bool rotationOfCharacterCallback(QueryData* queryData,
                                        const SVGTextFragment& fragment) {
  RotationOfCharacterData* data =
      static_cast<RotationOfCharacterData*>(queryData);

  int startPosition = data->position;
  int endPosition = startPosition + 1;
  if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment,
                                                   startPosition, endPosition))
    return false;

  if (!fragment.isTransformed()) {
    data->rotation = 0;
  } else {
    AffineTransform fragmentTransform = fragment.buildFragmentTransform(
        SVGTextFragment::TransformIgnoringTextLength);
    fragmentTransform.scale(1 / fragmentTransform.xScale(),
                            1 / fragmentTransform.yScale());
    data->rotation = clampTo<float>(
        rad2deg(atan2(fragmentTransform.b(), fragmentTransform.a())));
  }
  return true;
}

float SVGTextQuery::rotationOfCharacter(unsigned position) const {
  RotationOfCharacterData data(position);
  logicalQuery(m_queryRootLayoutObject, &data, rotationOfCharacterCallback);
  return data.rotation;
}

// extentOfCharacter() implementation
struct ExtentOfCharacterData : QueryData {
  ExtentOfCharacterData(unsigned queryPosition) : position(queryPosition) {}

  unsigned position;
  FloatRect extent;
};

static FloatRect physicalGlyphExtents(const QueryData* queryData,
                                      const SVGTextMetrics& metrics,
                                      const FloatPoint& glyphPosition) {
  // TODO(fs): Negative glyph extents seems kind of weird to have, but
  // presently it can occur in some cases (like Arabic.)
  FloatRect glyphExtents(glyphPosition,
                         FloatSize(std::max<float>(metrics.width(), 0),
                                   std::max<float>(metrics.height(), 0)));

  // If RTL, adjust the starting point to align with the LHS of the glyph
  // bounding box.
  if (!queryData->textBox->isLeftToRightDirection()) {
    if (queryData->isVerticalText)
      glyphExtents.move(0, -glyphExtents.height());
    else
      glyphExtents.move(-glyphExtents.width(), 0);
  }
  return glyphExtents;
}

static inline FloatRect calculateGlyphBoundaries(
    const QueryData* queryData,
    const SVGTextFragment& fragment,
    int startPosition) {
  const float scalingFactor = queryData->textLineLayout.scalingFactor();
  ASSERT(scalingFactor);
  const float baseline =
      queryData->textLineLayout.scaledFont().getFontMetrics().floatAscent() /
      scalingFactor;

  float glyphOffsetInDirection =
      calculateGlyphRange(queryData, fragment, 0, startPosition);
  FloatPoint glyphPosition = logicalGlyphPositionToPhysical(
      queryData, fragment, glyphOffsetInDirection);
  glyphPosition.move(0, -baseline);

  // Use the SVGTextMetrics computed by SVGTextMetricsBuilder.
  const MetricsList& metricsList = queryData->textLineLayout.metricsList();
  auto metrics = findMetricsForCharacter(metricsList, fragment, startPosition);

  FloatRect extent = physicalGlyphExtents(queryData, *metrics, glyphPosition);
  if (fragment.isTransformed()) {
    AffineTransform fragmentTransform = fragment.buildFragmentTransform(
        SVGTextFragment::TransformIgnoringTextLength);
    extent = fragmentTransform.mapRect(extent);
  }
  return extent;
}

static bool extentOfCharacterCallback(QueryData* queryData,
                                      const SVGTextFragment& fragment) {
  ExtentOfCharacterData* data = static_cast<ExtentOfCharacterData*>(queryData);

  int startPosition = data->position;
  int endPosition = startPosition + 1;
  if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment,
                                                   startPosition, endPosition))
    return false;

  data->extent = calculateGlyphBoundaries(queryData, fragment, startPosition);
  return true;
}

FloatRect SVGTextQuery::extentOfCharacter(unsigned position) const {
  ExtentOfCharacterData data(position);
  logicalQuery(m_queryRootLayoutObject, &data, extentOfCharacterCallback);
  return data.extent;
}

// characterNumberAtPosition() implementation
struct CharacterNumberAtPositionData : QueryData {
  CharacterNumberAtPositionData(const FloatPoint& queryPosition)
      : position(queryPosition), hitLayoutItem(nullptr), offsetInTextNode(0) {}

  int characterNumberWithin(const LayoutObject* queryRoot) const;

  FloatPoint position;
  LineLayoutItem hitLayoutItem;
  int offsetInTextNode;
};

int CharacterNumberAtPositionData::characterNumberWithin(
    const LayoutObject* queryRoot) const {
  // http://www.w3.org/TR/SVG/single-page.html#text-__svg__SVGTextContentElement__getCharNumAtPosition
  // "If no such character exists, a value of -1 is returned."
  if (!hitLayoutItem)
    return -1;
  ASSERT(queryRoot);
  int characterNumber = offsetInTextNode;

  // Accumulate the lengths of all the text nodes preceding the target layout
  // object within the queried root, to get the complete character number.
  for (LineLayoutItem layoutItem = hitLayoutItem.previousInPreOrder(queryRoot);
       layoutItem; layoutItem = layoutItem.previousInPreOrder(queryRoot)) {
    if (!layoutItem.isSVGInlineText())
      continue;
    characterNumber += LineLayoutSVGInlineText(layoutItem).resolvedTextLength();
  }
  return characterNumber;
}

static unsigned logicalOffsetInTextNode(LineLayoutSVGInlineText textLineLayout,
                                        const SVGInlineTextBox* startTextBox,
                                        unsigned fragmentOffset) {
  Vector<SVGInlineTextBox*> textBoxes;
  collectTextBoxesInLogicalOrder(textLineLayout, textBoxes);

  ASSERT(startTextBox);
  size_t index = textBoxes.find(startTextBox);
  ASSERT(index != kNotFound);

  unsigned offset = fragmentOffset;
  while (index) {
    --index;
    offset += textBoxes[index]->len();
  }
  return offset;
}

static bool characterNumberAtPositionCallback(QueryData* queryData,
                                              const SVGTextFragment& fragment) {
  CharacterNumberAtPositionData* data =
      static_cast<CharacterNumberAtPositionData*>(queryData);

  const float scalingFactor = data->textLineLayout.scalingFactor();
  ASSERT(scalingFactor);
  const float baseline =
      data->textLineLayout.scaledFont().getFontMetrics().floatAscent() /
      scalingFactor;

  // Test the query point against the bounds of the entire fragment first.
  if (!fragment.boundingBox(baseline).contains(data->position))
    return false;

  AffineTransform fragmentTransform = fragment.buildFragmentTransform(
      SVGTextFragment::TransformIgnoringTextLength);

  // Iterate through the glyphs in this fragment, and check if their extents
  // contain the query point.
  MetricsList::const_iterator metrics =
      data->textLineLayout.metricsList().begin() + fragment.metricsListOffset;
  unsigned fragmentOffset = 0;
  float glyphOffset = 0;
  while (fragmentOffset < fragment.length) {
    FloatPoint glyphPosition =
        logicalGlyphPositionToPhysical(data, fragment, glyphOffset);
    glyphPosition.move(0, -baseline);

    FloatRect extent = fragmentTransform.mapRect(
        physicalGlyphExtents(data, *metrics, glyphPosition));
    if (extent.contains(data->position)) {
      // Compute the character offset of the glyph within the text node.
      unsigned offsetInBox = fragment.characterOffset -
                             queryData->textBox->start() + fragmentOffset;
      data->offsetInTextNode = logicalOffsetInTextNode(
          queryData->textLineLayout, queryData->textBox, offsetInBox);
      data->hitLayoutItem = LineLayoutItem(data->textLineLayout);
      return true;
    }
    fragmentOffset += metrics->length();
    glyphOffset += data->isVerticalText ? metrics->height() : metrics->width();
    ++metrics;
  }
  return false;
}

int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const {
  CharacterNumberAtPositionData data(position);
  spatialQuery(m_queryRootLayoutObject, &data,
               characterNumberAtPositionCallback);
  return data.characterNumberWithin(m_queryRootLayoutObject);
}

}  // namespace blink
