Commit 18def511 authored by Adam Rice's avatar Adam Rice Committed by Commit Bot

Return ScriptPromise from TransformStreamTransformer

Previously the Transform() and Flush() methods of
TransformStreamTransformer returned void. This meant that there was no
way for them to wait for asynchronous work to finish.

Change the function signatures to return ScriptPromise. Transform() or
Flush() won't be called again until the returned promise is settled.

Returning v8::Local<v8::Promise> would have been slightly more
efficient, but ScriptPromise was used for consistency with
UnderlyingSinkBase and UnderlyingSourceBase.

Add tests that Transform() and Flush() promises are actually waited for.

BUG=962837

Change-Id: I2e79c6a79a457fd021eee17eca4f1502c3aa521f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1865735Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709861}
parent 9d5550ff
......@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/streams/transform_stream_native.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
......@@ -66,11 +67,12 @@ class TransformStreamNative::FlushAlgorithm final : public StreamAlgorithm {
ExceptionState exception_state(script_state->GetIsolate(),
ExceptionState::kUnknownContext, "", "");
ControllerInterface controller_interface(script_state, controller_);
ScriptPromise promise;
{
// This is needed because the realm of the transformer can be different
// from the realm of the transform stream.
ScriptState::Scope scope(transformer_->GetScriptState());
transformer_->Flush(&controller_interface, exception_state);
promise = transformer_->Flush(&controller_interface, exception_state);
}
if (exception_state.HadException()) {
auto exception = exception_state.GetException();
......@@ -78,7 +80,7 @@ class TransformStreamNative::FlushAlgorithm final : public StreamAlgorithm {
return PromiseReject(script_state, exception);
}
return PromiseResolveWithUndefined(script_state);
return promise.V8Value().As<v8::Promise>();
}
// SetController() must be called before Run() is.
......@@ -112,11 +114,13 @@ class TransformStreamNative::TransformAlgorithm final : public StreamAlgorithm {
ExceptionState exception_state(script_state->GetIsolate(),
ExceptionState::kUnknownContext, "", "");
ControllerInterface controller_interface(script_state, controller_);
ScriptPromise promise;
{
// This is needed because the realm of the transformer can be different
// from the realm of the transform stream.
ScriptState::Scope scope(transformer_->GetScriptState());
transformer_->Transform(argv[0], &controller_interface, exception_state);
promise = transformer_->Transform(argv[0], &controller_interface,
exception_state);
}
if (exception_state.HadException()) {
auto exception = exception_state.GetException();
......@@ -124,7 +128,7 @@ class TransformStreamNative::TransformAlgorithm final : public StreamAlgorithm {
return PromiseReject(script_state, exception);
}
return PromiseResolveWithUndefined(script_state);
return promise.V8Value().As<v8::Promise>();
}
// SetController() must be called before Run() is.
......
......@@ -7,6 +7,8 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
......@@ -29,8 +31,11 @@
namespace blink {
namespace {
using ::testing::_;
using ::testing::ByMove;
using ::testing::Mock;
using ::testing::Return;
class TransformStreamTest : public ::testing::Test {
public:
......@@ -68,19 +73,33 @@ class TransformStreamTest : public ::testing::Test {
Persistent<TransformStream> stream_;
};
class IdentityTransformer final : public TransformStreamTransformer {
// A convenient base class to make tests shorter. Subclasses need not implement
// both Transform() and Flush(), and can override the void versions to avoid the
// need to create a promise to return. Not appropriate for use in production.
class TestTransformer : public TransformStreamTransformer {
public:
explicit IdentityTransformer(ScriptState* script_state)
explicit TestTransformer(ScriptState* script_state)
: script_state_(script_state) {}
void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
controller->Enqueue(chunk, exception_state);
virtual void TransformVoid(v8::Local<v8::Value>,
TransformStreamDefaultControllerInterface*,
ExceptionState&) {}
ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
TransformVoid(chunk, controller, exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
void Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {}
virtual void FlushVoid(TransformStreamDefaultControllerInterface*,
ExceptionState&) {}
ScriptPromise Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
FlushVoid(controller, exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
ScriptState* GetScriptState() override { return script_state_; }
......@@ -93,18 +112,30 @@ class IdentityTransformer final : public TransformStreamTransformer {
const Member<ScriptState> script_state_;
};
class IdentityTransformer final : public TestTransformer {
public:
explicit IdentityTransformer(ScriptState* script_state)
: TestTransformer(script_state) {}
void TransformVoid(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
controller->Enqueue(chunk, exception_state);
}
};
class MockTransformStreamTransformer : public TransformStreamTransformer {
public:
explicit MockTransformStreamTransformer(ScriptState* script_state)
: script_state_(script_state) {}
MOCK_METHOD3(Transform,
void(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&));
ScriptPromise(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&));
MOCK_METHOD2(Flush,
void(TransformStreamDefaultControllerInterface*,
ExceptionState&));
ScriptPromise(TransformStreamDefaultControllerInterface*,
ExceptionState&));
ScriptState* GetScriptState() override { return script_state_; }
......@@ -144,7 +175,9 @@ TEST_F(TransformStreamTest, TransformIsCalled) {
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
CopyReadableAndWritableToGlobal(scope);
EXPECT_CALL(*mock, Transform(_, _, _));
EXPECT_CALL(*mock, Transform(_, _, _))
.WillOnce(
Return(ByMove(ScriptPromise::CastUndefined(scope.GetScriptState()))));
// The initial read is needed to relieve backpressure.
EvalWithPrintingError(&scope,
......@@ -165,7 +198,9 @@ TEST_F(TransformStreamTest, FlushIsCalled) {
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
CopyReadableAndWritableToGlobal(scope);
EXPECT_CALL(*mock, Flush(_, _));
EXPECT_CALL(*mock, Flush(_, _))
.WillOnce(
Return(ByMove(ScriptPromise::CastUndefined(scope.GetScriptState()))));
EvalWithPrintingError(&scope,
"const writer = writable.getWriter();\n"
......@@ -237,27 +272,17 @@ TEST_F(TransformStreamTest, EnqueueFromTransform) {
}
TEST_F(TransformStreamTest, EnqueueFromFlush) {
class EnqueueFromFlushTransformer : public TransformStreamTransformer {
class EnqueueFromFlushTransformer final : public TestTransformer {
public:
explicit EnqueueFromFlushTransformer(ScriptState* script_state)
: script_state_(script_state) {}
void Transform(v8::Local<v8::Value>,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override {}
void Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
controller->Enqueue(ToV8("a", script_state_), exception_state);
}
ScriptState* GetScriptState() override { return script_state_; }
void Trace(Visitor* visitor) override {
visitor->Trace(script_state_);
TransformStreamTransformer::Trace(visitor);
}
: TestTransformer(script_state) {}
private:
const Member<ScriptState> script_state_;
void FlushVoid(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
controller->Enqueue(ToV8("a", GetScriptState()), exception_state);
}
};
V8TestingScope scope;
auto* script_state = scope.GetScriptState();
Init(MakeGarbageCollected<EnqueueFromFlushTransformer>(script_state),
......@@ -280,27 +305,18 @@ TEST_F(TransformStreamTest, EnqueueFromFlush) {
TEST_F(TransformStreamTest, ThrowFromTransform) {
static constexpr char kMessage[] = "errorInTransform";
class ThrowFromTransformTransformer : public TransformStreamTransformer {
class ThrowFromTransformTransformer final : public TestTransformer {
public:
explicit ThrowFromTransformTransformer(ScriptState* script_state)
: script_state_(script_state) {}
void Transform(v8::Local<v8::Value>,
TransformStreamDefaultControllerInterface*,
ExceptionState& exception_state) override {
exception_state.ThrowTypeError(kMessage);
}
void Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override {}
: TestTransformer(script_state) {}
ScriptState* GetScriptState() override { return script_state_; }
void Trace(Visitor* visitor) override {
visitor->Trace(script_state_);
TransformStreamTransformer::Trace(visitor);
void TransformVoid(v8::Local<v8::Value>,
TransformStreamDefaultControllerInterface*,
ExceptionState& exception_state) override {
exception_state.ThrowTypeError(kMessage);
}
private:
const Member<ScriptState> script_state_;
};
V8TestingScope scope;
auto* script_state = scope.GetScriptState();
Init(MakeGarbageCollected<ThrowFromTransformTransformer>(
......@@ -331,25 +347,15 @@ TEST_F(TransformStreamTest, ThrowFromTransform) {
TEST_F(TransformStreamTest, ThrowFromFlush) {
static constexpr char kMessage[] = "errorInFlush";
class ThrowFromFlushTransformer : public TransformStreamTransformer {
class ThrowFromFlushTransformer final : public TestTransformer {
public:
explicit ThrowFromFlushTransformer(ScriptState* script_state)
: script_state_(script_state) {}
void Transform(v8::Local<v8::Value>,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override {}
void Flush(TransformStreamDefaultControllerInterface*,
ExceptionState& exception_state) override {
: TestTransformer(script_state) {}
void FlushVoid(TransformStreamDefaultControllerInterface*,
ExceptionState& exception_state) override {
exception_state.ThrowTypeError(kMessage);
}
ScriptState* GetScriptState() override { return script_state_; }
void Trace(Visitor* visitor) override {
visitor->Trace(script_state_);
TransformStreamTransformer::Trace(visitor);
}
private:
const Member<ScriptState> script_state_;
};
V8TestingScope scope;
auto* script_state = scope.GetScriptState();
......@@ -389,5 +395,126 @@ TEST_F(TransformStreamTest, CreateFromReadableWritablePair) {
EXPECT_EQ(writable, transform.Writable());
}
TEST_F(TransformStreamTest, WaitInTransform) {
class WaitInTransformTransformer final : public TestTransformer {
public:
explicit WaitInTransformTransformer(ScriptState* script_state)
: TestTransformer(script_state),
transform_promise_resolver_(
MakeGarbageCollected<ScriptPromiseResolver>(script_state)) {}
ScriptPromise Transform(v8::Local<v8::Value>,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override {
return transform_promise_resolver_->Promise();
}
void FlushVoid(TransformStreamDefaultControllerInterface*,
ExceptionState&) override {
flush_called_ = true;
}
void ResolvePromise() { transform_promise_resolver_->Resolve(); }
bool FlushCalled() const { return flush_called_; }
void Trace(Visitor* visitor) override {
visitor->Trace(transform_promise_resolver_);
TestTransformer::Trace(visitor);
}
private:
const Member<ScriptPromiseResolver> transform_promise_resolver_;
bool flush_called_ = false;
};
V8TestingScope scope;
auto* script_state = scope.GetScriptState();
auto* transformer =
MakeGarbageCollected<WaitInTransformTransformer>(script_state);
Init(transformer, script_state, ASSERT_NO_EXCEPTION);
CopyReadableAndWritableToGlobal(scope);
ScriptValue promise =
EvalWithPrintingError(&scope,
"const writer = writable.getWriter();\n"
"const promise = writer.write('a');\n"
"writer.close();\n"
"promise;\n");
// Need to read to relieve backpressure.
Stream()
->Readable()
->GetReadHandle(script_state, ASSERT_NO_EXCEPTION)
->Read(script_state);
ScriptPromiseTester write_tester(script_state,
ScriptPromise::Cast(script_state, promise));
// Give Transform() the opportunity to be called.
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
EXPECT_FALSE(write_tester.IsFulfilled());
EXPECT_FALSE(transformer->FlushCalled());
transformer->ResolvePromise();
write_tester.WaitUntilSettled();
EXPECT_TRUE(write_tester.IsFulfilled());
EXPECT_TRUE(transformer->FlushCalled());
}
TEST_F(TransformStreamTest, WaitInFlush) {
class WaitInFlushTransformer final : public TestTransformer {
public:
explicit WaitInFlushTransformer(ScriptState* script_state)
: TestTransformer(script_state),
flush_promise_resolver_(
MakeGarbageCollected<ScriptPromiseResolver>(script_state)) {}
ScriptPromise Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override {
return flush_promise_resolver_->Promise();
}
void ResolvePromise() { flush_promise_resolver_->Resolve(); }
void Trace(Visitor* visitor) override {
visitor->Trace(flush_promise_resolver_);
TestTransformer::Trace(visitor);
}
private:
const Member<ScriptPromiseResolver> flush_promise_resolver_;
};
V8TestingScope scope;
auto* script_state = scope.GetScriptState();
auto* transformer =
MakeGarbageCollected<WaitInFlushTransformer>(script_state);
Init(transformer, script_state, ASSERT_NO_EXCEPTION);
CopyReadableAndWritableToGlobal(scope);
ScriptValue promise =
EvalWithPrintingError(&scope,
"const writer = writable.getWriter();\n"
"writer.close();\n");
// Need to read to relieve backpressure.
Stream()
->Readable()
->GetReadHandle(script_state, ASSERT_NO_EXCEPTION)
->Read(script_state);
ScriptPromiseTester close_tester(script_state,
ScriptPromise::Cast(script_state, promise));
// Give Flush() the opportunity to be called.
v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate());
EXPECT_FALSE(close_tester.IsFulfilled());
transformer->ResolvePromise();
close_tester.WaitUntilSettled();
EXPECT_TRUE(close_tester.IsFulfilled());
}
} // namespace
} // namespace blink
......@@ -14,6 +14,7 @@
namespace blink {
class ExceptionState;
class ScriptPromise;
class ScriptState;
class TransformStreamDefaultControllerInterface;
class Visitor;
......@@ -33,11 +34,11 @@ class CORE_EXPORT TransformStreamTransformer
TransformStreamTransformer() = default;
virtual ~TransformStreamTransformer() = default;
virtual void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) = 0;
virtual void Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) = 0;
virtual ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) = 0;
virtual ScriptPromise Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) = 0;
// Returns the ScriptState associated with this Transformer.
virtual ScriptState* GetScriptState() = 0;
......
......@@ -9,6 +9,7 @@
#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/script_promise.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"
......@@ -50,7 +51,7 @@ DeflateTransformer::~DeflateTransformer() {
}
}
void DeflateTransformer::Transform(
ScriptPromise DeflateTransformer::Transform(
v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
......@@ -59,29 +60,33 @@ void DeflateTransformer::Transform(
script_state_->GetIsolate(), chunk, buffer_source,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException()) {
return;
return ScriptPromise();
}
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;
return ScriptPromise::CastUndefined(script_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);
return ScriptPromise::CastUndefined(script_state_);
}
void DeflateTransformer::Flush(
ScriptPromise DeflateTransformer::Flush(
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
Deflate(nullptr, 0u, IsFinished(true), controller, exception_state);
was_flush_called_ = true;
deflateEnd(&stream_);
out_buffer_.clear();
return ScriptPromise::CastUndefined(script_state_);
}
void DeflateTransformer::Deflate(
......
......@@ -21,12 +21,12 @@ class DeflateTransformer final : public TransformStreamTransformer {
DeflateTransformer(ScriptState*, Format, int level);
~DeflateTransformer() override;
void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
void Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptPromise Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptState* GetScriptState() override { return script_state_; }
......
......@@ -5,6 +5,7 @@
#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/script_promise.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"
......@@ -41,7 +42,7 @@ InflateTransformer::~InflateTransformer() {
}
}
void InflateTransformer::Transform(
ScriptPromise InflateTransformer::Transform(
v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
......@@ -51,23 +52,25 @@ void InflateTransformer::Transform(
script_state_->GetIsolate(), chunk, buffer_source,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException()) {
return;
return ScriptPromise();
}
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();
Inflate(start, length, IsFinished(false), controller, exception_state);
return;
return ScriptPromise::CastUndefined(script_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();
Inflate(start, length, IsFinished(false), controller, exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
void InflateTransformer::Flush(
ScriptPromise InflateTransformer::Flush(
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
DCHECK(!was_flush_called_);
......@@ -75,6 +78,8 @@ void InflateTransformer::Flush(
inflateEnd(&stream_);
was_flush_called_ = true;
out_buffer_.clear();
return ScriptPromise::CastUndefined(script_state_);
}
void InflateTransformer::Inflate(
......
......@@ -17,12 +17,12 @@ class InflateTransformer final : public TransformStreamTransformer {
InflateTransformer(ScriptState*, Format format);
~InflateTransformer() override;
void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
void Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptPromise Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptState* GetScriptState() override { return script_state_; }
......
......@@ -8,6 +8,7 @@
#include <utility>
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_interface.h"
#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
......@@ -38,15 +39,15 @@ class TextDecoderStream::Transformer final : public TransformStreamTransformer {
// Implements the type conversion part of the "decode and enqueue a chunk"
// algorithm.
void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ArrayBufferOrArrayBufferView bufferSource;
V8ArrayBufferOrArrayBufferView::ToImpl(
script_state_->GetIsolate(), chunk, bufferSource,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException())
return;
return ScriptPromise();
// This implements the "get a copy of the bytes held by the buffer source"
// algorithm (https://heycam.github.io/webidl/#dfn-get-buffer-source-copy).
......@@ -56,7 +57,7 @@ class TextDecoderStream::Transformer final : public TransformStreamTransformer {
uint32_t length = view->byteLength();
DecodeAndEnqueue(start, length, WTF::FlushBehavior::kDoNotFlush,
controller, exception_state);
return;
return ScriptPromise::CastUndefined(script_state_);
}
DCHECK(bufferSource.IsArrayBuffer());
const auto* array_buffer = bufferSource.GetAsArrayBuffer();
......@@ -64,13 +65,17 @@ class TextDecoderStream::Transformer final : public TransformStreamTransformer {
uint32_t length = array_buffer->ByteLength();
DecodeAndEnqueue(start, length, WTF::FlushBehavior::kDoNotFlush, controller,
exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
// Implements the "encode and flush" algorithm.
void Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ScriptPromise Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
DecodeAndEnqueue(nullptr, 0u, WTF::FlushBehavior::kDataEOF, controller,
exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
ScriptState* GetScriptState() override { return script_state_; }
......
......@@ -12,6 +12,7 @@
#include "base/optional.h"
#include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_string_resource.h"
#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_interface.h"
#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
......@@ -34,15 +35,15 @@ class TextEncoderStream::Transformer final : public TransformStreamTransformer {
// Implements the "encode and enqueue a chunk" algorithm. For efficiency, only
// the characters at the end of chunks are special-cased.
void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
V8StringResource<> input_resource = chunk;
if (!input_resource.Prepare(script_state_->GetIsolate(), exception_state))
return;
return ScriptPromise();
const String input = input_resource;
if (input.IsEmpty())
return;
return ScriptPromise::CastUndefined(script_state_);
const base::Optional<UChar> high_surrogate = pending_high_surrogate_;
pending_high_surrogate_ = base::nullopt;
......@@ -60,19 +61,21 @@ class TextEncoderStream::Transformer final : public TransformStreamTransformer {
bool have_output =
Encode16BitString(input, high_surrogate, &prefix, &result);
if (!have_output)
return;
return ScriptPromise::CastUndefined(script_state_);
}
DOMUint8Array* array =
CreateDOMUint8ArrayFromTwoStdStringsConcatenated(prefix, result);
controller->Enqueue(ToV8(array, script_state_), exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
// Implements the "encode and flush" algorithm.
void Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ScriptPromise Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
if (!pending_high_surrogate_.has_value())
return;
return ScriptPromise::CastUndefined(script_state_);
const std::string replacement_character = ReplacementCharacterInUtf8();
const uint8_t* u8buffer =
......@@ -82,6 +85,8 @@ class TextEncoderStream::Transformer final : public TransformStreamTransformer {
replacement_character.length())),
script_state_),
exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
ScriptState* GetScriptState() override { return script_state_; }
......
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