forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add image generator registry (flutter#25987)
Add image generator protocol and priority registry. The protocol supports multi-frame images as well as optional subpixel/downsampled decoding.
- Loading branch information
Showing
19 changed files
with
690 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// 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/image_generator.h" | ||
|
||
namespace flutter { | ||
|
||
ImageGenerator::~ImageGenerator() = default; | ||
|
||
BuiltinSkiaImageGenerator::~BuiltinSkiaImageGenerator() = default; | ||
|
||
BuiltinSkiaImageGenerator::BuiltinSkiaImageGenerator( | ||
std::unique_ptr<SkImageGenerator> generator) | ||
: generator_(std::move(generator)) {} | ||
|
||
const SkImageInfo& BuiltinSkiaImageGenerator::GetInfo() const { | ||
return generator_->getInfo(); | ||
} | ||
|
||
unsigned int BuiltinSkiaImageGenerator::GetFrameCount() const { | ||
return 1; | ||
} | ||
|
||
const ImageGenerator::FrameInfo BuiltinSkiaImageGenerator::GetFrameInfo( | ||
unsigned int frame_index) const { | ||
return {.required_frame = std::nullopt, | ||
.duration = 0, | ||
.disposal_method = SkCodecAnimation::DisposalMethod::kKeep}; | ||
} | ||
|
||
SkISize BuiltinSkiaImageGenerator::GetScaledDimensions( | ||
float desired_scale) const { | ||
return generator_->getInfo().dimensions(); | ||
} | ||
|
||
bool BuiltinSkiaImageGenerator::GetPixels( | ||
const SkImageInfo& info, | ||
void* pixels, | ||
size_t row_bytes, | ||
unsigned int frame_index, | ||
std::optional<unsigned int> prior_frame) const { | ||
return generator_->getPixels(info, pixels, row_bytes); | ||
} | ||
|
||
BuiltinSkiaCodecImageGenerator::~BuiltinSkiaCodecImageGenerator() = default; | ||
|
||
std::unique_ptr<ImageGenerator> BuiltinSkiaImageGenerator::MakeFromGenerator( | ||
std::unique_ptr<SkImageGenerator> generator) { | ||
if (!generator) { | ||
return nullptr; | ||
} | ||
return std::make_unique<BuiltinSkiaImageGenerator>(std::move(generator)); | ||
} | ||
|
||
BuiltinSkiaCodecImageGenerator::BuiltinSkiaCodecImageGenerator( | ||
std::unique_ptr<SkCodec> codec) | ||
: codec_generator_(static_cast<SkCodecImageGenerator*>( | ||
SkCodecImageGenerator::MakeFromCodec(std::move(codec)).release())) {} | ||
|
||
BuiltinSkiaCodecImageGenerator::BuiltinSkiaCodecImageGenerator( | ||
sk_sp<SkData> buffer) | ||
: codec_generator_(static_cast<SkCodecImageGenerator*>( | ||
SkCodecImageGenerator::MakeFromEncodedCodec(buffer).release())) {} | ||
|
||
const SkImageInfo& BuiltinSkiaCodecImageGenerator::GetInfo() const { | ||
return codec_generator_->getInfo(); | ||
} | ||
|
||
unsigned int BuiltinSkiaCodecImageGenerator::GetFrameCount() const { | ||
return codec_generator_->getFrameCount(); | ||
} | ||
|
||
const ImageGenerator::FrameInfo BuiltinSkiaCodecImageGenerator::GetFrameInfo( | ||
unsigned int frame_index) const { | ||
SkCodec::FrameInfo info; | ||
codec_generator_->getFrameInfo(frame_index, &info); | ||
return { | ||
.required_frame = info.fRequiredFrame == SkCodec::kNoFrame | ||
? std::nullopt | ||
: std::optional<unsigned int>(info.fRequiredFrame), | ||
.duration = static_cast<unsigned int>(info.fDuration), | ||
.disposal_method = info.fDisposalMethod}; | ||
} | ||
|
||
SkISize BuiltinSkiaCodecImageGenerator::GetScaledDimensions( | ||
float desired_scale) const { | ||
return codec_generator_->getScaledDimensions(desired_scale); | ||
} | ||
|
||
bool BuiltinSkiaCodecImageGenerator::GetPixels( | ||
const SkImageInfo& info, | ||
void* pixels, | ||
size_t row_bytes, | ||
unsigned int frame_index, | ||
std::optional<unsigned int> prior_frame) const { | ||
SkCodec::Options options; | ||
options.fFrameIndex = frame_index; | ||
if (prior_frame.has_value()) { | ||
options.fPriorFrame = prior_frame.value(); | ||
} | ||
return codec_generator_->getPixels(info, pixels, row_bytes, &options); | ||
} | ||
|
||
std::unique_ptr<ImageGenerator> BuiltinSkiaCodecImageGenerator::MakeFromData( | ||
sk_sp<SkData> data) { | ||
auto codec = SkCodec::MakeFromData(data); | ||
if (!codec) { | ||
return nullptr; | ||
} | ||
return std::make_unique<BuiltinSkiaCodecImageGenerator>(std::move(codec)); | ||
} | ||
|
||
} // namespace flutter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
// 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 "flutter/fml/macros.h" | ||
#include "flutter/lib/ui/painting/codec.h" | ||
#include "third_party/skia/include/core/SkImageInfo.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: | ||
/// @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() const = 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 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) const = 0; | ||
|
||
/// @brief Decode the image into a given buffer. | ||
/// @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) const = 0; | ||
}; | ||
|
||
class BuiltinSkiaImageGenerator : public ImageGenerator { | ||
public: | ||
~BuiltinSkiaImageGenerator(); | ||
|
||
BuiltinSkiaImageGenerator(std::unique_ptr<SkImageGenerator> generator); | ||
|
||
// |ImageGenerator| | ||
const SkImageInfo& GetInfo() const override; | ||
|
||
// |ImageGenerator| | ||
unsigned int GetFrameCount() const override; | ||
|
||
// |ImageGenerator| | ||
const ImageGenerator::FrameInfo GetFrameInfo( | ||
unsigned int frame_index) const override; | ||
|
||
// |ImageGenerator| | ||
SkISize GetScaledDimensions(float desired_scale) const 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) const 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(); | ||
|
||
BuiltinSkiaCodecImageGenerator(std::unique_ptr<SkCodec> codec); | ||
|
||
BuiltinSkiaCodecImageGenerator(sk_sp<SkData> buffer); | ||
|
||
// |ImageGenerator| | ||
const SkImageInfo& GetInfo() const override; | ||
|
||
// |ImageGenerator| | ||
unsigned int GetFrameCount() const override; | ||
|
||
// |ImageGenerator| | ||
const ImageGenerator::FrameInfo GetFrameInfo( | ||
unsigned int frame_index) const override; | ||
|
||
// |ImageGenerator| | ||
SkISize GetScaledDimensions(float desired_scale) const 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) const 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_ |
Oops, something went wrong.