// Copyright 2013 The Flutter 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 "impeller/entity/contents/text_contents.h"

#include <cstring>
#include <optional>
#include <utility>

#include "impeller/core/formats.h"
#include "impeller/core/sampler_descriptor.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/entity.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/typographer/glyph_atlas.h"
#include "impeller/typographer/lazy_glyph_atlas.h"

namespace impeller {

TextContents::TextContents() = default;

TextContents::~TextContents() = default;

void TextContents::SetTextFrame(const std::shared_ptr<TextFrame>& frame) {
  frame_ = frame;
}

void TextContents::SetColor(Color color) {
  color_ = color;
}

Color TextContents::GetColor() const {
  return color_.WithAlpha(color_.alpha * inherited_opacity_);
}

bool TextContents::CanInheritOpacity(const Entity& entity) const {
  return !frame_->MaybeHasOverlapping();
}

void TextContents::SetInheritedOpacity(Scalar opacity) {
  inherited_opacity_ = opacity;
}

void TextContents::SetOffset(Vector2 offset) {
  offset_ = offset;
}

void TextContents::SetForceTextColor(bool value) {
  force_text_color_ = value;
}

std::optional<Rect> TextContents::GetCoverage(const Entity& entity) const {
  return frame_->GetBounds().TransformBounds(entity.GetTransform());
}

void TextContents::PopulateGlyphAtlas(
    const std::shared_ptr<LazyGlyphAtlas>& lazy_glyph_atlas,
    Scalar scale) {
  lazy_glyph_atlas->AddTextFrame(*frame_, scale);
  scale_ = scale;
}

bool TextContents::Render(const ContentContext& renderer,
                          const Entity& entity,
                          RenderPass& pass) const {
  auto color = GetColor();
  if (color.IsTransparent()) {
    return true;
  }

  auto type = frame_->GetAtlasType();
  const std::shared_ptr<GlyphAtlas>& atlas =
      renderer.GetLazyGlyphAtlas()->CreateOrGetGlyphAtlas(
          *renderer.GetContext(), type);

  if (!atlas || !atlas->IsValid()) {
    VALIDATION_LOG << "Cannot render glyphs without prepared atlas.";
    return false;
  }

  // Information shared by all glyph draw calls.
  pass.SetCommandLabel("TextFrame");
  auto opts = OptionsFromPassAndEntity(pass, entity);
  opts.primitive_type = PrimitiveType::kTriangle;
  if (type == GlyphAtlas::Type::kAlphaBitmap) {
    pass.SetPipeline(renderer.GetGlyphAtlasPipeline(opts));
  } else {
    pass.SetPipeline(renderer.GetGlyphAtlasColorPipeline(opts));
  }
  pass.SetStencilReference(entity.GetClipDepth());

  using VS = GlyphAtlasPipeline::VertexShader;
  using FS = GlyphAtlasPipeline::FragmentShader;

  // Common vertex uniforms for all glyphs.
  VS::FrameInfo frame_info;
  frame_info.depth = entity.GetShaderClipDepth();
  frame_info.mvp = pass.GetOrthographicTransform();
  frame_info.atlas_size =
      Vector2{static_cast<Scalar>(atlas->GetTexture()->GetSize().width),
              static_cast<Scalar>(atlas->GetTexture()->GetSize().height)};
  frame_info.offset = offset_;
  frame_info.is_translation_scale =
      entity.GetTransform().IsTranslationScaleOnly();
  frame_info.entity_transform = entity.GetTransform();
  frame_info.text_color = ToVector(color.Premultiply());

  VS::BindFrameInfo(pass,
                    renderer.GetTransientsBuffer().EmplaceUniform(frame_info));

  if (type == GlyphAtlas::Type::kColorBitmap) {
    using FSS = GlyphAtlasColorPipeline::FragmentShader;
    FSS::FragInfo frag_info;
    frag_info.use_text_color = force_text_color_ ? 1.0 : 0.0;
    FSS::BindFragInfo(pass,
                      renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
  }

  SamplerDescriptor sampler_desc;
  if (frame_info.is_translation_scale) {
    sampler_desc.min_filter = MinMagFilter::kNearest;
    sampler_desc.mag_filter = MinMagFilter::kNearest;
  } else {
    // Currently, we only propagate the scale of the transform to the atlas
    // renderer, so if the transform has more than just a translation, we turn
    // on linear sampling to prevent crunchiness caused by the pixel grid not
    // being perfectly aligned.
    // The downside is that this slightly over-blurs rotated/skewed text.
    sampler_desc.min_filter = MinMagFilter::kLinear;
    sampler_desc.mag_filter = MinMagFilter::kLinear;
  }
  sampler_desc.mip_filter = MipFilter::kNearest;

  FS::BindGlyphAtlasSampler(
      pass,                 // command
      atlas->GetTexture(),  // texture
      renderer.GetContext()->GetSamplerLibrary()->GetSampler(
          sampler_desc)  // sampler
  );

  // Common vertex information for all glyphs.
  // All glyphs are given the same vertex information in the form of a
  // unit-sized quad. The size of the glyph is specified in per instance data
  // and the vertex shader uses this to size the glyph correctly. The
  // interpolated vertex information is also used in the fragment shader to
  // sample from the glyph atlas.

  constexpr std::array<Point, 6> unit_points = {Point{0, 0}, Point{1, 0},
                                                Point{0, 1}, Point{1, 0},
                                                Point{0, 1}, Point{1, 1}};

  auto& host_buffer = renderer.GetTransientsBuffer();
  size_t vertex_count = 0;
  for (const auto& run : frame_->GetRuns()) {
    vertex_count += run.GetGlyphPositions().size();
  }
  vertex_count *= 6;

  auto buffer_view = host_buffer.Emplace(
      vertex_count * sizeof(VS::PerVertexData), alignof(VS::PerVertexData),
      [&](uint8_t* contents) {
        VS::PerVertexData vtx;
        VS::PerVertexData* vtx_contents =
            reinterpret_cast<VS::PerVertexData*>(contents);
        for (const TextRun& run : frame_->GetRuns()) {
          const Font& font = run.GetFont();
          Scalar rounded_scale = TextFrame::RoundScaledFontSize(
              scale_, font.GetMetrics().point_size);
          const FontGlyphAtlas* font_atlas =
              atlas->GetFontGlyphAtlas(font, rounded_scale);
          if (!font_atlas) {
            VALIDATION_LOG << "Could not find font in the atlas.";
            continue;
          }

          for (const TextRun::GlyphPosition& glyph_position :
               run.GetGlyphPositions()) {
            std::optional<Rect> maybe_atlas_glyph_bounds =
                font_atlas->FindGlyphBounds(glyph_position.glyph);
            if (!maybe_atlas_glyph_bounds.has_value()) {
              VALIDATION_LOG << "Could not find glyph position in the atlas.";
              continue;
            }
            const Rect& atlas_glyph_bounds = maybe_atlas_glyph_bounds.value();
            vtx.atlas_glyph_bounds = Vector4(atlas_glyph_bounds.GetXYWH());
            vtx.glyph_bounds = Vector4(glyph_position.glyph.bounds.GetXYWH());
            vtx.glyph_position = glyph_position.position;

            for (const Point& point : unit_points) {
              vtx.unit_position = point;
              std::memcpy(vtx_contents++, &vtx, sizeof(VS::PerVertexData));
            }
          }
        }
      });

  pass.SetVertexBuffer({
      .vertex_buffer = std::move(buffer_view),
      .index_buffer = {},
      .vertex_count = vertex_count,
      .index_type = IndexType::kNone,
  });

  return pass.Draw().ok();
}

}  // namespace impeller
