Commit 35433236 authored by Canon Mukai's avatar Canon Mukai Committed by Commit Bot

DecompressionStream: Accept BufferSource chunks

The previous version of DecompressionStream accepted only Uint8Array
as its input, so I added change to accept ArrayBuffer and
other ArrayBufferView like Int16Array.

I also added a test.

Bug: 999091
Change-Id: I8c153c3f639cb4e9b8563128e4cce1e6c6597cb4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1831920Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarAdam Rice <ricea@chromium.org>
Commit-Queue: Canon Mukai <canonmukai@google.com>
Cr-Commit-Position: refs/heads/master@{#703221}
parent 229c7fe3
......@@ -4,6 +4,7 @@
#include <algorithm>
#include <limits>
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_uint8_array.h"
#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_interface.h"
......@@ -11,7 +12,6 @@
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/to_v8.h"
#include "v8/include/v8.h"
namespace blink {
......@@ -44,43 +44,47 @@ void InflateTransformer::Transform(
v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
// TODO(canonmukai): Change to MaybeShared<DOMUint8Array>
// when we are ready to support SharedArrayBuffer.
NotShared<DOMUint8Array> chunk_data = ToNotShared<NotShared<DOMUint8Array>>(
script_state_->GetIsolate(), chunk, exception_state);
// TODO(canonmukai): Support SharedArrayBuffer.
ArrayBufferOrArrayBufferView buffer_source;
V8ArrayBufferOrArrayBufferView::ToImpl(
script_state_->GetIsolate(), chunk, buffer_source,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException()) {
return;
}
if (!chunk_data) {
exception_state.ThrowTypeError("chunk is not of type Uint8Array.");
if (buffer_source.IsArrayBufferView()) {
const auto* view = buffer_source.GetAsArrayBufferView().View();
const Bytef* start = static_cast<const Bytef*>(view->BaseAddress());
wtf_size_t length = view->byteLength();
Inflate(start, length, IsFinished(false), controller, exception_state);
return;
}
Inflate(chunk_data.View(), IsFinished(false), controller, exception_state);
DCHECK(buffer_source.IsArrayBuffer());
const auto* array_buffer = buffer_source.GetAsArrayBuffer();
const uint8_t* start = static_cast<const Bytef*>(array_buffer->Data());
wtf_size_t length = array_buffer->ByteLength();
Inflate(start, length, IsFinished(false), controller, exception_state);
}
void InflateTransformer::Flush(
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
DCHECK(!was_flush_called_);
Inflate(nullptr, IsFinished(true), controller, exception_state);
Inflate(nullptr, 0u, IsFinished(true), controller, exception_state);
inflateEnd(&stream_);
was_flush_called_ = true;
}
void InflateTransformer::Inflate(
const DOMUint8Array* data,
const Bytef* start,
wtf_size_t length,
IsFinished finished,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
unsigned int out_buffer_size = static_cast<unsigned int>(kBufferSize);
if (data) {
stream_.avail_in = data->length();
stream_.next_in = data->DataMaybeShared();
} else {
stream_.avail_in = 0;
stream_.next_in = nullptr;
}
stream_.avail_in = length;
// Zlib treats this pointer as const, so this cast is safe.
stream_.next_in = const_cast<Bytef*>(start);
do {
stream_.avail_out = out_buffer_size;
......
......@@ -31,7 +31,8 @@ class InflateTransformer final : public TransformStreamTransformer {
private:
using IsFinished = util::StrongAlias<class IsFinishedTag, bool>;
void Inflate(const DOMUint8Array* data,
void Inflate(const Bytef*,
wtf_size_t,
IsFinished,
TransformStreamDefaultControllerInterface*,
ExceptionState&);
......
// META: global=worker
'use strict';
const compressedBytesWithDeflate = [120, 156, 75, 52, 48, 52, 50, 54, 49, 53, 3, 0, 8, 136, 1, 199];
const compressedBytesWithGzip = [31, 139, 8, 0, 0, 0, 0, 0, 0, 3, 75, 52, 48, 52, 2, 0, 216, 252, 63, 136, 4, 0, 0, 0];
// Two chunk values below were chosen to make the length of the compressed
// output be a multiple of 8 bytes.
const deflateExpectedChunkValue = new TextEncoder().encode('a0123456');
const gzipExpectedChunkValue = new TextEncoder().encode('a012');
const bufferSourceChunksForDeflate = [
{
name: 'ArrayBuffer',
value: new Uint8Array(compressedBytesWithDeflate).buffer
},
{
name: 'Int8Array',
value: new Int8Array(new Uint8Array(compressedBytesWithDeflate).buffer)
},
{
name: 'Uint8Array',
value: new Uint8Array(new Uint8Array(compressedBytesWithDeflate).buffer)
},
{
name: 'Uint8ClampedArray',
value: new Uint8ClampedArray(new Uint8Array(compressedBytesWithDeflate).buffer)
},
{
name: 'Int16Array',
value: new Int16Array(new Uint8Array(compressedBytesWithDeflate).buffer)
},
{
name: 'Uint16Array',
value: new Uint16Array(new Uint8Array(compressedBytesWithDeflate).buffer)
},
{
name: 'Int32Array',
value: new Int32Array(new Uint8Array(compressedBytesWithDeflate).buffer)
},
{
name: 'Uint32Array',
value: new Uint32Array(new Uint8Array(compressedBytesWithDeflate).buffer)
},
{
name: 'Float32Array',
value: new Float32Array(new Uint8Array(compressedBytesWithDeflate).buffer)
},
{
name: 'Float64Array',
value: new Float64Array(new Uint8Array(compressedBytesWithDeflate).buffer)
},
{
name: 'DataView',
value: new DataView(new Uint8Array(compressedBytesWithDeflate).buffer)
},
];
const bufferSourceChunksForGzip = [
{
name: 'ArrayBuffer',
value: new Uint8Array(compressedBytesWithGzip).buffer
},
{
name: 'Int8Array',
value: new Int8Array(new Uint8Array(compressedBytesWithGzip).buffer)
},
{
name: 'Uint8Array',
value: new Uint8Array(new Uint8Array(compressedBytesWithGzip).buffer)
},
{
name: 'Uint8ClambedArray',
value: new Uint8ClampedArray(new Uint8Array(compressedBytesWithGzip).buffer)
},
{
name: 'Int16Array',
value: new Int16Array(new Uint8Array(compressedBytesWithGzip).buffer)
},
{
name: 'Uint16Array',
value: new Uint16Array(new Uint8Array(compressedBytesWithGzip).buffer)
},
{
name: 'Int32Array',
value: new Int32Array(new Uint8Array(compressedBytesWithGzip).buffer)
},
{
name: 'Uint32Array',
value: new Uint32Array(new Uint8Array(compressedBytesWithGzip).buffer)
},
{
name: 'Float32Array',
value: new Float32Array(new Uint8Array(compressedBytesWithGzip).buffer)
},
{
name: 'Float64Array',
value: new Float64Array(new Uint8Array(compressedBytesWithGzip).buffer)
},
{
name: 'DataView',
value: new DataView(new Uint8Array(compressedBytesWithGzip).buffer)
},
];
for (const chunk of bufferSourceChunksForDeflate) {
promise_test(async t => {
const ds = new DecompressionStream('deflate');
const reader = ds.readable.getReader();
const writer = ds.writable.getWriter();
const writePromise = writer.write(chunk.value);
writer.close();
const { value } = await reader.read();
assert_array_equals(Array.from(value), deflateExpectedChunkValue, 'value should match');
}, `chunk of type ${chunk.name} should work for deflate`);
}
for (const chunk of bufferSourceChunksForGzip) {
promise_test(async t => {
const ds = new DecompressionStream('gzip');
const reader = ds.readable.getReader();
const writer = ds.writable.getWriter();
const writePromise = writer.write(chunk.value);
writer.close();
const { value } = await reader.read();
assert_array_equals(Array.from(value), gzipExpectedChunkValue, 'value should match');
}, `chunk of type ${chunk.name} should work for gzip`);
}
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