// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/cpp/dev/font_dev.h"

#include <algorithm>

#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/instance_handle.h"
#include "ppapi/cpp/point.h"
#include "ppapi/cpp/rect.h"
#include "ppapi/cpp/module_impl.h"

namespace pp {

namespace {

template <> const char* interface_name<PPB_Font_Dev>() {
  return PPB_FONT_DEV_INTERFACE;
}

}  // namespace

// FontDescription_Dev ---------------------------------------------------------

FontDescription_Dev::FontDescription_Dev() {
  pp_font_description_.face = face_.pp_var();
  set_family(PP_FONTFAMILY_DEFAULT);
  set_size(0);
  set_weight(PP_FONTWEIGHT_NORMAL);
  set_italic(false);
  set_small_caps(false);
  set_letter_spacing(0);
  set_word_spacing(0);
}

FontDescription_Dev::FontDescription_Dev(const FontDescription_Dev& other) {
  set_face(other.face());
  set_family(other.family());
  set_size(other.size());
  set_weight(other.weight());
  set_italic(other.italic());
  set_small_caps(other.small_caps());
  set_letter_spacing(other.letter_spacing());
  set_word_spacing(other.word_spacing());
}

FontDescription_Dev::~FontDescription_Dev() {
}

FontDescription_Dev& FontDescription_Dev::operator=(
    const FontDescription_Dev& other) {
  pp_font_description_ = other.pp_font_description_;

  // Be careful about the refcount of the string, the copy that operator= made
  // above didn't copy a ref.
  pp_font_description_.face = PP_MakeUndefined();
  set_face(other.face());

  return *this;
}

// TextRun_Dev -----------------------------------------------------------------

TextRun_Dev::TextRun_Dev() {
  pp_text_run_.text = text_.pp_var();
  pp_text_run_.rtl = PP_FALSE;
  pp_text_run_.override_direction = PP_FALSE;
}

TextRun_Dev::TextRun_Dev(const std::string& text,
                         bool rtl,
                         bool override_direction)
    : text_(text) {
  pp_text_run_.text = text_.pp_var();
  pp_text_run_.rtl = PP_FromBool(rtl);
  pp_text_run_.override_direction = PP_FromBool(override_direction);
}

TextRun_Dev::TextRun_Dev(const TextRun_Dev& other) : text_(other.text_) {
  pp_text_run_.text = text_.pp_var();
  pp_text_run_.rtl = other.pp_text_run_.rtl;
  pp_text_run_.override_direction = other.pp_text_run_.override_direction;
}

TextRun_Dev::~TextRun_Dev() {
}

TextRun_Dev& TextRun_Dev::operator=(const TextRun_Dev& other) {
  pp_text_run_ = other.pp_text_run_;
  text_ = other.text_;
  pp_text_run_.text = text_.pp_var();
  return *this;
}

// Font ------------------------------------------------------------------------

Font_Dev::Font_Dev() : Resource() {
}

Font_Dev::Font_Dev(PP_Resource resource) : Resource(resource) {
}

Font_Dev::Font_Dev(const InstanceHandle& instance,
                   const FontDescription_Dev& description) {
  if (!has_interface<PPB_Font_Dev>())
    return;
  PassRefFromConstructor(get_interface<PPB_Font_Dev>()->Create(
      instance.pp_instance(), &description.pp_font_description()));
}

Font_Dev::Font_Dev(const Font_Dev& other) : Resource(other) {
}

Font_Dev& Font_Dev::operator=(const Font_Dev& other) {
  Resource::operator=(other);
  return *this;
}

// static
Var Font_Dev::GetFontFamilies(const InstanceHandle& instance) {
  if (!has_interface<PPB_Font_Dev>())
    return Var();
  return Var(PASS_REF, get_interface<PPB_Font_Dev>()->GetFontFamilies(
                 instance.pp_instance()));
}

bool Font_Dev::Describe(FontDescription_Dev* description,
                        PP_FontMetrics_Dev* metrics) const {
  if (!has_interface<PPB_Font_Dev>())
    return false;

  // Be careful with ownership of the |face| string. It will come back with
  // a ref of 1, which we want to assign to the |face_| member of the C++ class.
  if (!get_interface<PPB_Font_Dev>()->Describe(
      pp_resource(), &description->pp_font_description_, metrics))
    return false;
  description->face_ = Var(PASS_REF,
                           description->pp_font_description_.face);

  return true;
}

bool Font_Dev::DrawTextAt(ImageData* dest,
                          const TextRun_Dev& text,
                          const Point& position,
                          uint32_t color,
                          const Rect& clip,
                          bool image_data_is_opaque) const {
  if (!has_interface<PPB_Font_Dev>())
    return false;
  return PP_ToBool(get_interface<PPB_Font_Dev>()->DrawTextAt(
      pp_resource(),
      dest->pp_resource(),
      &text.pp_text_run(),
      &position.pp_point(),
      color,
      &clip.pp_rect(),
      PP_FromBool(image_data_is_opaque)));
}

int32_t Font_Dev::MeasureText(const TextRun_Dev& text) const {
  if (!has_interface<PPB_Font_Dev>())
    return -1;
  return get_interface<PPB_Font_Dev>()->MeasureText(pp_resource(),
                                                    &text.pp_text_run());
}

uint32_t Font_Dev::CharacterOffsetForPixel(const TextRun_Dev& text,
                                           int32_t pixel_position) const {
  if (!has_interface<PPB_Font_Dev>())
    return 0;
  return get_interface<PPB_Font_Dev>()->CharacterOffsetForPixel(
      pp_resource(), &text.pp_text_run(), pixel_position);

}

int32_t Font_Dev::PixelOffsetForCharacter(const TextRun_Dev& text,
                                          uint32_t char_offset) const {
  if (!has_interface<PPB_Font_Dev>())
    return 0;
  return get_interface<PPB_Font_Dev>()->PixelOffsetForCharacter(
      pp_resource(), &text.pp_text_run(), char_offset);
}

bool Font_Dev::DrawSimpleText(ImageData* dest,
                              const std::string& text,
                              const Point& position,
                              uint32_t color,
                              bool image_data_is_opaque) const {
  return DrawTextAt(dest, TextRun_Dev(text), position, color,
                    Rect(dest->size()), image_data_is_opaque);
}

int32_t Font_Dev::MeasureSimpleText(const std::string& text) const {
  return MeasureText(TextRun_Dev(text));
}

}  // namespace pp