/*
 * Copyright (C) 2013, Google 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.
 * 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 "modules/accessibility/AXInlineTextBox.h"

#include "core/dom/Range.h"
#include "core/layout/LayoutText.h"
#include "core/layout/api/LineLayoutAPIShim.h"
#include "modules/accessibility/AXObjectCacheImpl.h"
#include "platform/LayoutUnit.h"

namespace blink {

using namespace HTMLNames;

AXInlineTextBox::AXInlineTextBox(
    PassRefPtr<AbstractInlineTextBox> inlineTextBox,
    AXObjectCacheImpl& axObjectCache)
    : AXObject(axObjectCache), m_inlineTextBox(inlineTextBox) {}

AXInlineTextBox* AXInlineTextBox::create(
    PassRefPtr<AbstractInlineTextBox> inlineTextBox,
    AXObjectCacheImpl& axObjectCache) {
  return new AXInlineTextBox(std::move(inlineTextBox), axObjectCache);
}

void AXInlineTextBox::init() {}

void AXInlineTextBox::detach() {
  AXObject::detach();
  m_inlineTextBox = nullptr;
}

void AXInlineTextBox::getRelativeBounds(
    AXObject** outContainer,
    FloatRect& outBoundsInContainer,
    SkMatrix44& outContainerTransform) const {
  *outContainer = nullptr;
  outBoundsInContainer = FloatRect();
  outContainerTransform.setIdentity();

  if (!m_inlineTextBox || !parentObject() || !parentObject()->getLayoutObject())
    return;

  *outContainer = parentObject();
  outBoundsInContainer = FloatRect(m_inlineTextBox->localBounds());

  // Subtract the local bounding box of the parent because they're
  // both in the same coordinate system.
  LayoutObject* parentLayoutObject = parentObject()->getLayoutObject();
  FloatRect parentBoundingBox =
      parentLayoutObject->localBoundingBoxRectForAccessibility();
  outBoundsInContainer.moveBy(-parentBoundingBox.location());
}

bool AXInlineTextBox::computeAccessibilityIsIgnored(
    IgnoredReasons* ignoredReasons) const {
  AXObject* parent = parentObject();
  if (!parent)
    return false;

  if (!parent->accessibilityIsIgnored())
    return false;

  if (ignoredReasons)
    parent->computeAccessibilityIsIgnored(ignoredReasons);

  return true;
}

void AXInlineTextBox::textCharacterOffsets(Vector<int>& offsets) const {
  if (!m_inlineTextBox)
    return;

  unsigned len = m_inlineTextBox->len();
  Vector<float> widths;
  m_inlineTextBox->characterWidths(widths);
  ASSERT(widths.size() == len);
  offsets.resize(len);

  float widthSoFar = 0;
  for (unsigned i = 0; i < len; i++) {
    widthSoFar += widths[i];
    offsets[i] = roundf(widthSoFar);
  }
}

void AXInlineTextBox::wordBoundaries(Vector<AXRange>& words) const {
  if (!m_inlineTextBox)
    return;

  Vector<AbstractInlineTextBox::WordBoundaries> wordBoundaries;
  m_inlineTextBox->wordBoundaries(wordBoundaries);
  words.resize(wordBoundaries.size());
  for (unsigned i = 0; i < wordBoundaries.size(); i++)
    words[i] =
        AXRange(wordBoundaries[i].startIndex, wordBoundaries[i].endIndex);
}

String AXInlineTextBox::name(AXNameFrom& nameFrom,
                             AXObject::AXObjectVector* nameObjects) const {
  if (!m_inlineTextBox)
    return String();

  nameFrom = AXNameFromContents;
  return m_inlineTextBox->text();
}

AXObject* AXInlineTextBox::computeParent() const {
  ASSERT(!isDetached());
  if (!m_inlineTextBox || !m_axObjectCache)
    return 0;

  LineLayoutText lineLayoutText = m_inlineTextBox->getLineLayoutItem();
  return m_axObjectCache->getOrCreate(
      LineLayoutAPIShim::layoutObjectFrom(lineLayoutText));
}

// In addition to LTR and RTL direction, edit fields also support
// top to bottom and bottom to top via the CSS writing-mode property.
AccessibilityTextDirection AXInlineTextBox::textDirection() const {
  if (!m_inlineTextBox)
    return AXObject::textDirection();

  switch (m_inlineTextBox->getDirection()) {
    case AbstractInlineTextBox::LeftToRight:
      return AccessibilityTextDirectionLTR;
    case AbstractInlineTextBox::RightToLeft:
      return AccessibilityTextDirectionRTL;
    case AbstractInlineTextBox::TopToBottom:
      return AccessibilityTextDirectionTTB;
    case AbstractInlineTextBox::BottomToTop:
      return AccessibilityTextDirectionBTT;
  }

  return AXObject::textDirection();
}

AXObject* AXInlineTextBox::nextOnLine() const {
  RefPtr<AbstractInlineTextBox> nextOnLine = m_inlineTextBox->nextOnLine();
  if (nextOnLine)
    return m_axObjectCache->getOrCreate(nextOnLine.get());

  if (!m_inlineTextBox->isLast())
    return 0;

  return parentObject()->nextOnLine();
}

AXObject* AXInlineTextBox::previousOnLine() const {
  RefPtr<AbstractInlineTextBox> previousOnLine =
      m_inlineTextBox->previousOnLine();
  if (previousOnLine)
    return m_axObjectCache->getOrCreate(previousOnLine.get());

  if (!m_inlineTextBox->isFirst())
    return 0;

  return parentObject()->previousOnLine();
}

}  // namespace blink
