// Copyright 2016 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <memory>

#include "cobalt/renderer/rasterizer/blitter/image.h"

#include "base/bind.h"
#include "cobalt/render_tree/image.h"
#include "cobalt/renderer/backend/blitter/surface_render_target.h"
#include "cobalt/renderer/rasterizer/blitter/render_tree_blitter_conversions.h"
#include "cobalt/renderer/rasterizer/blitter/skia_blitter_conversions.h"
#include "cobalt/renderer/rasterizer/skia/image.h"
#include "starboard/blitter.h"

#if SB_API_VERSION >= SB_ALL_RENDERERS_REQUIRED_VERSION || SB_HAS(BLITTER)

namespace cobalt {
namespace renderer {
namespace rasterizer {
namespace blitter {

ImageData::ImageData(SbBlitterDevice device, const math::Size& size,
                     render_tree::PixelFormat pixel_format,
                     render_tree::AlphaFormat alpha_format)
    : device_(device),
      pixel_data_(SbBlitterCreatePixelData(
          device_, size.width(), size.height(),
          RenderTreePixelFormatToBlitter(pixel_format))) {
  CHECK(alpha_format == render_tree::kAlphaFormatPremultiplied ||
        alpha_format == render_tree::kAlphaFormatOpaque);

  if (SbBlitterIsPixelDataValid(pixel_data_)) {
    descriptor_.emplace(size, pixel_format, alpha_format,
                        SbBlitterGetPixelDataPitchInBytes(pixel_data_));
  } else {
    LOG(ERROR) << "Failed to allocate pixel data for image.";
  }
}

ImageData::~ImageData() {
  if (SbBlitterIsPixelDataValid(pixel_data_)) {
    SbBlitterDestroyPixelData(pixel_data_);
  }
}

uint8* ImageData::GetMemory() {
  if (!SbBlitterIsPixelDataValid(pixel_data_)) {
    return NULL;
  } else {
    return static_cast<uint8*>(SbBlitterGetPixelDataPointer(pixel_data_));
  }
}

SbBlitterPixelData ImageData::TakePixelData() {
  SbBlitterPixelData pixel_data = pixel_data_;
  pixel_data_ = kSbBlitterInvalidPixelData;
  return pixel_data;
}

SinglePlaneImage::SinglePlaneImage(std::unique_ptr<ImageData> image_data)
    : size_(image_data->GetDescriptor().size) {
  surface_ = SbBlitterCreateSurfaceFromPixelData(image_data->device(),
                                                 image_data->TakePixelData());
  CHECK(SbBlitterIsSurfaceValid(surface_));

  is_opaque_ = image_data->GetDescriptor().alpha_format ==
               render_tree::kAlphaFormatOpaque;
}

SinglePlaneImage::SinglePlaneImage(SbBlitterSurface surface, bool is_opaque,
                                   const base::Closure& delete_function)
    : surface_(surface),
      is_opaque_(is_opaque),
      delete_function_(delete_function) {
  CHECK(SbBlitterIsSurfaceValid(surface_));
  SbBlitterSurfaceInfo info;
  if (!SbBlitterGetSurfaceInfo(surface_, &info)) {
    NOTREACHED();
  }
  size_ = math::Size(info.width, info.height);
}

SinglePlaneImage::SinglePlaneImage(
    const scoped_refptr<render_tree::Node>& root,
    SubmitOffscreenCallback submit_offscreen_callback, SbBlitterDevice device)
    : size_(static_cast<int>(root->GetBounds().right()),
            static_cast<int>(root->GetBounds().bottom())),
      is_opaque_(false),
      surface_(kSbBlitterInvalidSurface) {
  initialize_image_ = base::Bind(
      &SinglePlaneImage::InitializeImageFromRenderTree, base::Unretained(this),
      root, submit_offscreen_callback, device);
}

bool SinglePlaneImage::EnsureInitialized() {
  if (!initialize_image_.is_null()) {
    initialize_image_.Run();
    initialize_image_.Reset();
    return true;
  }
  return false;
}

const sk_sp<SkImage>& SinglePlaneImage::GetImage() const {
  // This function will only ever get called if the Skia software renderer needs
  // to reference the image, and so should be called rarely.  In that case, the
  // first time it is called on this image, we will download the image data from
  // the Blitter API surface into a SkBitmap object where the pixel data lives
  // in CPU memory.  It will then create an SkImage from that SkBitmap object,
  // and the pointer to the new SkImage object will be returned.
  if (!image_) {
    SkImageInfo image_info = SkImageInfo::Make(
        size_.width(), size_.height(), kN32_SkColorType, kPremul_SkAlphaType);

    SkBitmap bitmap;
    bool allocation_successful = bitmap.tryAllocPixels(image_info);
    if (!allocation_successful) {
      LOG(WARNING) << "Unable to allocate pixels of size " << size_.width()
                   << "x" << size_.height();
      return image_;
    }
    bool result = SbBlitterDownloadSurfacePixels(
        surface_, SkiaToBlitterPixelFormat(image_info.colorType()),
        bitmap.rowBytes(), bitmap.getPixels());
    if (!result) {
      LOG(WARNING) << "Failed to download surface pixel data so that it could "
                      "be accessed by software skia.";
      NOTREACHED();
    } else {
      image_ = SkImage::MakeFromBitmap(bitmap);
    }
  }

  return image_;
}

SinglePlaneImage::~SinglePlaneImage() {
  if (!delete_function_.is_null()) {
    delete_function_.Run();
  } else {
    SbBlitterDestroySurface(surface_);
  }
}

void SinglePlaneImage::InitializeImageFromRenderTree(
    const scoped_refptr<render_tree::Node>& root,
    const SubmitOffscreenCallback& submit_offscreen_callback,
    SbBlitterDevice device) {
  scoped_refptr<backend::SurfaceRenderTargetBlitter> render_target(
      new backend::SurfaceRenderTargetBlitter(device, size_));

  submit_offscreen_callback.Run(root, render_target);
  surface_ = render_target->TakeSbSurface();
  CHECK(SbBlitterIsSurfaceValid(surface_));
}

}  // namespace blitter
}  // namespace rasterizer
}  // namespace renderer
}  // namespace cobalt

#endif  // #if SB_API_VERSION >= SB_ALL_RENDERERS_REQUIRED_VERSION ||
        // SB_HAS(BLITTER)
