blob: c3ed972259f3e8dc712684a047b637ec55908613 [file] [log] [blame]
// 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.
#ifndef FLUTTER_LIB_UI_PAINTING_IMAGE_GENERATOR_H_
#define FLUTTER_LIB_UI_PAINTING_IMAGE_GENERATOR_H_
#include <optional>
#include "flutter/fml/macros.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/src/codec/SkCodecImageGenerator.h"
namespace flutter {
/// @brief The minimal interface necessary for defining a decoder that can be
/// used for both single and multi-frame image decoding. Image
/// generators can also optionally support decoding into a subscaled
/// buffer. Implementers of `ImageGenerator` regularly keep internal
/// state which is not thread safe, and so aliasing and parallel access
/// should never be done with `ImageGenerator`s.
/// @see `ImageGenerator::GetScaledDimensions`
class ImageGenerator {
public:
/// Frame count value to denote infinite looping.
const static unsigned int kInfinitePlayCount =
std::numeric_limits<unsigned int>::max();
/// @brief Info about a single frame in the context of a multi-frame image,
/// useful for animation and blending.
struct FrameInfo {
/// The frame index of the frame that, if any, this frame needs to be
/// blended with.
std::optional<unsigned int> required_frame;
/// Number of milliseconds to show this frame.
unsigned int duration;
/// How this frame should be modified before decoding the next one.
SkCodecAnimation::DisposalMethod disposal_method;
};
virtual ~ImageGenerator();
/// @brief Returns basic information about the contents of the encoded
/// image. This information can almost always be collected by just
/// interpreting the header of a decoded image.
/// @return Size and color information describing the image.
/// @note This method is executed on the UI thread and used for layout
/// purposes by the framework, and so this method should not perform
/// long synchronous tasks.
virtual const SkImageInfo& GetInfo() = 0;
/// @brief Get the number of frames that the encoded image stores. This
/// method is always expected to be called before `GetFrameInfo`, as
/// the underlying image decoder may interpret frame information that
/// is then used when calling `GetFrameInfo`.
/// @return The number of frames that the encoded image stores. This will
/// always be 1 for single-frame images.
virtual unsigned int GetFrameCount() const = 0;
/// @brief The number of times an animated image should play through before
/// playback stops.
/// @return If this image is animated, the number of times the animation
/// should play through is returned, otherwise it'll just return 1.
/// If the animation should loop forever, `kInfinitePlayCount` is
/// returned.
virtual unsigned int GetPlayCount() const = 0;
/// @brief Get information about a single frame in the context of a
/// multi-frame image, useful for animation and frame blending.
/// This method should only ever be called after `GetFrameCount`
/// has been called. This information is nonsensical for
/// single-frame images.
/// @param[in] frame_index The index of the frame to get information about.
/// @return Information about the given frame. If the image is
/// single-frame, a default result is returned.
/// @see `GetFrameCount`
virtual const FrameInfo GetFrameInfo(unsigned int frame_index) const = 0;
/// @brief Given a scale value, find the closest image size that can be
/// used for efficiently decoding the image. If subpixel image
/// decoding is not supported by the decoder, this method should
/// just return the original image size.
/// @param[in] scale The desired scale factor of the image for decoding.
/// @return The closest image size that can be used for efficiently
/// decoding the image.
/// @note This method is called prior to `GetPixels` in order to query
/// for supported sizes.
/// @see `GetPixels`
virtual SkISize GetScaledDimensions(float scale) = 0;
/// @brief Decode the image into a given buffer. This method is currently
/// always used for sub-pixel image decoding. For full-sized still
/// images, `GetImage` is always attempted first.
/// @param[in] info The desired size and color info of the decoded
/// image to be returned. The implementation of
/// `GetScaledDimensions` determines which sizes are
/// supported by the image decoder.
/// @param[in] pixels The location where the raw decoded image data
/// should be written.
/// @param[in] row_bytes The total number of bytes that should make up a
/// single row of decoded image data
/// (i.e. width * bytes_per_pixel).
/// @param[in] frame_index Which frame to decode. This is only useful for
/// multi-frame images.
/// @param[in] prior_frame Optional frame index parameter for multi-frame
/// images which specifies the previous frame that
/// should be use for blending. This hints to the
/// decoder that it should use a previously cached
/// frame instead of decoding dependency frame(s).
/// If an empty value is supplied, the decoder should
/// decode any necessary frames first.
/// @return True if the image was successfully decoded.
/// @note This method performs potentially long synchronous work, and so
/// it should never be executed on the UI thread. Image decoders
/// do not require GPU acceleration, and so threads without a GPU
/// context may also be used.
/// @see `GetScaledDimensions`
virtual bool GetPixels(
const SkImageInfo& info,
void* pixels,
size_t row_bytes,
unsigned int frame_index = 0,
std::optional<unsigned int> prior_frame = std::nullopt) = 0;
/// @brief Creates an `SkImage` based on the current `ImageInfo` of this
/// `ImageGenerator`.
/// @return A new `SkImage` containing the decoded image data.
sk_sp<SkImage> GetImage();
};
class BuiltinSkiaImageGenerator : public ImageGenerator {
public:
~BuiltinSkiaImageGenerator();
explicit BuiltinSkiaImageGenerator(
std::unique_ptr<SkImageGenerator> generator);
// |ImageGenerator|
const SkImageInfo& GetInfo() override;
// |ImageGenerator|
unsigned int GetFrameCount() const override;
// |ImageGenerator|
unsigned int GetPlayCount() const override;
// |ImageGenerator|
const ImageGenerator::FrameInfo GetFrameInfo(
unsigned int frame_index) const override;
// |ImageGenerator|
SkISize GetScaledDimensions(float desired_scale) override;
// |ImageGenerator|
bool GetPixels(
const SkImageInfo& info,
void* pixels,
size_t row_bytes,
unsigned int frame_index = 0,
std::optional<unsigned int> prior_frame = std::nullopt) override;
static std::unique_ptr<ImageGenerator> MakeFromGenerator(
std::unique_ptr<SkImageGenerator> generator);
private:
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(BuiltinSkiaImageGenerator);
std::unique_ptr<SkImageGenerator> generator_;
};
class BuiltinSkiaCodecImageGenerator : public ImageGenerator {
public:
~BuiltinSkiaCodecImageGenerator();
explicit BuiltinSkiaCodecImageGenerator(std::unique_ptr<SkCodec> codec);
explicit BuiltinSkiaCodecImageGenerator(sk_sp<SkData> buffer);
// |ImageGenerator|
const SkImageInfo& GetInfo() override;
// |ImageGenerator|
unsigned int GetFrameCount() const override;
// |ImageGenerator|
unsigned int GetPlayCount() const override;
// |ImageGenerator|
const ImageGenerator::FrameInfo GetFrameInfo(
unsigned int frame_index) const override;
// |ImageGenerator|
SkISize GetScaledDimensions(float desired_scale) override;
// |ImageGenerator|
bool GetPixels(
const SkImageInfo& info,
void* pixels,
size_t row_bytes,
unsigned int frame_index = 0,
std::optional<unsigned int> prior_frame = std::nullopt) override;
static std::unique_ptr<ImageGenerator> MakeFromData(sk_sp<SkData> data);
private:
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(BuiltinSkiaCodecImageGenerator);
std::unique_ptr<SkCodecImageGenerator> codec_generator_;
};
} // namespace flutter
#endif // FLUTTER_LIB_UI_PAINTING_IMAGE_GENERATOR_H_