// 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 "flutter/lib/ui/painting/gradient.h"

#include "flutter/lib/ui/floating_point.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_args.h"
#include "third_party/tonic/dart_binding_macros.h"
#include "third_party/tonic/dart_library_natives.h"

namespace flutter {

typedef CanvasGradient
    Gradient;  // Because the C++ name doesn't match the Dart name.

IMPLEMENT_WRAPPERTYPEINFO(ui, Gradient);

void CanvasGradient::Create(Dart_Handle wrapper) {
  UIDartState::ThrowIfUIOperationsProhibited();
  auto res = fml::MakeRefCounted<CanvasGradient>();
  res->AssociateWithDartWrapper(wrapper);
}

void CanvasGradient::initLinear(const tonic::Float32List& end_points,
                                const tonic::Int32List& colors,
                                const tonic::Float32List& color_stops,
                                DlTileMode tile_mode,
                                const tonic::Float64List& matrix4) {
  FML_DCHECK(end_points.num_elements() == 4);
  FML_DCHECK(colors.num_elements() == color_stops.num_elements() ||
             color_stops.data() == nullptr);

  static_assert(sizeof(SkPoint) == sizeof(float) * 2,
                "SkPoint doesn't use floats.");
  static_assert(sizeof(SkColor) == sizeof(int32_t),
                "SkColor doesn't use int32_t.");

  SkMatrix sk_matrix;
  bool has_matrix = matrix4.data() != nullptr;
  if (has_matrix) {
    sk_matrix = ToSkMatrix(matrix4);
  }

  SkPoint p0 = SkPoint::Make(end_points[0], end_points[1]);
  SkPoint p1 = SkPoint::Make(end_points[2], end_points[3]);
  const DlColor* colors_array = reinterpret_cast<const DlColor*>(colors.data());

  dl_shader_ = DlColorSource::MakeLinear(
      p0, p1, colors.num_elements(), colors_array, color_stops.data(),
      tile_mode, has_matrix ? &sk_matrix : nullptr);
  // Just a sanity check, all gradient shaders should be thread-safe
  FML_DCHECK(dl_shader_->isUIThreadSafe());
}

void CanvasGradient::initRadial(double center_x,
                                double center_y,
                                double radius,
                                const tonic::Int32List& colors,
                                const tonic::Float32List& color_stops,
                                DlTileMode tile_mode,
                                const tonic::Float64List& matrix4) {
  FML_DCHECK(colors.num_elements() == color_stops.num_elements() ||
             color_stops.data() == nullptr);

  static_assert(sizeof(SkColor) == sizeof(int32_t),
                "SkColor doesn't use int32_t.");

  SkMatrix sk_matrix;
  bool has_matrix = matrix4.data() != nullptr;
  if (has_matrix) {
    sk_matrix = ToSkMatrix(matrix4);
  }

  const DlColor* colors_array = reinterpret_cast<const DlColor*>(colors.data());

  dl_shader_ = DlColorSource::MakeRadial(
      SkPoint::Make(SafeNarrow(center_x), SafeNarrow(center_y)),
      SafeNarrow(radius), colors.num_elements(), colors_array,
      color_stops.data(), tile_mode, has_matrix ? &sk_matrix : nullptr);
  // Just a sanity check, all gradient shaders should be thread-safe
  FML_DCHECK(dl_shader_->isUIThreadSafe());
}

void CanvasGradient::initSweep(double center_x,
                               double center_y,
                               const tonic::Int32List& colors,
                               const tonic::Float32List& color_stops,
                               DlTileMode tile_mode,
                               double start_angle,
                               double end_angle,
                               const tonic::Float64List& matrix4) {
  FML_DCHECK(colors.num_elements() == color_stops.num_elements() ||
             color_stops.data() == nullptr);

  static_assert(sizeof(SkColor) == sizeof(int32_t),
                "SkColor doesn't use int32_t.");

  SkMatrix sk_matrix;
  bool has_matrix = matrix4.data() != nullptr;
  if (has_matrix) {
    sk_matrix = ToSkMatrix(matrix4);
  }

  const DlColor* colors_array = reinterpret_cast<const DlColor*>(colors.data());

  dl_shader_ = DlColorSource::MakeSweep(
      SkPoint::Make(SafeNarrow(center_x), SafeNarrow(center_y)),
      SafeNarrow(start_angle) * 180.0f / static_cast<float>(M_PI),
      SafeNarrow(end_angle) * 180.0f / static_cast<float>(M_PI),
      colors.num_elements(), colors_array, color_stops.data(), tile_mode,
      has_matrix ? &sk_matrix : nullptr);
  // Just a sanity check, all gradient shaders should be thread-safe
  FML_DCHECK(dl_shader_->isUIThreadSafe());
}

void CanvasGradient::initTwoPointConical(double start_x,
                                         double start_y,
                                         double start_radius,
                                         double end_x,
                                         double end_y,
                                         double end_radius,
                                         const tonic::Int32List& colors,
                                         const tonic::Float32List& color_stops,
                                         DlTileMode tile_mode,
                                         const tonic::Float64List& matrix4) {
  FML_DCHECK(colors.num_elements() == color_stops.num_elements() ||
             color_stops.data() == nullptr);

  static_assert(sizeof(SkColor) == sizeof(int32_t),
                "SkColor doesn't use int32_t.");

  SkMatrix sk_matrix;
  bool has_matrix = matrix4.data() != nullptr;
  if (has_matrix) {
    sk_matrix = ToSkMatrix(matrix4);
  }

  const DlColor* colors_array = reinterpret_cast<const DlColor*>(colors.data());

  dl_shader_ = DlColorSource::MakeConical(
      SkPoint::Make(SafeNarrow(start_x), SafeNarrow(start_y)),
      SafeNarrow(start_radius),
      SkPoint::Make(SafeNarrow(end_x), SafeNarrow(end_y)),
      SafeNarrow(end_radius), colors.num_elements(), colors_array,
      color_stops.data(), tile_mode, has_matrix ? &sk_matrix : nullptr);
  // Just a sanity check, all gradient shaders should be thread-safe
  FML_DCHECK(dl_shader_->isUIThreadSafe());
}

CanvasGradient::CanvasGradient() = default;

CanvasGradient::~CanvasGradient() = default;

}  // namespace flutter
