summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc')
-rw-r--r--chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc170
1 files changed, 97 insertions, 73 deletions
diff --git a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
index cc082117cf4..e42ceaf3703 100644
--- a/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
+++ b/chromium/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/time/time.h"
+#include "third_party/blink/public/common/mime_util/mime_util.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_decoder_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_frame.h"
@@ -41,10 +42,16 @@ ImageDecoderExternal::DecodeRequest::DecodeRequest(
frame_index(frame_index),
complete_frames_only(complete_frames_only) {}
-void ImageDecoderExternal::DecodeRequest::Trace(Visitor* visitor) {
+void ImageDecoderExternal::DecodeRequest::Trace(Visitor* visitor) const {
visitor->Trace(resolver);
}
+// static
+bool ImageDecoderExternal::canDecodeType(String type) {
+ return type.ContainsOnlyASCIIOrEmpty() &&
+ IsSupportedImageMimeType(type.Ascii());
+}
+
ImageDecoderExternal::ImageDecoderExternal(ScriptState* script_state,
const ImageDecoderInit* init,
ExceptionState& exception_state)
@@ -56,6 +63,13 @@ ImageDecoderExternal::ImageDecoderExternal(ScriptState* script_state,
options_ =
init->hasOptions() ? init->options() : ImageBitmapOptions::Create();
+ mime_type_ = init->type();
+ if (!canDecodeType(mime_type_)) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
+ "Unsupported image format.");
+ return;
+ }
+
if (init->data().IsReadableStream()) {
consumer_ = MakeGarbageCollected<ReadableStreamBytesConsumer>(
script_state, init->data().GetAsReadableStream(), exception_state);
@@ -63,11 +77,11 @@ ImageDecoderExternal::ImageDecoderExternal(ScriptState* script_state,
return;
stream_buffer_ = WTF::SharedBuffer::Create();
- consumer_->SetClient(this);
+ CreateImageDecoder();
- // We can't create the ImageDecoder until we have some data, so we may be
- // done for now; we need one initial call to OnStateChange(), but thereafter
- // calls will be driven by the ReadableStreamBytesConsumer.
+ // We need one initial call to OnStateChange() to start reading, but
+ // thereafter calls will be driven by the ReadableStreamBytesConsumer.
+ consumer_->SetClient(this);
OnStateChange();
return;
}
@@ -88,23 +102,18 @@ 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));
- if (!decoder_) {
- exception_state.ThrowDOMException(DOMExceptionCode::kConstraintError,
- "Failed to create image decoder");
- return;
- }
- UpdateFrameAndRepetitionCount();
+ CreateImageDecoder();
+ MaybeUpdateMetadata();
if (decoder_->Failed()) {
exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
"Image decoding failed");
@@ -128,6 +137,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_;
}
@@ -164,12 +183,9 @@ void ImageDecoderExternal::OnStateChange() {
}
data_complete_ = result == BytesConsumer::Result::kDone;
- if (!decoder_)
- MaybeCreateImageDecoder(nullptr);
- else
- decoder_->SetData(stream_buffer_, data_complete_);
+ decoder_->SetData(stream_buffer_, data_complete_);
- UpdateFrameAndRepetitionCount();
+ MaybeUpdateMetadata();
MaybeSatisfyPendingDecodes();
}
}
@@ -178,24 +194,65 @@ String ImageDecoderExternal::DebugName() const {
return "ImageDecoderExternal";
}
-void ImageDecoderExternal::Trace(Visitor* visitor) {
+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);
}
+void ImageDecoderExternal::CreateImageDecoder() {
+ DCHECK(!decoder_);
+
+ // TODO: We should probably call ImageDecoder::SetMemoryAllocator() so that
+ // we can recycle frame buffers for decoded images.
+
+ constexpr char kNoneOption[] = "none";
+
+ auto color_behavior = ColorBehavior::Tag();
+ if (options_->colorSpaceConversion() == kNoneOption)
+ color_behavior = ColorBehavior::Ignore();
+
+ auto premultiply_alpha = ImageDecoder::kAlphaPremultiplied;
+ if (options_->premultiplyAlpha() == kNoneOption)
+ premultiply_alpha = ImageDecoder::kAlphaNotPremultiplied;
+
+ // TODO: Is it okay to use resize size like this?
+ auto desired_size = SkISize::MakeEmpty();
+ if (options_->hasResizeWidth() && options_->hasResizeHeight()) {
+ desired_size =
+ SkISize::Make(options_->resizeWidth(), options_->resizeHeight());
+ }
+
+ if (stream_buffer_) {
+ if (!segment_reader_)
+ segment_reader_ = SegmentReader::CreateFromSharedBuffer(stream_buffer_);
+ } else {
+ DCHECK(data_complete_);
+ }
+
+ DCHECK(canDecodeType(mime_type_));
+ decoder_ = ImageDecoder::CreateByMimeType(
+ mime_type_, segment_reader_, data_complete_, premultiply_alpha,
+ ImageDecoder::kHighBitDepthToHalfFloat, color_behavior,
+ ImageDecoder::OverrideAllowDecodeToYuv::kDeny, desired_size);
+
+ // CreateByImageType() can't fail if we use a supported image type. Which we
+ // DCHECK above via canDecodeType().
+ DCHECK(decoder_);
+}
+
void ImageDecoderExternal::MaybeSatisfyPendingDecodes() {
+ DCHECK(decoder_);
for (auto& request : pending_decodes_) {
if (!data_complete_) {
// We can't fulfill this promise at this time.
if (request->frame_index >= frame_count_)
continue;
-
- DCHECK(decoder_);
- } else if (!decoder_ || request->frame_index >= frame_count_) {
+ } else if (request->frame_index >= frame_count_) {
request->complete = true;
// TODO: Include frameIndex in rejection?
request->resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -268,62 +325,27 @@ void ImageDecoderExternal::MaybeSatisfyPendingDecodes() {
static_cast<wtf_size_t>(new_end - pending_decodes_.begin()));
}
-void ImageDecoderExternal::MaybeCreateImageDecoder(
- scoped_refptr<SegmentReader> sr) {
- // 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.
-
- // TODO: We should probably call ImageDecoder::SetMemoryAllocator() so that
- // we can recycle frame buffers for decoded images.
-
- constexpr char kNoneOption[] = "none";
-
- auto color_behavior = ColorBehavior::Tag();
- if (options_->colorSpaceConversion() == kNoneOption)
- color_behavior = ColorBehavior::Ignore();
-
- auto premultiply_alpha = ImageDecoder::kAlphaPremultiplied;
- if (options_->premultiplyAlpha() == kNoneOption)
- premultiply_alpha = ImageDecoder::kAlphaNotPremultiplied;
-
- // TODO: Is it okay to use resize size like this?
- auto desired_size = SkISize::MakeEmpty();
- if (options_->hasResizeWidth() && options_->hasResizeHeight()) {
- desired_size =
- SkISize::Make(options_->resizeWidth(), options_->resizeHeight());
- }
-
- if (stream_buffer_) {
- // TODO: If mime-type is supplied we must use that instead of sniffing.
- if (!ImageDecoder::HasSufficientDataToSniffImageType(*stream_buffer_))
- return;
-
- DCHECK(!sr);
- decoder_ = ImageDecoder::Create(
- stream_buffer_, data_complete_, premultiply_alpha,
- ImageDecoder::kHighBitDepthToHalfFloat, color_behavior,
- ImageDecoder::OverrideAllowDecodeToYuv::kDeny, desired_size);
- return;
- }
-
- DCHECK(data_complete_);
- decoder_ = ImageDecoder::Create(
- std::move(sr), data_complete_, premultiply_alpha,
- ImageDecoder::kHighBitDepthToHalfFloat, color_behavior,
- ImageDecoder::OverrideAllowDecodeToYuv::kDeny, desired_size);
+void ImageDecoderExternal::MaybeSatisfyPendingMetadataDecodes() {
+ DCHECK(decoder_);
+ DCHECK(decoder_->Failed() || decoder_->IsDecodedSizeAvailable());
+ for (auto& resolver : pending_metadata_decodes_)
+ resolver->Resolve();
+ pending_metadata_decodes_.clear();
}
-void ImageDecoderExternal::UpdateFrameAndRepetitionCount() {
- if (!decoder_)
+void ImageDecoderExternal::MaybeUpdateMetadata() {
+ const size_t decoded_frame_count = decoder_->FrameCount();
+ if (decoder_->Failed()) {
+ MaybeSatisfyPendingMetadataDecodes();
return;
+ }
- const size_t decoded_frame_count = decoder_->FrameCount();
- if (decoder_->Failed())
+ // Since we always create the decoder at construction, we need to wait until
+ // at least the size is available before signaling that metadata has been
+ // retrieved.
+ if (!decoder_->IsSizeAvailable())
return;
- // TODO: Is this useful? We should have each decoder indicate its own mime
- // type then.
- mime_type_ = "image/todo";
frame_count_ = static_cast<uint32_t>(decoded_frame_count);
// The internal value has some magic negative numbers; for external purposes
@@ -332,6 +354,8 @@ void ImageDecoderExternal::UpdateFrameAndRepetitionCount() {
const int decoded_repetition_count = decoder_->RepetitionCount();
if (decoded_repetition_count > 0)
repetition_count_ = decoded_repetition_count;
+
+ MaybeSatisfyPendingMetadataDecodes();
}
} // namespace blink