Commit bb4d860b authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Add decodeMetadata() method to ImageDecoder.

Allows API users with ReadableStreams as input to know when they can
start using the metadata fields on the ImageDecoder.

R=sandersd

Bug: 1073995
Change-Id: I6d32fcf7e2dda5927e62cd370c50238cb96d5074
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2254455
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Auto-Submit: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#780531}
parent d29480f9
......@@ -23,23 +23,29 @@
Promise<ImageFrame> decode(optional unsigned long frameIndex = 0,
optional boolean completeFramesOnly = true);
// Decodes only the metadata for an image; resolves the promise when metadata
// can be decoded. Normally this is done automatically at construction time.
// However when using a ReadableStream, there may not be enough data to decode
// metadata at the time of construction.
Promise<void> decodeMetadata();
// The number of frames in the image.
//
// When decoding a ReadableStream the value will be 0 until enough data to
// decode the frame count has been received. If the format has no fixed count,
// the value will increase as frames are received by the decoder.
// decode metadata has been received. If the format has no fixed count, the
// value will increase as frames are received by the decoder.
readonly attribute unsigned long frameCount;
// The detected mime type for the decoded image.
//
// When decoding a ReadableStream the value will be an empty string until
// enough data to detect the mime type has been received.
// enough data to decode metadata has been received.
readonly attribute USVString type;
// The image's preferred repetition count.
//
// When decoding a ReadableStream the value will be 0 until enough data to
// decode the repetition count has been received.
// decode metadata has been received.
readonly attribute unsigned long repetitionCount;
// True if all available frames have been received by the decoder.
......
......@@ -88,23 +88,23 @@ ImageDecoderExternal::ImageDecoderExternal(ScriptState* script_state,
// TODO: Data is owned by the caller who may be free to manipulate it. We will
// probably need to make a copy to our own internal data or neuter the buffers
// as seen by JS.
auto sr = SegmentReader::CreateFromSkData(
segment_reader_ = SegmentReader::CreateFromSkData(
SkData::MakeWithoutCopy(buffer.Data(), buffer.ByteLengthAsSizeT()));
if (!sr) {
if (!segment_reader_) {
exception_state.ThrowDOMException(DOMExceptionCode::kConstraintError,
"Failed to read image data");
return;
}
data_complete_ = true;
MaybeCreateImageDecoder(std::move(sr));
MaybeCreateImageDecoder();
if (!decoder_) {
exception_state.ThrowDOMException(DOMExceptionCode::kConstraintError,
"Failed to create image decoder");
return;
}
UpdateFrameAndRepetitionCount();
MaybeUpdateMetadata();
if (decoder_->Failed()) {
exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
"Image decoding failed");
......@@ -128,6 +128,16 @@ ScriptPromise ImageDecoderExternal::decode(uint32_t frame_index,
return promise;
}
ScriptPromise ImageDecoderExternal::decodeMetadata() {
DVLOG(1) << __func__;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state_);
auto promise = resolver->Promise();
pending_metadata_decodes_.push_back(resolver);
MaybeSatisfyPendingMetadataDecodes();
return promise;
}
uint32_t ImageDecoderExternal::frameCount() const {
return frame_count_;
}
......@@ -165,11 +175,11 @@ void ImageDecoderExternal::OnStateChange() {
data_complete_ = result == BytesConsumer::Result::kDone;
if (!decoder_)
MaybeCreateImageDecoder(nullptr);
MaybeCreateImageDecoder();
else
decoder_->SetData(stream_buffer_, data_complete_);
UpdateFrameAndRepetitionCount();
MaybeUpdateMetadata();
MaybeSatisfyPendingDecodes();
}
}
......@@ -182,6 +192,7 @@ void ImageDecoderExternal::Trace(Visitor* visitor) const {
visitor->Trace(script_state_);
visitor->Trace(consumer_);
visitor->Trace(pending_decodes_);
visitor->Trace(pending_metadata_decodes_);
visitor->Trace(init_data_);
visitor->Trace(options_);
ScriptWrappable::Trace(visitor);
......@@ -268,8 +279,15 @@ void ImageDecoderExternal::MaybeSatisfyPendingDecodes() {
static_cast<wtf_size_t>(new_end - pending_decodes_.begin()));
}
void ImageDecoderExternal::MaybeCreateImageDecoder(
scoped_refptr<SegmentReader> sr) {
void ImageDecoderExternal::MaybeSatisfyPendingMetadataDecodes() {
DCHECK(decoder_);
DCHECK(decoder_->Failed() || frame_count_ > 0);
for (auto& resolver : pending_metadata_decodes_)
resolver->Resolve();
pending_metadata_decodes_.clear();
}
void ImageDecoderExternal::MaybeCreateImageDecoder() {
// TODO: This does not handle SVG Images since they use another "decoder." It
// is highly coupled with the DOM today, so isn't suitable for this API.
......@@ -298,7 +316,6 @@ void ImageDecoderExternal::MaybeCreateImageDecoder(
if (!ImageDecoder::HasSufficientDataToSniffImageType(*stream_buffer_))
return;
DCHECK(!sr);
decoder_ = ImageDecoder::Create(
stream_buffer_, data_complete_, premultiply_alpha,
ImageDecoder::kHighBitDepthToHalfFloat, color_behavior,
......@@ -308,18 +325,20 @@ void ImageDecoderExternal::MaybeCreateImageDecoder(
DCHECK(data_complete_);
decoder_ = ImageDecoder::Create(
std::move(sr), data_complete_, premultiply_alpha,
segment_reader_, data_complete_, premultiply_alpha,
ImageDecoder::kHighBitDepthToHalfFloat, color_behavior,
ImageDecoder::OverrideAllowDecodeToYuv::kDeny, desired_size);
}
void ImageDecoderExternal::UpdateFrameAndRepetitionCount() {
void ImageDecoderExternal::MaybeUpdateMetadata() {
if (!decoder_)
return;
const size_t decoded_frame_count = decoder_->FrameCount();
if (decoder_->Failed())
if (decoder_->Failed()) {
MaybeSatisfyPendingMetadataDecodes();
return;
}
// TODO: Is this useful? We should have each decoder indicate its own mime
// type then.
......@@ -332,6 +351,8 @@ void ImageDecoderExternal::UpdateFrameAndRepetitionCount() {
const int decoded_repetition_count = decoder_->RepetitionCount();
if (decoded_repetition_count > 0)
repetition_count_ = decoded_repetition_count;
MaybeSatisfyPendingMetadataDecodes();
}
} // namespace blink
......@@ -39,6 +39,7 @@ class MODULES_EXPORT ImageDecoderExternal final : public ScriptWrappable,
// image_decoder.idl implementation.
ScriptPromise decode(uint32_t frame_index, bool complete_frames_only);
ScriptPromise decodeMetadata();
uint32_t frameCount() const;
String type() const;
uint32_t repetitionCount() const;
......@@ -53,8 +54,9 @@ class MODULES_EXPORT ImageDecoderExternal final : public ScriptWrappable,
private:
void MaybeSatisfyPendingDecodes();
void MaybeCreateImageDecoder(scoped_refptr<SegmentReader> sr);
void UpdateFrameAndRepetitionCount();
void MaybeSatisfyPendingMetadataDecodes();
void MaybeCreateImageDecoder();
void MaybeUpdateMetadata();
Member<ScriptState> script_state_;
......@@ -62,6 +64,9 @@ class MODULES_EXPORT ImageDecoderExternal final : public ScriptWrappable,
Member<ReadableStreamBytesConsumer> consumer_;
scoped_refptr<SharedBuffer> stream_buffer_;
// Used when all data is provided at construction time.
scoped_refptr<SegmentReader> segment_reader_;
// Construction parameters.
Member<const ImageDecoderInit> init_data_;
Member<const ImageBitmapOptions> options_;
......@@ -86,6 +91,7 @@ class MODULES_EXPORT ImageDecoderExternal final : public ScriptWrappable,
bool complete = false;
};
HeapVector<Member<DecodeRequest>> pending_decodes_;
HeapVector<Member<ScriptPromiseResolver>> pending_metadata_decodes_;
// When decode() of incomplete frames has been requested, we need to track the
// generation id for each SkBitmap that we've handed out. So that we can defer
......
......@@ -7,5 +7,9 @@
typedef (ArrayBuffer or ArrayBufferView or ReadableStream) ImageBufferSource;
dictionary ImageDecoderInit {
required ImageBufferSource data;
// Options to use when creating ImageBitmap objects from decoded frames. The
// resize width and height are additionally used to facilitate reduced
// resolution decoding.
ImageBitmapOptions options;
};
......@@ -795,6 +795,7 @@ interface ImageDecoder
getter type
method constructor
method decode
method decodeMetadata
interface InstallEvent : ExtendableEvent
attribute @@toStringTag
method constructor
......
......@@ -738,6 +738,7 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] getter type
[Worker] method constructor
[Worker] method decode
[Worker] method decodeMetadata
[Worker] interface Lock
[Worker] attribute @@toStringTag
[Worker] getter mode
......
......@@ -4544,6 +4544,7 @@ interface ImageDecoder
getter type
method constructor
method decode
method decodeMetadata
interface Ink
attribute @@toStringTag
method constructor
......
......@@ -725,6 +725,7 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] getter type
[Worker] method constructor
[Worker] method decode
[Worker] method decodeMetadata
[Worker] interface Lock
[Worker] attribute @@toStringTag
[Worker] getter mode
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment