Commit 42bda3eb authored by Canon Mukai's avatar Canon Mukai Committed by Commit Bot

Align CompressionStream and DecompressionStream

There were some differences between CompressionStream and
DecompressionStream. So I aligned them.
Also, I made CompressionStream accept BufferSource.

Bug: 999091
Change-Id: Iaf6c3e54804a10ef22d05c5f4da0d5ae07d0e765
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1847605
Commit-Queue: Canon Mukai <canonmukai@google.com>
Reviewed-by: default avatarAdam Rice <ricea@chromium.org>
Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Cr-Commit-Position: refs/heads/master@{#704610}
parent f4d4c687
......@@ -16,8 +16,6 @@ CompressionStream* CompressionStream::Create(ScriptState* script_state,
exception_state);
}
CompressionStream::~CompressionStream() = default;
ReadableStream* CompressionStream::readable() const {
return transform_->Readable();
}
......@@ -35,12 +33,11 @@ CompressionStream::CompressionStream(ScriptState* script_state,
const AtomicString& format,
ExceptionState& exception_state)
: transform_(MakeGarbageCollected<TransformStream>()) {
DeflateTransformer::Format deflate_format;
DeflateTransformer::Format deflate_format =
DeflateTransformer::Format::kDeflate;
if (format == "gzip") {
deflate_format = DeflateTransformer::Format::Gzip;
} else if (format == "deflate") {
deflate_format = DeflateTransformer::Format::Deflate;
} else {
deflate_format = DeflateTransformer::Format::kGzip;
} else if (format != "deflate") {
exception_state.ThrowTypeError("Unsupported format");
return;
}
......
......@@ -19,7 +19,6 @@ class CompressionStream final : public ScriptWrappable {
const AtomicString&,
ExceptionState&);
CompressionStream(ScriptState*, const AtomicString&, ExceptionState&);
~CompressionStream() override;
ReadableStream* readable() const;
WritableStream* writable() const;
......
......@@ -29,17 +29,17 @@ DecompressionStream::DecompressionStream(ScriptState* script_state,
const AtomicString& format,
ExceptionState& exception_state)
: transform_(MakeGarbageCollected<TransformStream>()) {
InflateTransformer::Algorithm algorithm =
InflateTransformer::Algorithm::kDeflate;
InflateTransformer::Format deflate_format =
InflateTransformer::Format::kDeflate;
if (format == "gzip") {
algorithm = InflateTransformer::Algorithm::kGzip;
deflate_format = InflateTransformer::Format::kGzip;
} else if (format != "deflate") {
exception_state.ThrowTypeError("Unsupported format");
return;
}
transform_->Init(
MakeGarbageCollected<InflateTransformer>(script_state, algorithm),
MakeGarbageCollected<InflateTransformer>(script_state, deflate_format),
script_state, exception_state);
}
......
......@@ -8,6 +8,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"
......@@ -15,7 +16,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 {
......@@ -23,23 +23,27 @@ namespace blink {
DeflateTransformer::DeflateTransformer(ScriptState* script_state,
Format format,
int level)
: script_state_(script_state),
// TODO(arenevier): same as PODArena default chunk size. Is that
// reasonable? Or should we use a variable size buffer?
buffer_(16384) {
: script_state_(script_state), out_buffer_(kBufferSize) {
DCHECK(level >= 1 && level <= 9);
int window_bits = 15;
if (format == Format::Gzip) {
window_bits += 16;
}
memset(&stream_, 0, sizeof(z_stream));
int err = deflateInit2(&stream_, level, Z_DEFLATED, window_bits, 8,
constexpr int kWindowBits = 15;
constexpr int kUseGzip = 16;
int err;
switch (format) {
case Format::kDeflate:
err = deflateInit2(&stream_, level, Z_DEFLATED, kWindowBits, 8,
Z_DEFAULT_STRATEGY);
break;
case Format::kGzip:
err = deflateInit2(&stream_, level, Z_DEFLATED, kWindowBits + kUseGzip, 8,
Z_DEFAULT_STRATEGY);
break;
}
DCHECK_EQ(Z_OK, err);
}
DeflateTransformer::~DeflateTransformer() {
if (!is_stream_freed_) {
if (!was_flush_called_) {
deflateEnd(&stream_);
}
}
......@@ -48,54 +52,56 @@ void DeflateTransformer::Transform(
v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
NotShared<DOMUint8Array> chunk_data = ToNotShared<NotShared<DOMUint8Array>>(
script_state_->GetIsolate(), chunk, exception_state);
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 uint8_t* start = static_cast<const uint8_t*>(view->BaseAddress());
wtf_size_t length = view->byteLength();
Deflate(start, length, IsFinished(false), controller, exception_state);
return;
}
if (chunk_data.View()->length() == 0) {
return;
}
Deflate(chunk_data.View(), false, controller, exception_state);
DCHECK(buffer_source.IsArrayBuffer());
const auto* array_buffer = buffer_source.GetAsArrayBuffer();
const uint8_t* start = static_cast<const uint8_t*>(array_buffer->Data());
wtf_size_t length = array_buffer->ByteLength();
Deflate(start, length, IsFinished(false), controller, exception_state);
}
void DeflateTransformer::Flush(
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
Deflate(nullptr, true, controller, exception_state);
is_stream_freed_ = true;
Deflate(nullptr, 0u, IsFinished(true), controller, exception_state);
was_flush_called_ = true;
deflateEnd(&stream_);
}
void DeflateTransformer::Deflate(
const DOMUint8Array* data,
bool finished,
const uint8_t* start,
wtf_size_t length,
IsFinished finished,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
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<uint8_t*>(start);
do {
stream_.avail_out = buffer_.size();
stream_.next_out = buffer_.data();
stream_.avail_out = out_buffer_.size();
stream_.next_out = out_buffer_.data();
int err = deflate(&stream_, finished ? Z_FINISH : Z_NO_FLUSH);
DCHECK((finished && err == Z_STREAM_END) || (err == Z_OK));
DCHECK((finished && err == Z_STREAM_END) || err == Z_OK ||
err == Z_BUF_ERROR);
wtf_size_t bytes = buffer_.size() - stream_.avail_out;
wtf_size_t bytes = out_buffer_.size() - stream_.avail_out;
if (bytes) {
controller->Enqueue(
ToV8(DOMUint8Array::Create(buffer_.data(), bytes), script_state_),
ToV8(DOMUint8Array::Create(out_buffer_.data(), bytes), script_state_),
exception_state);
if (exception_state.HadException()) {
return;
......
......@@ -5,17 +5,18 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_COMPRESSION_DEFLATE_TRANSFORMER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_COMPRESSION_DEFLATE_TRANSFORMER_H_
#include "base/util/type_safety/strong_alias.h"
#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/zlib/zlib.h"
namespace blink {
class DeflateTransformer final : public TransformStreamTransformer {
public:
enum class Format { Gzip, Deflate };
enum class Format { kGzip, kDeflate };
DeflateTransformer(ScriptState*, Format, int level);
~DeflateTransformer() override;
......@@ -32,18 +33,24 @@ class DeflateTransformer final : public TransformStreamTransformer {
void Trace(Visitor*) override;
private:
void Deflate(const DOMUint8Array* data,
bool finished,
using IsFinished = util::StrongAlias<class IsFinishedTag, bool>;
void Deflate(const uint8_t*,
wtf_size_t,
IsFinished,
TransformStreamDefaultControllerInterface*,
ExceptionState&);
Member<ScriptState> script_state_;
Vector<uint8_t> buffer_;
Vector<uint8_t> out_buffer_;
z_stream stream_;
bool is_stream_freed_ = false;
bool was_flush_called_ = false;
// This buffer size has been experimentally verified to be optimal.
static constexpr wtf_size_t kBufferSize = 16384;
DISALLOW_COPY_AND_ASSIGN(DeflateTransformer);
};
......
......@@ -16,18 +16,17 @@
namespace blink {
InflateTransformer::InflateTransformer(ScriptState* script_state,
Algorithm algorithm)
InflateTransformer::InflateTransformer(ScriptState* script_state, Format format)
: script_state_(script_state), out_buffer_(kBufferSize) {
memset(&stream_, 0, sizeof(z_stream));
int err;
constexpr int kWindowBits = 15;
constexpr int kUseGzip = 16;
switch (algorithm) {
case Algorithm::kDeflate:
int err;
switch (format) {
case Format::kDeflate:
err = inflateInit2(&stream_, kWindowBits);
break;
case Algorithm::kGzip:
case Format::kGzip:
err = inflateInit2(&stream_, kWindowBits + kUseGzip);
break;
}
......@@ -54,14 +53,14 @@ void InflateTransformer::Transform(
}
if (buffer_source.IsArrayBufferView()) {
const auto* view = buffer_source.GetAsArrayBufferView().View();
const Bytef* start = static_cast<const Bytef*>(view->BaseAddress());
const uint8_t* start = static_cast<const uint8_t*>(view->BaseAddress());
wtf_size_t length = view->byteLength();
Inflate(start, length, IsFinished(false), controller, exception_state);
return;
}
DCHECK(buffer_source.IsArrayBuffer());
const auto* array_buffer = buffer_source.GetAsArrayBuffer();
const uint8_t* start = static_cast<const Bytef*>(array_buffer->Data());
const uint8_t* start = static_cast<const uint8_t*>(array_buffer->Data());
wtf_size_t length = array_buffer->ByteLength();
Inflate(start, length, IsFinished(false), controller, exception_state);
}
......@@ -76,18 +75,17 @@ void InflateTransformer::Flush(
}
void InflateTransformer::Inflate(
const Bytef* start,
const uint8_t* start,
wtf_size_t length,
IsFinished finished,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
unsigned int out_buffer_size = static_cast<unsigned int>(kBufferSize);
stream_.avail_in = length;
// Zlib treats this pointer as const, so this cast is safe.
stream_.next_in = const_cast<Bytef*>(start);
stream_.next_in = const_cast<uint8_t*>(start);
do {
stream_.avail_out = out_buffer_size;
stream_.avail_out = out_buffer_.size();
stream_.next_out = out_buffer_.data();
int err = inflate(&stream_, finished ? Z_FINISH : Z_NO_FLUSH);
if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) {
......@@ -95,7 +93,7 @@ void InflateTransformer::Inflate(
return;
}
wtf_size_t bytes = out_buffer_size - stream_.avail_out;
wtf_size_t bytes = out_buffer_.size() - stream_.avail_out;
if (bytes) {
controller->Enqueue(
ToV8(DOMUint8Array::Create(out_buffer_.data(), bytes), script_state_),
......
......@@ -12,9 +12,9 @@ namespace blink {
class InflateTransformer final : public TransformStreamTransformer {
public:
enum class Algorithm { kDeflate, kGzip };
enum class Format { kDeflate, kGzip };
InflateTransformer(ScriptState*, Algorithm algorithm);
InflateTransformer(ScriptState*, Format format);
~InflateTransformer() override;
void Transform(v8::Local<v8::Value> chunk,
......@@ -31,7 +31,7 @@ class InflateTransformer final : public TransformStreamTransformer {
private:
using IsFinished = util::StrongAlias<class IsFinishedTag, bool>;
void Inflate(const Bytef*,
void Inflate(const uint8_t*,
wtf_size_t,
IsFinished,
TransformStreamDefaultControllerInterface*,
......@@ -41,10 +41,11 @@ class InflateTransformer final : public TransformStreamTransformer {
z_stream stream_;
Vector<Bytef> out_buffer_;
Vector<uint8_t> out_buffer_;
bool was_flush_called_ = false;
// This buffer size has been experimentally verified to be optimal.
static constexpr wtf_size_t kBufferSize = 65536;
DISALLOW_COPY_AND_ASSIGN(InflateTransformer);
......
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