blob: 3f15e396440df7c4dedc408e77f6ae907d7c4c10 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/webcodecs/array_buffer_util.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
namespace blink {
ArrayBufferContents PinArrayBufferContent(
const AllowSharedBufferSource* buffer_union) {
ArrayBufferContents result;
switch (buffer_union->GetContentType()) {
case AllowSharedBufferSource::ContentType::kArrayBufferAllowShared: {
auto* buffer = buffer_union->GetAsArrayBufferAllowShared();
if (buffer && !buffer->IsDetached()) {
if (buffer->IsShared()) {
buffer->Content()->ShareWith(result);
} else {
static_cast<blink::DOMArrayBuffer*>(buffer)
->ShareNonSharedForInternalUse(result);
}
}
return result;
}
case AllowSharedBufferSource::ContentType::kArrayBufferViewAllowShared: {
auto* view = buffer_union->GetAsArrayBufferViewAllowShared().Get();
if (view && !view->IsDetached()) {
if (view->IsShared()) {
view->BufferShared()->Content()->ShareWith(result);
} else {
view->buffer()->ShareNonSharedForInternalUse(result);
}
}
return result;
}
}
}
ArrayBufferContents TransferArrayBufferForSpan(
const HeapVector<Member<DOMArrayBuffer>>& transfer_list,
base::span<const uint8_t> data_range,
ExceptionState& exception_state,
v8::Isolate* isolate) {
// Before transferring anything, we check that all the arraybuffers in the
// list are transferable and there are no duplicates.
WTF::HashSet<Member<DOMArrayBuffer>> seen_buffers;
for (const Member<DOMArrayBuffer>& array_buffer : transfer_list) {
if (!array_buffer) {
continue;
}
if (!array_buffer->IsDetachable(isolate) || array_buffer->IsDetached()) {
exception_state.ThrowDOMException(DOMExceptionCode::kDataCloneError,
"Cannot detach ArrayBuffer");
return {};
}
if (!seen_buffers.insert(array_buffer).is_new_entry) {
// While inserting we found that the buffer has already been seen.
exception_state.ThrowDOMException(
DOMExceptionCode::kDataCloneError,
"Duplicate ArrayBuffers in the transfer list");
return {};
}
}
// Transfer all arraybuffers and check if any of them encompass given
// `data_range`.
ArrayBufferContents result;
for (const Member<DOMArrayBuffer>& array_buffer : transfer_list) {
if (!array_buffer) {
continue;
}
ArrayBufferContents contents;
if (!array_buffer->Transfer(isolate, contents, exception_state) ||
!contents.IsValid()) {
if (exception_state.HadException()) {
return {};
}
continue;
}
auto* contents_data = static_cast<const uint8_t*>(contents.Data());
if (data_range.data() < contents_data ||
data_range.data() + data_range.size() >
contents_data + contents.DataLength()) {
// This array buffer doesn't contain `data_range`. Let's ignore it.
continue;
}
if (!result.IsValid()) {
// We haven't found a matching arraybuffer yet, and this one meets
// all the criteria. It is our result.
contents.Transfer(result);
}
}
return result;
}
} // namespace blink