| Index: third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
|
| diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
|
| deleted file mode 100644
|
| index 2108dc97e330a09d20a8bb1df313cfe24980a3ac..0000000000000000000000000000000000000000
|
| --- a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
|
| +++ /dev/null
|
| @@ -1,2631 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "bindings/core/v8/ScriptValueSerializer.h"
|
| -
|
| -#include "bindings/core/v8/Transferables.h"
|
| -#include "bindings/core/v8/V8ArrayBuffer.h"
|
| -#include "bindings/core/v8/V8ArrayBufferView.h"
|
| -#include "bindings/core/v8/V8Blob.h"
|
| -#include "bindings/core/v8/V8CompositorProxy.h"
|
| -#include "bindings/core/v8/V8File.h"
|
| -#include "bindings/core/v8/V8FileList.h"
|
| -#include "bindings/core/v8/V8ImageBitmap.h"
|
| -#include "bindings/core/v8/V8ImageData.h"
|
| -#include "bindings/core/v8/V8MessagePort.h"
|
| -#include "bindings/core/v8/V8OffscreenCanvas.h"
|
| -#include "bindings/core/v8/V8SharedArrayBuffer.h"
|
| -#include "core/dom/CompositorProxy.h"
|
| -#include "core/dom/DOMDataView.h"
|
| -#include "core/dom/DOMSharedArrayBuffer.h"
|
| -#include "core/dom/DOMTypedArray.h"
|
| -#include "core/fileapi/Blob.h"
|
| -#include "core/fileapi/File.h"
|
| -#include "core/fileapi/FileList.h"
|
| -#include "platform/RuntimeEnabledFeatures.h"
|
| -#include "public/platform/Platform.h"
|
| -#include "public/platform/WebBlobInfo.h"
|
| -#include "wtf/DateMath.h"
|
| -#include "wtf/text/StringHash.h"
|
| -#include "wtf/text/StringUTF8Adaptor.h"
|
| -#include <memory>
|
| -
|
| -// FIXME: consider crashing in debug mode on deserialization errors
|
| -// NOTE: be sure to change wireFormatVersion as necessary!
|
| -
|
| -namespace blink {
|
| -
|
| -namespace {
|
| -
|
| -// This code implements the HTML5 Structured Clone algorithm:
|
| -// http://www.whatwg.org/specs/web-apps/current-work/multipage/urls.html#safe-passing-of-structured-data
|
| -
|
| -// ZigZag encoding helps VarInt encoding stay small for negative
|
| -// numbers with small absolute values.
|
| -class ZigZag {
|
| - public:
|
| - static uint32_t encode(uint32_t value) {
|
| - if (value & (1U << 31))
|
| - value = ((~value) << 1) + 1;
|
| - else
|
| - value <<= 1;
|
| - return value;
|
| - }
|
| -
|
| - static uint32_t decode(uint32_t value) {
|
| - if (value & 1)
|
| - value = ~(value >> 1);
|
| - else
|
| - value >>= 1;
|
| - return value;
|
| - }
|
| -
|
| - private:
|
| - ZigZag();
|
| -};
|
| -
|
| -const int maxDepth = 20000;
|
| -
|
| -bool shouldCheckForCycles(int depth) {
|
| - ASSERT(depth >= 0);
|
| - // Since we are not required to spot the cycle as soon as it
|
| - // happens we can check for cycles only when the current depth
|
| - // is a power of two.
|
| - return !(depth & (depth - 1));
|
| -}
|
| -
|
| -// Returns true if the provided object is to be considered a 'host object', as
|
| -// used in the HTML5 structured clone algorithm.
|
| -bool isHostObject(v8::Local<v8::Object> object) {
|
| - // If the object has any internal fields, then we won't be able to serialize
|
| - // or deserialize them; conveniently, this is also a quick way to detect DOM
|
| - // wrapper objects, because the mechanism for these relies on data stored in
|
| - // these fields. We should catch external array data as a special case.
|
| - return object->InternalFieldCount();
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -void SerializedScriptValueWriter::writeUndefined() {
|
| - append(UndefinedTag);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeNull() {
|
| - append(NullTag);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeTrue() {
|
| - append(TrueTag);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeFalse() {
|
| - append(FalseTag);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeBooleanObject(bool value) {
|
| - append(value ? TrueObjectTag : FalseObjectTag);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeRawStringBytes(
|
| - v8::Local<v8::String>& string) {
|
| - int rawLength = string->Length();
|
| - string->WriteOneByte(byteAt(m_position), 0, rawLength,
|
| - v8StringWriteOptions());
|
| - m_position += rawLength;
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeUtf8String(
|
| - v8::Local<v8::String>& string) {
|
| - int utf8Length = string->Utf8Length();
|
| - char* buffer = reinterpret_cast<char*>(byteAt(m_position));
|
| - string->WriteUtf8(buffer, utf8Length, 0, v8StringWriteOptions());
|
| - m_position += utf8Length;
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeOneByteString(
|
| - v8::Local<v8::String>& string) {
|
| - int stringLength = string->Length();
|
| - int utf8Length = string->Utf8Length();
|
| - ASSERT(stringLength >= 0 && utf8Length >= 0);
|
| -
|
| - append(StringTag);
|
| - doWriteUint32(static_cast<uint32_t>(utf8Length));
|
| - ensureSpace(utf8Length);
|
| -
|
| - // ASCII fast path.
|
| - if (stringLength == utf8Length) {
|
| - writeRawStringBytes(string);
|
| - } else {
|
| - writeUtf8String(string);
|
| - }
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeUCharString(
|
| - v8::Local<v8::String>& string) {
|
| - int length = string->Length();
|
| - ASSERT(length >= 0);
|
| -
|
| - int size = length * sizeof(UChar);
|
| - int bytes = bytesNeededToWireEncode(static_cast<uint32_t>(size));
|
| - if ((m_position + 1 + bytes) & 1)
|
| - append(PaddingTag);
|
| -
|
| - append(StringUCharTag);
|
| - doWriteUint32(static_cast<uint32_t>(size));
|
| - ensureSpace(size);
|
| -
|
| - ASSERT(!(m_position & 1));
|
| - uint16_t* buffer = reinterpret_cast<uint16_t*>(byteAt(m_position));
|
| - string->Write(buffer, 0, length, v8StringWriteOptions());
|
| - m_position += size;
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeStringObject(const char* data,
|
| - int length) {
|
| - ASSERT(length >= 0);
|
| - append(StringObjectTag);
|
| - doWriteString(data, length);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeWebCoreString(const String& string) {
|
| - // Uses UTF8 encoding so we can read it back as either V8 or
|
| - // WebCore string.
|
| - append(StringTag);
|
| - doWriteWebCoreString(string);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeVersion() {
|
| - append(VersionTag);
|
| - doWriteUint32(SerializedScriptValue::wireFormatVersion);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeInt32(int32_t value) {
|
| - append(Int32Tag);
|
| - doWriteUint32(ZigZag::encode(static_cast<uint32_t>(value)));
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeUint32(uint32_t value) {
|
| - append(Uint32Tag);
|
| - doWriteUint32(value);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeDate(double numberValue) {
|
| - append(DateTag);
|
| - doWriteNumber(numberValue);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeNumber(double number) {
|
| - append(NumberTag);
|
| - doWriteNumber(number);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeNumberObject(double number) {
|
| - append(NumberObjectTag);
|
| - doWriteNumber(number);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeBlob(const String& uuid,
|
| - const String& type,
|
| - unsigned long long size) {
|
| - append(BlobTag);
|
| - doWriteWebCoreString(uuid);
|
| - doWriteWebCoreString(type);
|
| - doWriteUint64(size);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeBlobIndex(int blobIndex) {
|
| - ASSERT(blobIndex >= 0);
|
| - append(BlobIndexTag);
|
| - doWriteUint32(blobIndex);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeCompositorProxy(
|
| - const CompositorProxy& compositorProxy) {
|
| - append(CompositorProxyTag);
|
| - doWriteUint64(compositorProxy.elementId());
|
| - doWriteUint32(compositorProxy.compositorMutableProperties());
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeFile(const File& file) {
|
| - append(FileTag);
|
| - doWriteFile(file);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeFileIndex(int blobIndex) {
|
| - append(FileIndexTag);
|
| - doWriteUint32(blobIndex);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeFileList(const FileList& fileList) {
|
| - append(FileListTag);
|
| - uint32_t length = fileList.length();
|
| - doWriteUint32(length);
|
| - for (unsigned i = 0; i < length; ++i)
|
| - doWriteFile(*fileList.item(i));
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeFileListIndex(
|
| - const Vector<int>& blobIndices) {
|
| - append(FileListIndexTag);
|
| - uint32_t length = blobIndices.size();
|
| - doWriteUint32(length);
|
| - for (unsigned i = 0; i < length; ++i)
|
| - doWriteUint32(blobIndices[i]);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeArrayBuffer(
|
| - const DOMArrayBuffer& arrayBuffer) {
|
| - append(ArrayBufferTag);
|
| - doWriteArrayBuffer(arrayBuffer);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeArrayBufferView(
|
| - const DOMArrayBufferView& arrayBufferView) {
|
| - append(ArrayBufferViewTag);
|
| -#if DCHECK_IS_ON()
|
| - ASSERT(static_cast<const uint8_t*>(arrayBufferView.bufferBase()->data()) +
|
| - arrayBufferView.byteOffset() ==
|
| - static_cast<const uint8_t*>(arrayBufferView.baseAddress()));
|
| -#endif
|
| - DOMArrayBufferView::ViewType type = arrayBufferView.type();
|
| -
|
| - switch (type) {
|
| - case DOMArrayBufferView::TypeInt8:
|
| - append(ByteArrayTag);
|
| - break;
|
| - case DOMArrayBufferView::TypeUint8Clamped:
|
| - append(UnsignedByteClampedArrayTag);
|
| - break;
|
| - case DOMArrayBufferView::TypeUint8:
|
| - append(UnsignedByteArrayTag);
|
| - break;
|
| - case DOMArrayBufferView::TypeInt16:
|
| - append(ShortArrayTag);
|
| - break;
|
| - case DOMArrayBufferView::TypeUint16:
|
| - append(UnsignedShortArrayTag);
|
| - break;
|
| - case DOMArrayBufferView::TypeInt32:
|
| - append(IntArrayTag);
|
| - break;
|
| - case DOMArrayBufferView::TypeUint32:
|
| - append(UnsignedIntArrayTag);
|
| - break;
|
| - case DOMArrayBufferView::TypeFloat32:
|
| - append(FloatArrayTag);
|
| - break;
|
| - case DOMArrayBufferView::TypeFloat64:
|
| - append(DoubleArrayTag);
|
| - break;
|
| - case DOMArrayBufferView::TypeDataView:
|
| - append(DataViewTag);
|
| - break;
|
| - default:
|
| - ASSERT_NOT_REACHED();
|
| - }
|
| - doWriteUint32(arrayBufferView.byteOffset());
|
| - doWriteUint32(arrayBufferView.byteLength());
|
| -}
|
| -
|
| -// Helper function shared by writeImageData and writeImageBitmap
|
| -void SerializedScriptValueWriter::doWriteImageData(uint32_t width,
|
| - uint32_t height,
|
| - const uint8_t* pixelData,
|
| - uint32_t pixelDataLength) {
|
| - doWriteUint32(width);
|
| - doWriteUint32(height);
|
| - doWriteUint32(pixelDataLength);
|
| - append(pixelData, pixelDataLength);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeImageData(uint32_t width,
|
| - uint32_t height,
|
| - const uint8_t* pixelData,
|
| - uint32_t pixelDataLength) {
|
| - append(ImageDataTag);
|
| - doWriteImageData(width, height, pixelData, pixelDataLength);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeImageBitmap(uint32_t width,
|
| - uint32_t height,
|
| - uint32_t isOriginClean,
|
| - uint32_t isPremultiplied,
|
| - const uint8_t* pixelData,
|
| - uint32_t pixelDataLength) {
|
| - append(ImageBitmapTag);
|
| - append(isOriginClean);
|
| - append(isPremultiplied);
|
| - doWriteImageData(width, height, pixelData, pixelDataLength);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeRegExp(v8::Local<v8::String> pattern,
|
| - v8::RegExp::Flags flags) {
|
| - append(RegExpTag);
|
| - v8::String::Utf8Value patternUtf8Value(pattern);
|
| - doWriteString(*patternUtf8Value, patternUtf8Value.length());
|
| - doWriteUint32(static_cast<uint32_t>(flags));
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeTransferredMessagePort(uint32_t index) {
|
| - append(MessagePortTag);
|
| - doWriteUint32(index);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeTransferredArrayBuffer(uint32_t index) {
|
| - append(ArrayBufferTransferTag);
|
| - doWriteUint32(index);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeTransferredImageBitmap(uint32_t index) {
|
| - append(ImageBitmapTransferTag);
|
| - doWriteUint32(index);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeTransferredOffscreenCanvas(
|
| - uint32_t width,
|
| - uint32_t height,
|
| - uint32_t canvasId,
|
| - uint32_t clientId,
|
| - uint32_t sinkId) {
|
| - append(OffscreenCanvasTransferTag);
|
| - doWriteUint32(width);
|
| - doWriteUint32(height);
|
| - doWriteUint32(canvasId);
|
| - doWriteUint32(clientId);
|
| - doWriteUint32(sinkId);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeTransferredSharedArrayBuffer(
|
| - uint32_t index) {
|
| - ASSERT(RuntimeEnabledFeatures::sharedArrayBufferEnabled());
|
| - append(SharedArrayBufferTransferTag);
|
| - doWriteUint32(index);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeObjectReference(uint32_t reference) {
|
| - append(ObjectReferenceTag);
|
| - doWriteUint32(reference);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeObject(uint32_t numProperties) {
|
| - append(ObjectTag);
|
| - doWriteUint32(numProperties);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeSparseArray(uint32_t numProperties,
|
| - uint32_t length) {
|
| - append(SparseArrayTag);
|
| - doWriteUint32(numProperties);
|
| - doWriteUint32(length);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeDenseArray(uint32_t numProperties,
|
| - uint32_t length) {
|
| - append(DenseArrayTag);
|
| - doWriteUint32(numProperties);
|
| - doWriteUint32(length);
|
| -}
|
| -
|
| -String SerializedScriptValueWriter::takeWireString() {
|
| - static_assert(sizeof(BufferValueType) == 2,
|
| - "BufferValueType should be 2 bytes");
|
| - fillHole();
|
| - ASSERT((m_position + 1) / sizeof(BufferValueType) <= m_buffer.size());
|
| - return String(m_buffer.data(), (m_position + 1) / sizeof(BufferValueType));
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeReferenceCount(
|
| - uint32_t numberOfReferences) {
|
| - append(ReferenceCountTag);
|
| - doWriteUint32(numberOfReferences);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeGenerateFreshObject() {
|
| - append(GenerateFreshObjectTag);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeGenerateFreshSparseArray(
|
| - uint32_t length) {
|
| - append(GenerateFreshSparseArrayTag);
|
| - doWriteUint32(length);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeGenerateFreshDenseArray(
|
| - uint32_t length) {
|
| - append(GenerateFreshDenseArrayTag);
|
| - doWriteUint32(length);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeGenerateFreshMap() {
|
| - append(GenerateFreshMapTag);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeGenerateFreshSet() {
|
| - append(GenerateFreshSetTag);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeMap(uint32_t length) {
|
| - append(MapTag);
|
| - doWriteUint32(length);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::writeSet(uint32_t length) {
|
| - append(SetTag);
|
| - doWriteUint32(length);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::doWriteFile(const File& file) {
|
| - doWriteWebCoreString(file.hasBackingFile() ? file.path() : "");
|
| - doWriteWebCoreString(file.name());
|
| - doWriteWebCoreString(file.webkitRelativePath());
|
| - doWriteWebCoreString(file.uuid());
|
| - doWriteWebCoreString(file.type());
|
| -
|
| - // FIXME don't use 1 byte to encode a flag.
|
| - if (file.hasValidSnapshotMetadata()) {
|
| - doWriteUint32(static_cast<uint8_t>(1));
|
| -
|
| - long long size;
|
| - double lastModifiedMS;
|
| - file.captureSnapshot(size, lastModifiedMS);
|
| - doWriteUint64(static_cast<uint64_t>(size));
|
| - doWriteNumber(lastModifiedMS);
|
| - } else {
|
| - doWriteUint32(static_cast<uint8_t>(0));
|
| - }
|
| -
|
| - doWriteUint32(static_cast<uint8_t>(
|
| - (file.getUserVisibility() == File::IsUserVisible) ? 1 : 0));
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::doWriteArrayBuffer(
|
| - const DOMArrayBuffer& arrayBuffer) {
|
| - uint32_t byteLength = arrayBuffer.byteLength();
|
| - doWriteUint32(byteLength);
|
| - append(static_cast<const uint8_t*>(arrayBuffer.data()), byteLength);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::doWriteString(const char* data, int length) {
|
| - doWriteUint32(static_cast<uint32_t>(length));
|
| - append(reinterpret_cast<const uint8_t*>(data), length);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::doWriteWebCoreString(const String& string) {
|
| - StringUTF8Adaptor stringUTF8(string);
|
| - doWriteString(stringUTF8.data(), stringUTF8.length());
|
| -}
|
| -
|
| -int SerializedScriptValueWriter::bytesNeededToWireEncode(uint32_t value) {
|
| - int bytes = 1;
|
| - while (true) {
|
| - value >>= SerializedScriptValue::varIntShift;
|
| - if (!value)
|
| - break;
|
| - ++bytes;
|
| - }
|
| -
|
| - return bytes;
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::doWriteUint32(uint32_t value) {
|
| - doWriteUintHelper(value);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::doWriteUint64(uint64_t value) {
|
| - doWriteUintHelper(value);
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::doWriteNumber(double number) {
|
| - append(reinterpret_cast<uint8_t*>(&number), sizeof(number));
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::append(SerializationTag tag) {
|
| - append(static_cast<uint8_t>(tag));
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::append(uint8_t b) {
|
| - ensureSpace(1);
|
| - *byteAt(m_position++) = b;
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::append(const uint8_t* data, int length) {
|
| - ensureSpace(length);
|
| - memcpy(byteAt(m_position), data, length);
|
| - m_position += length;
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::ensureSpace(unsigned extra) {
|
| - static_assert(sizeof(BufferValueType) == 2,
|
| - "BufferValueType should be 2 bytes");
|
| - m_buffer.resize((m_position + extra + 1) /
|
| - sizeof(BufferValueType)); // "+ 1" to round up.
|
| -}
|
| -
|
| -void SerializedScriptValueWriter::fillHole() {
|
| - static_assert(sizeof(BufferValueType) == 2,
|
| - "BufferValueType should be 2 bytes");
|
| - // If the writer is at odd position in the buffer, then one of
|
| - // the bytes in the last UChar is not initialized.
|
| - if (m_position % 2)
|
| - *byteAt(m_position) = static_cast<uint8_t>(PaddingTag);
|
| -}
|
| -
|
| -uint8_t* SerializedScriptValueWriter::byteAt(int position) {
|
| - return reinterpret_cast<uint8_t*>(m_buffer.data()) + position;
|
| -}
|
| -
|
| -int SerializedScriptValueWriter::v8StringWriteOptions() {
|
| - return v8::String::NO_NULL_TERMINATION;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::AbstractObjectState::serializeProperties(
|
| - ScriptValueSerializer& serializer) {
|
| - while (m_index < m_propertyNames->Length()) {
|
| - v8::Local<v8::Value> propertyName;
|
| - if (!m_propertyNames->Get(serializer.context(), m_index)
|
| - .ToLocal(&propertyName))
|
| - return serializer.handleError(
|
| - Status::JSException,
|
| - "Failed to get a property while cloning an object.", this);
|
| -
|
| - bool hasProperty = false;
|
| - if (propertyName->IsString()) {
|
| - hasProperty = v8CallBoolean(composite()->HasRealNamedProperty(
|
| - serializer.context(), propertyName.As<v8::String>()));
|
| - } else if (propertyName->IsUint32()) {
|
| - hasProperty = v8CallBoolean(composite()->HasRealIndexedProperty(
|
| - serializer.context(), propertyName.As<v8::Uint32>()->Value()));
|
| - }
|
| - if (StateBase* newState = serializer.checkException(this))
|
| - return newState;
|
| - if (!hasProperty) {
|
| - ++m_index;
|
| - continue;
|
| - }
|
| -
|
| - // |propertyName| is v8::String or v8::Uint32, so its serialization cannot
|
| - // be recursive.
|
| - serializer.doSerialize(propertyName, nullptr);
|
| -
|
| - v8::Local<v8::Value> value;
|
| - if (!composite()->Get(serializer.context(), propertyName).ToLocal(&value))
|
| - return serializer.handleError(
|
| - Status::JSException,
|
| - "Failed to get a property while cloning an object.", this);
|
| - ++m_index;
|
| - ++m_numSerializedProperties;
|
| - // If we return early here, it's either because we have pushed a new state
|
| - // onto the serialization state stack or because we have encountered an
|
| - // error (and in both cases we are unwinding the native stack).
|
| - if (StateBase* newState = serializer.doSerialize(value, this))
|
| - return newState;
|
| - }
|
| - return objectDone(m_numSerializedProperties, serializer);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::ObjectState::advance(
|
| - ScriptValueSerializer& serializer) {
|
| - if (m_propertyNames.IsEmpty()) {
|
| - if (!composite()
|
| - ->GetOwnPropertyNames(serializer.context())
|
| - .ToLocal(&m_propertyNames))
|
| - return serializer.checkException(this);
|
| - }
|
| - return serializeProperties(serializer);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::ObjectState::objectDone(
|
| - unsigned numProperties,
|
| - ScriptValueSerializer& serializer) {
|
| - return serializer.writeObject(numProperties, this);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::DenseArrayState::advance(
|
| - ScriptValueSerializer& serializer) {
|
| - while (m_arrayIndex < m_arrayLength) {
|
| - v8::Local<v8::Value> value;
|
| - if (!composite()
|
| - .As<v8::Array>()
|
| - ->Get(serializer.context(), m_arrayIndex)
|
| - .ToLocal(&value))
|
| - return serializer.handleError(
|
| - Status::JSException,
|
| - "Failed to get an element while cloning an array.", this);
|
| - m_arrayIndex++;
|
| - if (StateBase* newState = serializer.checkException(this))
|
| - return newState;
|
| - if (StateBase* newState = serializer.doSerialize(value, this))
|
| - return newState;
|
| - }
|
| - return serializeProperties(serializer);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::DenseArrayState::objectDone(
|
| - unsigned numProperties,
|
| - ScriptValueSerializer& serializer) {
|
| - return serializer.writeDenseArray(numProperties, m_arrayLength, this);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::SparseArrayState::advance(
|
| - ScriptValueSerializer& serializer) {
|
| - return serializeProperties(serializer);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::SparseArrayState::objectDone(
|
| - unsigned numProperties,
|
| - ScriptValueSerializer& serializer) {
|
| - return serializer.writeSparseArray(
|
| - numProperties, composite().As<v8::Array>()->Length(), this);
|
| -}
|
| -
|
| -template <typename T>
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::CollectionState<T>::advance(
|
| - ScriptValueSerializer& serializer) {
|
| - while (m_index < m_length) {
|
| - v8::Local<v8::Value> value;
|
| - if (!m_entries->Get(serializer.context(), m_index).ToLocal(&value))
|
| - return serializer.handleError(
|
| - Status::JSException,
|
| - "Failed to get an element while cloning a collection.", this);
|
| - m_index++;
|
| - if (StateBase* newState = serializer.checkException(this))
|
| - return newState;
|
| - if (StateBase* newState = serializer.doSerialize(value, this))
|
| - return newState;
|
| - }
|
| - return serializer.writeCollection<T>(m_length, this);
|
| -}
|
| -
|
| -ScriptValueSerializer::ScriptValueSerializer(
|
| - SerializedScriptValueWriter& writer,
|
| - WebBlobInfoArray* blobInfo,
|
| - ScriptState* scriptState)
|
| - : m_scriptState(scriptState),
|
| - m_writer(writer),
|
| - m_tryCatch(scriptState->isolate()),
|
| - m_depth(0),
|
| - m_status(Status::Success),
|
| - m_nextObjectReference(0),
|
| - m_blobInfo(blobInfo),
|
| - m_blobDataHandles(nullptr) {
|
| - DCHECK(!m_tryCatch.HasCaught());
|
| -}
|
| -
|
| -void ScriptValueSerializer::copyTransferables(
|
| - const Transferables& transferables) {
|
| - v8::Local<v8::Object> creationContext = m_scriptState->context()->Global();
|
| -
|
| - // Also kept in separate ObjectPools, iterate and copy the contents
|
| - // of each kind of transferable vector.
|
| -
|
| - const auto& messagePorts = transferables.messagePorts;
|
| - for (size_t i = 0; i < messagePorts.size(); ++i) {
|
| - v8::Local<v8::Object> v8MessagePort =
|
| - ToV8(messagePorts[i].get(), creationContext, isolate())
|
| - .As<v8::Object>();
|
| - m_transferredMessagePorts.set(v8MessagePort, i);
|
| - }
|
| -
|
| - const auto& arrayBuffers = transferables.arrayBuffers;
|
| - for (size_t i = 0; i < arrayBuffers.size(); ++i) {
|
| - v8::Local<v8::Object> v8ArrayBuffer =
|
| - ToV8(arrayBuffers[i].get(), creationContext, isolate())
|
| - .As<v8::Object>();
|
| - // Coalesce multiple occurences of the same buffer to the first index.
|
| - if (!m_transferredArrayBuffers.contains(v8ArrayBuffer))
|
| - m_transferredArrayBuffers.set(v8ArrayBuffer, i);
|
| - }
|
| -
|
| - const auto& imageBitmaps = transferables.imageBitmaps;
|
| - for (size_t i = 0; i < imageBitmaps.size(); ++i) {
|
| - v8::Local<v8::Object> v8ImageBitmap =
|
| - ToV8(imageBitmaps[i].get(), creationContext, isolate())
|
| - .As<v8::Object>();
|
| - if (!m_transferredImageBitmaps.contains(v8ImageBitmap))
|
| - m_transferredImageBitmaps.set(v8ImageBitmap, i);
|
| - }
|
| -
|
| - const auto& offscreenCanvases = transferables.offscreenCanvases;
|
| - for (size_t i = 0; i < offscreenCanvases.size(); ++i) {
|
| - v8::Local<v8::Object> v8OffscreenCanvas =
|
| - ToV8(offscreenCanvases[i].get(), creationContext, isolate())
|
| - .As<v8::Object>();
|
| - if (!m_transferredOffscreenCanvas.contains(v8OffscreenCanvas))
|
| - m_transferredOffscreenCanvas.set(v8OffscreenCanvas, i);
|
| - }
|
| -}
|
| -
|
| -PassRefPtr<SerializedScriptValue> ScriptValueSerializer::serialize(
|
| - v8::Local<v8::Value> value,
|
| - Transferables* transferables,
|
| - ExceptionState& exceptionState) {
|
| - DCHECK(!m_blobDataHandles);
|
| -
|
| - RefPtr<SerializedScriptValue> serializedValue =
|
| - SerializedScriptValue::create();
|
| -
|
| - m_blobDataHandles = &serializedValue->blobDataHandles();
|
| - if (transferables)
|
| - copyTransferables(*transferables);
|
| -
|
| - v8::HandleScope scope(isolate());
|
| - writer().writeVersion();
|
| - StateBase* state = doSerialize(value, nullptr);
|
| - while (state)
|
| - state = state->advance(*this);
|
| -
|
| - switch (m_status) {
|
| - case Status::Success:
|
| - transferData(transferables, exceptionState, serializedValue.get());
|
| - break;
|
| - case Status::InputError:
|
| - case Status::DataCloneError:
|
| - exceptionState.throwDOMException(blink::DataCloneError, m_errorMessage);
|
| - break;
|
| - case Status::JSException:
|
| - exceptionState.rethrowV8Exception(m_tryCatch.Exception());
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| -
|
| - return serializedValue.release();
|
| -}
|
| -
|
| -void ScriptValueSerializer::transferData(
|
| - Transferables* transferables,
|
| - ExceptionState& exceptionState,
|
| - SerializedScriptValue* serializedValue) {
|
| - serializedValue->setData(m_writer.takeWireString());
|
| - DCHECK(serializedValue->dataHasOneRef());
|
| - if (!transferables)
|
| - return;
|
| -
|
| - serializedValue->transferImageBitmaps(isolate(), transferables->imageBitmaps,
|
| - exceptionState);
|
| - if (exceptionState.hadException())
|
| - return;
|
| - serializedValue->transferArrayBuffers(isolate(), transferables->arrayBuffers,
|
| - exceptionState);
|
| - if (exceptionState.hadException())
|
| - return;
|
| - serializedValue->transferOffscreenCanvas(
|
| - isolate(), transferables->offscreenCanvases, exceptionState);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::doSerialize(
|
| - v8::Local<v8::Value> value,
|
| - StateBase* next) {
|
| - m_writer.writeReferenceCount(m_nextObjectReference);
|
| -
|
| - if (value.IsEmpty())
|
| - return handleError(Status::InputError,
|
| - "The empty property cannot be cloned.", next);
|
| -
|
| - uint32_t objectReference;
|
| - if ((value->IsObject() || value->IsDate() || value->IsRegExp()) &&
|
| - m_objectPool.tryGet(value.As<v8::Object>(), &objectReference)) {
|
| - // Note that IsObject() also detects wrappers (eg, it will catch the things
|
| - // that we grey and write below).
|
| - ASSERT(!value->IsString());
|
| - m_writer.writeObjectReference(objectReference);
|
| - return nullptr;
|
| - }
|
| - if (value->IsObject())
|
| - return doSerializeObject(value.As<v8::Object>(), next);
|
| -
|
| - if (value->IsUndefined()) {
|
| - m_writer.writeUndefined();
|
| - } else if (value->IsNull()) {
|
| - m_writer.writeNull();
|
| - } else if (value->IsTrue()) {
|
| - m_writer.writeTrue();
|
| - } else if (value->IsFalse()) {
|
| - m_writer.writeFalse();
|
| - } else if (value->IsInt32()) {
|
| - m_writer.writeInt32(value.As<v8::Int32>()->Value());
|
| - } else if (value->IsUint32()) {
|
| - m_writer.writeUint32(value.As<v8::Uint32>()->Value());
|
| - } else if (value->IsNumber()) {
|
| - m_writer.writeNumber(value.As<v8::Number>()->Value());
|
| - } else if (value->IsString()) {
|
| - writeString(value);
|
| - } else {
|
| - return handleError(Status::DataCloneError, "A value could not be cloned.",
|
| - next);
|
| - }
|
| - return nullptr;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::doSerializeObject(
|
| - v8::Local<v8::Object> object,
|
| - StateBase* next) {
|
| - DCHECK(!object.IsEmpty());
|
| -
|
| - if (object->IsArrayBufferView()) {
|
| - return writeAndGreyArrayBufferView(object, next);
|
| - }
|
| - if (object->IsArrayBuffer()) {
|
| - return writeAndGreyArrayBuffer(object, next);
|
| - }
|
| - if (object->IsSharedArrayBuffer()) {
|
| - uint32_t index;
|
| - if (!m_transferredArrayBuffers.tryGet(object, &index)) {
|
| - return handleError(Status::DataCloneError,
|
| - "A SharedArrayBuffer could not be cloned.", next);
|
| - }
|
| - return writeTransferredSharedArrayBuffer(object, index, next);
|
| - }
|
| -
|
| - if (object->IsWebAssemblyCompiledModule())
|
| - return writeWasmCompiledModule(object, next);
|
| -
|
| - // Transferable only objects
|
| - if (V8MessagePort::hasInstance(object, isolate())) {
|
| - uint32_t index;
|
| - if (!m_transferredMessagePorts.tryGet(object, &index)) {
|
| - return handleError(Status::DataCloneError,
|
| - "A MessagePort could not be cloned.", next);
|
| - }
|
| - m_writer.writeTransferredMessagePort(index);
|
| - return nullptr;
|
| - }
|
| - if (V8OffscreenCanvas::hasInstance(object, isolate())) {
|
| - uint32_t index;
|
| - if (!m_transferredOffscreenCanvas.tryGet(object, &index)) {
|
| - return handleError(Status::DataCloneError,
|
| - "A OffscreenCanvas could not be cloned.", next);
|
| - }
|
| - return writeTransferredOffscreenCanvas(object, next);
|
| - }
|
| - if (V8ImageBitmap::hasInstance(object, isolate())) {
|
| - return writeAndGreyImageBitmap(object, next);
|
| - }
|
| -
|
| - greyObject(object);
|
| -
|
| - if (object->IsDate()) {
|
| - m_writer.writeDate(object.As<v8::Date>()->ValueOf());
|
| - return nullptr;
|
| - }
|
| - if (object->IsStringObject()) {
|
| - writeStringObject(object);
|
| - return nullptr;
|
| - }
|
| - if (object->IsNumberObject()) {
|
| - writeNumberObject(object);
|
| - return nullptr;
|
| - }
|
| - if (object->IsBooleanObject()) {
|
| - writeBooleanObject(object);
|
| - return nullptr;
|
| - }
|
| - if (object->IsArray()) {
|
| - return startArrayState(object.As<v8::Array>(), next);
|
| - }
|
| - if (object->IsMap()) {
|
| - return startMapState(object.As<v8::Map>(), next);
|
| - }
|
| - if (object->IsSet()) {
|
| - return startSetState(object.As<v8::Set>(), next);
|
| - }
|
| -
|
| - if (V8File::hasInstance(object, isolate())) {
|
| - return writeFile(object, next);
|
| - }
|
| - if (V8Blob::hasInstance(object, isolate())) {
|
| - return writeBlob(object, next);
|
| - }
|
| - if (V8FileList::hasInstance(object, isolate())) {
|
| - return writeFileList(object, next);
|
| - }
|
| - if (V8ImageData::hasInstance(object, isolate())) {
|
| - writeImageData(object);
|
| - return nullptr;
|
| - }
|
| - if (object->IsRegExp()) {
|
| - writeRegExp(object);
|
| - return nullptr;
|
| - }
|
| - if (V8CompositorProxy::hasInstance(object, isolate())) {
|
| - return writeCompositorProxy(object, next);
|
| - }
|
| -
|
| - // Since IsNativeError is expensive, this check should always be the last
|
| - // check.
|
| - if (isHostObject(object) || object->IsCallable() || object->IsNativeError()) {
|
| - return handleError(Status::DataCloneError, "An object could not be cloned.",
|
| - next);
|
| - }
|
| -
|
| - return startObjectState(object, next);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::doSerializeArrayBuffer(
|
| - v8::Local<v8::Value> arrayBuffer,
|
| - StateBase* next) {
|
| - return doSerialize(arrayBuffer, next);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::checkException(
|
| - StateBase* state) {
|
| - return m_tryCatch.HasCaught() ? handleError(Status::JSException, "", state)
|
| - : nullptr;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::writeObject(
|
| - uint32_t numProperties,
|
| - StateBase* state) {
|
| - m_writer.writeObject(numProperties);
|
| - return pop(state);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::writeSparseArray(
|
| - uint32_t numProperties,
|
| - uint32_t length,
|
| - StateBase* state) {
|
| - m_writer.writeSparseArray(numProperties, length);
|
| - return pop(state);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::writeDenseArray(
|
| - uint32_t numProperties,
|
| - uint32_t length,
|
| - StateBase* state) {
|
| - m_writer.writeDenseArray(numProperties, length);
|
| - return pop(state);
|
| -}
|
| -
|
| -template <>
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::writeCollection<v8::Map>(uint32_t length,
|
| - StateBase* state) {
|
| - m_writer.writeMap(length);
|
| - return pop(state);
|
| -}
|
| -
|
| -template <>
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::writeCollection<v8::Set>(uint32_t length,
|
| - StateBase* state) {
|
| - m_writer.writeSet(length);
|
| - return pop(state);
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::handleError(
|
| - ScriptValueSerializer::Status errorStatus,
|
| - const String& message,
|
| - StateBase* state) {
|
| - DCHECK(errorStatus != Status::Success);
|
| - m_status = errorStatus;
|
| - m_errorMessage = message;
|
| - while (state) {
|
| - state = pop(state);
|
| - }
|
| - return new ErrorState;
|
| -}
|
| -
|
| -bool ScriptValueSerializer::checkComposite(StateBase* top) {
|
| - ASSERT(top);
|
| - if (m_depth > maxDepth)
|
| - return false;
|
| - if (!shouldCheckForCycles(m_depth))
|
| - return true;
|
| - v8::Local<v8::Value> composite = top->composite();
|
| - for (StateBase* state = top->nextState(); state; state = state->nextState()) {
|
| - if (state->composite() == composite)
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void ScriptValueSerializer::writeString(v8::Local<v8::Value> value) {
|
| - v8::Local<v8::String> string = value.As<v8::String>();
|
| - if (!string->Length() || string->IsOneByte())
|
| - m_writer.writeOneByteString(string);
|
| - else
|
| - m_writer.writeUCharString(string);
|
| -}
|
| -
|
| -void ScriptValueSerializer::writeStringObject(v8::Local<v8::Value> value) {
|
| - v8::Local<v8::StringObject> stringObject = value.As<v8::StringObject>();
|
| - v8::String::Utf8Value stringValue(stringObject->ValueOf());
|
| - m_writer.writeStringObject(*stringValue, stringValue.length());
|
| -}
|
| -
|
| -void ScriptValueSerializer::writeNumberObject(v8::Local<v8::Value> value) {
|
| - v8::Local<v8::NumberObject> numberObject = value.As<v8::NumberObject>();
|
| - m_writer.writeNumberObject(numberObject->ValueOf());
|
| -}
|
| -
|
| -void ScriptValueSerializer::writeBooleanObject(v8::Local<v8::Value> value) {
|
| - v8::Local<v8::BooleanObject> booleanObject = value.As<v8::BooleanObject>();
|
| - m_writer.writeBooleanObject(booleanObject->ValueOf());
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::writeBlob(
|
| - v8::Local<v8::Value> value,
|
| - StateBase* next) {
|
| - Blob* blob = V8Blob::toImpl(value.As<v8::Object>());
|
| - if (!blob)
|
| - return nullptr;
|
| - if (blob->isClosed())
|
| - return handleError(
|
| - Status::DataCloneError,
|
| - "A Blob object has been closed, and could therefore not be cloned.",
|
| - next);
|
| - int blobIndex = -1;
|
| - m_blobDataHandles->set(blob->uuid(), blob->blobDataHandle());
|
| - if (appendBlobInfo(blob->uuid(), blob->type(), blob->size(), &blobIndex))
|
| - m_writer.writeBlobIndex(blobIndex);
|
| - else
|
| - m_writer.writeBlob(blob->uuid(), blob->type(), blob->size());
|
| - return nullptr;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::writeCompositorProxy(
|
| - v8::Local<v8::Value> value,
|
| - StateBase* next) {
|
| - CompositorProxy* compositorProxy =
|
| - V8CompositorProxy::toImpl(value.As<v8::Object>());
|
| - if (!compositorProxy)
|
| - return nullptr;
|
| - if (!compositorProxy->connected())
|
| - return handleError(Status::DataCloneError,
|
| - "A CompositorProxy object has been disconnected, and "
|
| - "could therefore not be cloned.",
|
| - next);
|
| - m_writer.writeCompositorProxy(*compositorProxy);
|
| - return nullptr;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::writeFile(
|
| - v8::Local<v8::Value> value,
|
| - StateBase* next) {
|
| - File* file = V8File::toImpl(value.As<v8::Object>());
|
| - if (!file)
|
| - return nullptr;
|
| - if (file->isClosed())
|
| - return handleError(
|
| - Status::DataCloneError,
|
| - "A File object has been closed, and could therefore not be cloned.",
|
| - next);
|
| - int blobIndex = -1;
|
| - m_blobDataHandles->set(file->uuid(), file->blobDataHandle());
|
| - if (appendFileInfo(file, &blobIndex)) {
|
| - ASSERT(blobIndex >= 0);
|
| - m_writer.writeFileIndex(blobIndex);
|
| - } else {
|
| - m_writer.writeFile(*file);
|
| - }
|
| - return nullptr;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::writeFileList(
|
| - v8::Local<v8::Value> value,
|
| - StateBase* next) {
|
| - FileList* fileList = V8FileList::toImpl(value.As<v8::Object>());
|
| - if (!fileList)
|
| - return nullptr;
|
| - unsigned length = fileList->length();
|
| - Vector<int> blobIndices;
|
| - for (unsigned i = 0; i < length; ++i) {
|
| - int blobIndex = -1;
|
| - const File* file = fileList->item(i);
|
| - if (file->isClosed())
|
| - return handleError(
|
| - Status::DataCloneError,
|
| - "A File object has been closed, and could therefore not be cloned.",
|
| - next);
|
| - m_blobDataHandles->set(file->uuid(), file->blobDataHandle());
|
| - if (appendFileInfo(file, &blobIndex)) {
|
| - ASSERT(!i || blobIndex > 0);
|
| - ASSERT(blobIndex >= 0);
|
| - blobIndices.push_back(blobIndex);
|
| - }
|
| - }
|
| - if (!blobIndices.isEmpty())
|
| - m_writer.writeFileListIndex(blobIndices);
|
| - else
|
| - m_writer.writeFileList(*fileList);
|
| - return nullptr;
|
| -}
|
| -
|
| -void ScriptValueSerializer::writeImageData(v8::Local<v8::Value> value) {
|
| - ImageData* imageData = V8ImageData::toImpl(value.As<v8::Object>());
|
| - if (!imageData)
|
| - return;
|
| - DOMUint8ClampedArray* pixelArray = imageData->data();
|
| - m_writer.writeImageData(imageData->width(), imageData->height(),
|
| - pixelArray->data(), pixelArray->length());
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::writeAndGreyImageBitmap(v8::Local<v8::Object> object,
|
| - StateBase* next) {
|
| - ImageBitmap* imageBitmap = V8ImageBitmap::toImpl(object);
|
| - if (!imageBitmap)
|
| - return nullptr;
|
| - if (imageBitmap->isNeutered())
|
| - return handleError(Status::DataCloneError,
|
| - "An ImageBitmap is detached and could not be cloned.",
|
| - next);
|
| -
|
| - uint32_t index;
|
| - if (m_transferredImageBitmaps.tryGet(object, &index)) {
|
| - m_writer.writeTransferredImageBitmap(index);
|
| - } else {
|
| - greyObject(object);
|
| - RefPtr<Uint8Array> pixelData = imageBitmap->copyBitmapData(
|
| - imageBitmap->isPremultiplied() ? PremultiplyAlpha
|
| - : DontPremultiplyAlpha,
|
| - N32ColorType);
|
| - m_writer.writeImageBitmap(
|
| - imageBitmap->width(), imageBitmap->height(),
|
| - static_cast<uint32_t>(imageBitmap->originClean()),
|
| - static_cast<uint32_t>(imageBitmap->isPremultiplied()),
|
| - pixelData->data(), imageBitmap->width() * imageBitmap->height() * 4);
|
| - }
|
| - return nullptr;
|
| -}
|
| -
|
| -void ScriptValueSerializer::writeRegExp(v8::Local<v8::Value> value) {
|
| - v8::Local<v8::RegExp> regExp = value.As<v8::RegExp>();
|
| - m_writer.writeRegExp(regExp->GetSource(), regExp->GetFlags());
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::writeAndGreyArrayBufferView(v8::Local<v8::Object> object,
|
| - StateBase* next) {
|
| - ASSERT(!object.IsEmpty());
|
| - DOMArrayBufferView* arrayBufferView = V8ArrayBufferView::toImpl(object);
|
| - if (!arrayBufferView)
|
| - return nullptr;
|
| - if (!arrayBufferView->bufferBase())
|
| - return handleError(Status::DataCloneError,
|
| - "An ArrayBuffer could not be cloned.", next);
|
| - v8::Local<v8::Value> underlyingBuffer =
|
| - ToV8(arrayBufferView->bufferBase(), m_scriptState->context()->Global(),
|
| - isolate());
|
| - if (underlyingBuffer.IsEmpty())
|
| - return handleError(Status::DataCloneError,
|
| - "An ArrayBuffer could not be cloned.", next);
|
| - StateBase* stateOut = doSerializeArrayBuffer(underlyingBuffer, next);
|
| - if (stateOut)
|
| - return stateOut;
|
| - m_writer.writeArrayBufferView(*arrayBufferView);
|
| - // This should be safe: we serialize something that we know to be a wrapper
|
| - // (see the toV8 call above), so the call to doSerializeArrayBuffer should
|
| - // neither cause the system stack to overflow nor should it have potential to
|
| - // reach this ArrayBufferView again.
|
| - //
|
| - // We do need to grey the underlying buffer before we grey its view, however;
|
| - // ArrayBuffers may be shared, so they need to be given reference IDs, and an
|
| - // ArrayBufferView cannot be constructed without a corresponding ArrayBuffer
|
| - // (or without an additional tag that would allow us to do two-stage
|
| - // construction like we do for Objects and Arrays).
|
| - greyObject(object);
|
| - return nullptr;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::writeWasmCompiledModule(v8::Local<v8::Object> object,
|
| - StateBase* next) {
|
| - CHECK(RuntimeEnabledFeatures::webAssemblySerializationEnabled());
|
| - // TODO (mtrofin): explore mechanism avoiding data copying / buffer resizing.
|
| - v8::Local<v8::WasmCompiledModule> wasmModule =
|
| - object.As<v8::WasmCompiledModule>();
|
| - v8::Local<v8::String> wireBytes = wasmModule->GetWasmWireBytes();
|
| - DCHECK(wireBytes->IsOneByte());
|
| -
|
| - v8::WasmCompiledModule::SerializedModule data = wasmModule->Serialize();
|
| - m_writer.append(WasmModuleTag);
|
| - uint32_t wireBytesLength = static_cast<uint32_t>(wireBytes->Length());
|
| - // We place a tag so we may evolve the format in which we store the
|
| - // wire bytes. We plan to move them to a blob.
|
| - // We want to control how we write the string, though, so we explicitly
|
| - // call writeRawStringBytes.
|
| - m_writer.append(RawBytesTag);
|
| - m_writer.doWriteUint32(wireBytesLength);
|
| - m_writer.ensureSpace(wireBytesLength);
|
| - m_writer.writeRawStringBytes(wireBytes);
|
| - m_writer.doWriteUint32(static_cast<uint32_t>(data.second));
|
| - m_writer.append(data.first.get(), static_cast<int>(data.second));
|
| - return nullptr;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::writeAndGreyArrayBuffer(v8::Local<v8::Object> object,
|
| - StateBase* next) {
|
| - DOMArrayBuffer* arrayBuffer = V8ArrayBuffer::toImpl(object);
|
| - if (!arrayBuffer)
|
| - return nullptr;
|
| - if (arrayBuffer->isNeutered())
|
| - return handleError(Status::DataCloneError,
|
| - "An ArrayBuffer is neutered and could not be cloned.",
|
| - next);
|
| -
|
| - uint32_t index;
|
| - if (m_transferredArrayBuffers.tryGet(object, &index)) {
|
| - m_writer.writeTransferredArrayBuffer(index);
|
| - } else {
|
| - greyObject(object);
|
| - m_writer.writeArrayBuffer(*arrayBuffer);
|
| - }
|
| - return nullptr;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::writeTransferredOffscreenCanvas(
|
| - v8::Local<v8::Value> value,
|
| - StateBase* next) {
|
| - OffscreenCanvas* offscreenCanvas =
|
| - V8OffscreenCanvas::toImpl(value.As<v8::Object>());
|
| - if (!offscreenCanvas)
|
| - return nullptr;
|
| - if (offscreenCanvas->isNeutered())
|
| - return handleError(
|
| - Status::DataCloneError,
|
| - "An OffscreenCanvas is detached and could not be cloned.", next);
|
| - if (offscreenCanvas->renderingContext())
|
| - return handleError(Status::DataCloneError,
|
| - "An OffscreenCanvas with a context could not be cloned.",
|
| - next);
|
| - m_writer.writeTransferredOffscreenCanvas(
|
| - offscreenCanvas->width(), offscreenCanvas->height(),
|
| - offscreenCanvas->placeholderCanvasId(), offscreenCanvas->clientId(),
|
| - offscreenCanvas->sinkId());
|
| - return nullptr;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase*
|
| -ScriptValueSerializer::writeTransferredSharedArrayBuffer(
|
| - v8::Local<v8::Value> value,
|
| - uint32_t index,
|
| - StateBase* next) {
|
| - ASSERT(RuntimeEnabledFeatures::sharedArrayBufferEnabled());
|
| - DOMSharedArrayBuffer* sharedArrayBuffer =
|
| - V8SharedArrayBuffer::toImpl(value.As<v8::Object>());
|
| - if (!sharedArrayBuffer)
|
| - return 0;
|
| - m_writer.writeTransferredSharedArrayBuffer(index);
|
| - return nullptr;
|
| -}
|
| -
|
| -bool ScriptValueSerializer::shouldSerializeDensely(uint32_t length,
|
| - uint32_t propertyCount) {
|
| - // Let K be the cost of serializing all property values that are there
|
| - // Cost of serializing sparsely: 5*propertyCount + K (5 bytes per uint32_t
|
| - // key)
|
| - // Cost of serializing densely: K + 1*(length - propertyCount) (1 byte for all
|
| - // properties that are not there)
|
| - // so densely is better than sparsly whenever 6*propertyCount > length
|
| - return 6 * propertyCount >= length;
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::startArrayState(
|
| - v8::Local<v8::Array> array,
|
| - StateBase* next) {
|
| - v8::Local<v8::Array> propertyNames;
|
| - if (!array->GetOwnPropertyNames(context()).ToLocal(&propertyNames))
|
| - return checkException(next);
|
| - uint32_t length = array->Length();
|
| -
|
| - if (shouldSerializeDensely(length, propertyNames->Length())) {
|
| - // In serializing a dense array, indexed properties are ignored, so we get
|
| - // non indexed own property names here.
|
| - if (!array
|
| - ->GetPropertyNames(context(),
|
| - v8::KeyCollectionMode::kIncludePrototypes,
|
| - static_cast<v8::PropertyFilter>(
|
| - v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS),
|
| - v8::IndexFilter::kSkipIndices)
|
| - .ToLocal(&propertyNames))
|
| - return checkException(next);
|
| -
|
| - m_writer.writeGenerateFreshDenseArray(length);
|
| - return push(new DenseArrayState(array, propertyNames, next, isolate()));
|
| - }
|
| -
|
| - m_writer.writeGenerateFreshSparseArray(length);
|
| - return push(new SparseArrayState(array, propertyNames, next, isolate()));
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::startMapState(
|
| - v8::Local<v8::Map> map,
|
| - StateBase* next) {
|
| - m_writer.writeGenerateFreshMap();
|
| - return push(new MapState(map, next));
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::startSetState(
|
| - v8::Local<v8::Set> set,
|
| - StateBase* next) {
|
| - m_writer.writeGenerateFreshSet();
|
| - return push(new SetState(set, next));
|
| -}
|
| -
|
| -ScriptValueSerializer::StateBase* ScriptValueSerializer::startObjectState(
|
| - v8::Local<v8::Object> object,
|
| - StateBase* next) {
|
| - m_writer.writeGenerateFreshObject();
|
| - // FIXME: check not a wrapper
|
| - return push(new ObjectState(object, next));
|
| -}
|
| -
|
| -// Marks object as having been visited by the serializer and assigns it a unique
|
| -// object reference ID. An object may only be greyed once.
|
| -void ScriptValueSerializer::greyObject(const v8::Local<v8::Object>& object) {
|
| - ASSERT(!m_objectPool.contains(object));
|
| - uint32_t objectReference = m_nextObjectReference++;
|
| - m_objectPool.set(object, objectReference);
|
| -}
|
| -
|
| -bool ScriptValueSerializer::appendBlobInfo(const String& uuid,
|
| - const String& type,
|
| - unsigned long long size,
|
| - int* index) {
|
| - if (!m_blobInfo)
|
| - return false;
|
| - *index = m_blobInfo->size();
|
| - m_blobInfo->push_back(WebBlobInfo(uuid, type, size));
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueSerializer::appendFileInfo(const File* file, int* index) {
|
| - if (!m_blobInfo)
|
| - return false;
|
| -
|
| - long long size = -1;
|
| - double lastModifiedMS = invalidFileTime();
|
| - file->captureSnapshot(size, lastModifiedMS);
|
| - *index = m_blobInfo->size();
|
| - // FIXME: transition WebBlobInfo.lastModified to be milliseconds-based also.
|
| - double lastModified = lastModifiedMS / msPerSecond;
|
| - m_blobInfo->push_back(WebBlobInfo(file->uuid(), file->path(), file->name(),
|
| - file->type(), lastModified, size));
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::read(v8::Local<v8::Value>* value,
|
| - ScriptValueDeserializer& deserializer) {
|
| - SerializationTag tag;
|
| - if (!readTag(&tag))
|
| - return false;
|
| - return readWithTag(tag, value, deserializer);
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readWithTag(
|
| - SerializationTag tag,
|
| - v8::Local<v8::Value>* value,
|
| - ScriptValueDeserializer& deserializer) {
|
| - switch (tag) {
|
| - case ReferenceCountTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t referenceTableSize;
|
| - if (!doReadUint32(&referenceTableSize))
|
| - return false;
|
| - // If this test fails, then the serializer and deserializer disagree about
|
| - // the assignment of object reference IDs. On the deserialization side,
|
| - // this means there are too many or too few calls to pushObjectReference.
|
| - if (referenceTableSize != deserializer.objectReferenceCount())
|
| - return false;
|
| - return true;
|
| - }
|
| - case InvalidTag:
|
| - return false;
|
| - case PaddingTag:
|
| - return true;
|
| - case UndefinedTag:
|
| - *value = v8::Undefined(isolate());
|
| - break;
|
| - case NullTag:
|
| - *value = v8::Null(isolate());
|
| - break;
|
| - case TrueTag:
|
| - *value = v8Boolean(true, isolate());
|
| - break;
|
| - case FalseTag:
|
| - *value = v8Boolean(false, isolate());
|
| - break;
|
| - case TrueObjectTag:
|
| - *value = v8::BooleanObject::New(isolate(), true);
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case FalseObjectTag:
|
| - *value = v8::BooleanObject::New(isolate(), false);
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case StringTag:
|
| - if (!readString(value))
|
| - return false;
|
| - break;
|
| - case StringUCharTag:
|
| - if (!readUCharString(value))
|
| - return false;
|
| - break;
|
| - case StringObjectTag:
|
| - if (!readStringObject(value))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case Int32Tag:
|
| - if (!readInt32(value))
|
| - return false;
|
| - break;
|
| - case Uint32Tag:
|
| - if (!readUint32(value))
|
| - return false;
|
| - break;
|
| - case DateTag:
|
| - if (!readDate(value))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case NumberTag:
|
| - if (!readNumber(value))
|
| - return false;
|
| - break;
|
| - case NumberObjectTag:
|
| - if (!readNumberObject(value))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case BlobTag:
|
| - case BlobIndexTag:
|
| - if (!readBlob(value, tag == BlobIndexTag))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case FileTag:
|
| - case FileIndexTag:
|
| - if (!readFile(value, tag == FileIndexTag))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case FileListTag:
|
| - case FileListIndexTag:
|
| - if (!readFileList(value, tag == FileListIndexTag))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case CompositorProxyTag:
|
| - if (!readCompositorProxy(value))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| -
|
| - case ImageDataTag:
|
| - if (!readImageData(value))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case ImageBitmapTag:
|
| - if (!readImageBitmap(value))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| -
|
| - case RegExpTag:
|
| - if (!readRegExp(value))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - case ObjectTag: {
|
| - uint32_t numProperties;
|
| - if (!doReadUint32(&numProperties))
|
| - return false;
|
| - if (!deserializer.completeObject(numProperties, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case SparseArrayTag: {
|
| - uint32_t numProperties;
|
| - uint32_t length;
|
| - if (!doReadUint32(&numProperties))
|
| - return false;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (!deserializer.completeSparseArray(numProperties, length, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case DenseArrayTag: {
|
| - uint32_t numProperties;
|
| - uint32_t length;
|
| - if (!doReadUint32(&numProperties))
|
| - return false;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (!deserializer.completeDenseArray(numProperties, length, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case MapTag: {
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (!deserializer.completeMap(length, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case SetTag: {
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (!deserializer.completeSet(length, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case ArrayBufferViewTag: {
|
| - if (!m_version)
|
| - return false;
|
| - if (!readArrayBufferView(value, deserializer))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - }
|
| - case WasmModuleTag: {
|
| - if (!readWasmCompiledModule(value))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - }
|
| - case ArrayBufferTag: {
|
| - if (!m_version)
|
| - return false;
|
| - if (!readArrayBuffer(value))
|
| - return false;
|
| - deserializer.pushObjectReference(*value);
|
| - break;
|
| - }
|
| - case GenerateFreshObjectTag: {
|
| - if (!m_version)
|
| - return false;
|
| - if (!deserializer.newObject())
|
| - return false;
|
| - return true;
|
| - }
|
| - case GenerateFreshSparseArrayTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (!deserializer.newSparseArray(length))
|
| - return false;
|
| - return true;
|
| - }
|
| - case GenerateFreshDenseArrayTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (!deserializer.newDenseArray(length))
|
| - return false;
|
| - return true;
|
| - }
|
| - case GenerateFreshMapTag: {
|
| - if (!m_version)
|
| - return false;
|
| - if (!deserializer.newMap())
|
| - return false;
|
| - return true;
|
| - }
|
| - case GenerateFreshSetTag: {
|
| - if (!m_version)
|
| - return false;
|
| - if (!deserializer.newSet())
|
| - return false;
|
| - return true;
|
| - }
|
| - case MessagePortTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t index;
|
| - if (!doReadUint32(&index))
|
| - return false;
|
| - if (!deserializer.tryGetTransferredMessagePort(index, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case ArrayBufferTransferTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t index;
|
| - if (!doReadUint32(&index))
|
| - return false;
|
| - if (!deserializer.tryGetTransferredArrayBuffer(index, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case ImageBitmapTransferTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t index;
|
| - if (!doReadUint32(&index))
|
| - return false;
|
| - if (!deserializer.tryGetTransferredImageBitmap(index, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case OffscreenCanvasTransferTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t width, height, canvasId, clientId, sinkId;
|
| - if (!doReadUint32(&width))
|
| - return false;
|
| - if (!doReadUint32(&height))
|
| - return false;
|
| - if (!doReadUint32(&canvasId))
|
| - return false;
|
| - if (!doReadUint32(&clientId))
|
| - return false;
|
| - if (!doReadUint32(&sinkId))
|
| - return false;
|
| - if (!deserializer.tryGetTransferredOffscreenCanvas(
|
| - width, height, canvasId, clientId, sinkId, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case SharedArrayBufferTransferTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t index;
|
| - if (!doReadUint32(&index))
|
| - return false;
|
| - if (!deserializer.tryGetTransferredSharedArrayBuffer(index, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case ObjectReferenceTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t reference;
|
| - if (!doReadUint32(&reference))
|
| - return false;
|
| - if (!deserializer.tryGetObjectFromObjectReference(reference, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case DOMFileSystemTag:
|
| - case CryptoKeyTag:
|
| - ASSERT_NOT_REACHED();
|
| - default:
|
| - return false;
|
| - }
|
| - return !value->IsEmpty();
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readVersion(uint32_t& version) {
|
| - SerializationTag tag;
|
| - if (!readTag(&tag)) {
|
| - // This is a nullary buffer. We're still version 0.
|
| - version = 0;
|
| - return true;
|
| - }
|
| - if (tag != VersionTag) {
|
| - // Versions of the format past 0 start with the version tag.
|
| - version = 0;
|
| - // Put back the tag.
|
| - undoReadTag();
|
| - return true;
|
| - }
|
| - // Version-bearing messages are obligated to finish the version tag.
|
| - return doReadUint32(&version);
|
| -}
|
| -
|
| -void SerializedScriptValueReader::setVersion(uint32_t version) {
|
| - m_version = version;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readTag(SerializationTag* tag) {
|
| - if (m_position >= m_length)
|
| - return false;
|
| - *tag = static_cast<SerializationTag>(m_buffer[m_position++]);
|
| - return true;
|
| -}
|
| -
|
| -void SerializedScriptValueReader::undoReadTag() {
|
| - if (m_position > 0)
|
| - --m_position;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readArrayBufferViewSubTag(
|
| - ArrayBufferViewSubTag* tag) {
|
| - if (m_position >= m_length)
|
| - return false;
|
| - *tag = static_cast<ArrayBufferViewSubTag>(m_buffer[m_position++]);
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readString(v8::Local<v8::Value>* value) {
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (m_position + length > m_length)
|
| - return false;
|
| - *value = v8StringFromUtf8(
|
| - isolate(), reinterpret_cast<const char*>(m_buffer + m_position), length);
|
| - m_position += length;
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readUCharString(v8::Local<v8::Value>* value) {
|
| - uint32_t length;
|
| - if (!doReadUint32(&length) || (length & 1))
|
| - return false;
|
| - if (m_position + length > m_length)
|
| - return false;
|
| - ASSERT(!(m_position & 1));
|
| - if (!v8::String::NewFromTwoByte(
|
| - isolate(), reinterpret_cast<const uint16_t*>(m_buffer + m_position),
|
| - v8::NewStringType::kNormal, length / sizeof(UChar))
|
| - .ToLocal(value))
|
| - return false;
|
| - m_position += length;
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readStringObject(
|
| - v8::Local<v8::Value>* value) {
|
| - v8::Local<v8::Value> stringValue;
|
| - if (!readString(&stringValue) || !stringValue->IsString())
|
| - return false;
|
| - *value = v8::StringObject::New(stringValue.As<v8::String>());
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readWebCoreString(String* string) {
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (m_position + length > m_length)
|
| - return false;
|
| - *string = String::fromUTF8(
|
| - reinterpret_cast<const char*>(m_buffer + m_position), length);
|
| - m_position += length;
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readInt32(v8::Local<v8::Value>* value) {
|
| - uint32_t rawValue;
|
| - if (!doReadUint32(&rawValue))
|
| - return false;
|
| - *value = v8::Integer::New(isolate(),
|
| - static_cast<int32_t>(ZigZag::decode(rawValue)));
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readUint32(v8::Local<v8::Value>* value) {
|
| - uint32_t rawValue;
|
| - if (!doReadUint32(&rawValue))
|
| - return false;
|
| - *value = v8::Integer::NewFromUnsigned(isolate(), rawValue);
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readDate(v8::Local<v8::Value>* value) {
|
| - double numberValue;
|
| - if (!doReadNumber(&numberValue))
|
| - return false;
|
| - if (!v8DateOrNaN(isolate(), numberValue).ToLocal(value))
|
| - return false;
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readNumber(v8::Local<v8::Value>* value) {
|
| - double number;
|
| - if (!doReadNumber(&number))
|
| - return false;
|
| - *value = v8::Number::New(isolate(), number);
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readNumberObject(
|
| - v8::Local<v8::Value>* value) {
|
| - double number;
|
| - if (!doReadNumber(&number))
|
| - return false;
|
| - *value = v8::NumberObject::New(isolate(), number);
|
| - return true;
|
| -}
|
| -
|
| -// Helper function used by readImageData and readImageBitmap.
|
| -bool SerializedScriptValueReader::doReadImageDataProperties(
|
| - uint32_t* width,
|
| - uint32_t* height,
|
| - uint32_t* pixelDataLength) {
|
| - if (!doReadUint32(width))
|
| - return false;
|
| - if (!doReadUint32(height))
|
| - return false;
|
| - if (!doReadUint32(pixelDataLength))
|
| - return false;
|
| - if (m_length - m_position < *pixelDataLength)
|
| - return false;
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readImageData(v8::Local<v8::Value>* value) {
|
| - uint32_t width;
|
| - uint32_t height;
|
| - uint32_t pixelDataLength;
|
| - if (!doReadImageDataProperties(&width, &height, &pixelDataLength))
|
| - return false;
|
| - ImageData* imageData = ImageData::create(IntSize(width, height));
|
| - DOMUint8ClampedArray* pixelArray = imageData->data();
|
| - ASSERT(pixelArray);
|
| - ASSERT(pixelArray->length() >= pixelDataLength);
|
| - memcpy(pixelArray->data(), m_buffer + m_position, pixelDataLength);
|
| - m_position += pixelDataLength;
|
| - if (!imageData)
|
| - return false;
|
| - *value = ToV8(imageData, m_scriptState->context()->Global(), isolate());
|
| - return !value->IsEmpty();
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readImageBitmap(v8::Local<v8::Value>* value) {
|
| - uint32_t isOriginClean;
|
| - if (!doReadUint32(&isOriginClean))
|
| - return false;
|
| - uint32_t isPremultiplied;
|
| - if (!doReadUint32(&isPremultiplied))
|
| - return false;
|
| - uint32_t width;
|
| - uint32_t height;
|
| - uint32_t pixelDataLength;
|
| - if (!doReadImageDataProperties(&width, &height, &pixelDataLength))
|
| - return false;
|
| - const void* pixelData = m_buffer + m_position;
|
| - m_position += pixelDataLength;
|
| - ImageBitmap* imageBitmap = ImageBitmap::create(
|
| - pixelData, width, height, isPremultiplied, isOriginClean);
|
| - if (!imageBitmap)
|
| - return false;
|
| - *value = ToV8(imageBitmap, m_scriptState->context()->Global(), isolate());
|
| - return !value->IsEmpty();
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readCompositorProxy(
|
| - v8::Local<v8::Value>* value) {
|
| - uint32_t attributes;
|
| - uint64_t element;
|
| - if (!doReadUint64(&element))
|
| - return false;
|
| - if (!doReadUint32(&attributes))
|
| - return false;
|
| -
|
| - CompositorProxy* compositorProxy = CompositorProxy::create(
|
| - m_scriptState->getExecutionContext(), element, attributes);
|
| - *value = ToV8(compositorProxy, m_scriptState->context()->Global(), isolate());
|
| - return !value->IsEmpty();
|
| -}
|
| -
|
| -DOMArrayBuffer* SerializedScriptValueReader::doReadArrayBuffer() {
|
| - uint32_t byteLength;
|
| - if (!doReadUint32(&byteLength))
|
| - return nullptr;
|
| - if (m_position + byteLength > m_length)
|
| - return nullptr;
|
| - const void* bufferStart = m_buffer + m_position;
|
| - m_position += byteLength;
|
| - return DOMArrayBuffer::create(bufferStart, byteLength);
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readWasmCompiledModule(
|
| - v8::Local<v8::Value>* value) {
|
| - CHECK(RuntimeEnabledFeatures::webAssemblySerializationEnabled());
|
| - // First, read the tag of the wire bytes.
|
| - SerializationTag wireBytesFormat = InvalidTag;
|
| - if (!readTag(&wireBytesFormat))
|
| - return false;
|
| - DCHECK(wireBytesFormat == RawBytesTag);
|
| - // Just like when writing, we don't rely on the default string serialization
|
| - // mechanics for the wire bytes. We don't even want a string, because
|
| - // that would lead to a memory copying API implementation on the V8 side.
|
| - uint32_t wireBytesSize = 0;
|
| - uint32_t compiledBytesSize = 0;
|
| - if (!doReadUint32(&wireBytesSize))
|
| - return false;
|
| - if (m_position + wireBytesSize > m_length)
|
| - return false;
|
| - const uint8_t* wireBytesStart = m_buffer + m_position;
|
| - m_position += wireBytesSize;
|
| -
|
| - if (!doReadUint32(&compiledBytesSize))
|
| - return false;
|
| - if (m_position + compiledBytesSize > m_length)
|
| - return false;
|
| - const uint8_t* compiledBytesStart = m_buffer + m_position;
|
| - m_position += compiledBytesSize;
|
| -
|
| - v8::WasmCompiledModule::CallerOwnedBuffer wireBytes = {
|
| - wireBytesStart, static_cast<size_t>(wireBytesSize)};
|
| -
|
| - v8::WasmCompiledModule::CallerOwnedBuffer compiledBytes = {
|
| - compiledBytesStart, static_cast<size_t>(compiledBytesSize)};
|
| -
|
| - v8::MaybeLocal<v8::WasmCompiledModule> retval =
|
| - v8::WasmCompiledModule::DeserializeOrCompile(isolate(), compiledBytes,
|
| - wireBytes);
|
| -
|
| - return retval.ToLocal(value);
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readArrayBuffer(v8::Local<v8::Value>* value) {
|
| - DOMArrayBuffer* arrayBuffer = doReadArrayBuffer();
|
| - if (!arrayBuffer)
|
| - return false;
|
| - *value = ToV8(arrayBuffer, m_scriptState->context()->Global(), isolate());
|
| - return !value->IsEmpty();
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readArrayBufferView(
|
| - v8::Local<v8::Value>* value,
|
| - ScriptValueDeserializer& deserializer) {
|
| - ArrayBufferViewSubTag subTag;
|
| - uint32_t byteOffset;
|
| - uint32_t byteLength;
|
| - DOMArrayBufferBase* arrayBuffer = nullptr;
|
| - v8::Local<v8::Value> arrayBufferV8Value;
|
| - if (!readArrayBufferViewSubTag(&subTag))
|
| - return false;
|
| - if (!doReadUint32(&byteOffset))
|
| - return false;
|
| - if (!doReadUint32(&byteLength))
|
| - return false;
|
| - if (!deserializer.consumeTopOfStack(&arrayBufferV8Value))
|
| - return false;
|
| - if (arrayBufferV8Value.IsEmpty())
|
| - return false;
|
| - if (arrayBufferV8Value->IsArrayBuffer()) {
|
| - arrayBuffer = V8ArrayBuffer::toImpl(arrayBufferV8Value.As<v8::Object>());
|
| - if (!arrayBuffer)
|
| - return false;
|
| - } else if (arrayBufferV8Value->IsSharedArrayBuffer()) {
|
| - arrayBuffer =
|
| - V8SharedArrayBuffer::toImpl(arrayBufferV8Value.As<v8::Object>());
|
| - if (!arrayBuffer)
|
| - return false;
|
| - } else {
|
| - ASSERT_NOT_REACHED();
|
| - }
|
| -
|
| - // Check the offset, length and alignment.
|
| - int elementByteSize;
|
| - switch (subTag) {
|
| - case ByteArrayTag:
|
| - elementByteSize = sizeof(DOMInt8Array::ValueType);
|
| - break;
|
| - case UnsignedByteArrayTag:
|
| - elementByteSize = sizeof(DOMUint8Array::ValueType);
|
| - break;
|
| - case UnsignedByteClampedArrayTag:
|
| - elementByteSize = sizeof(DOMUint8ClampedArray::ValueType);
|
| - break;
|
| - case ShortArrayTag:
|
| - elementByteSize = sizeof(DOMInt16Array::ValueType);
|
| - break;
|
| - case UnsignedShortArrayTag:
|
| - elementByteSize = sizeof(DOMUint16Array::ValueType);
|
| - break;
|
| - case IntArrayTag:
|
| - elementByteSize = sizeof(DOMInt32Array::ValueType);
|
| - break;
|
| - case UnsignedIntArrayTag:
|
| - elementByteSize = sizeof(DOMUint32Array::ValueType);
|
| - break;
|
| - case FloatArrayTag:
|
| - elementByteSize = sizeof(DOMFloat32Array::ValueType);
|
| - break;
|
| - case DoubleArrayTag:
|
| - elementByteSize = sizeof(DOMFloat64Array::ValueType);
|
| - break;
|
| - case DataViewTag:
|
| - elementByteSize = sizeof(DOMDataView::ValueType);
|
| - break;
|
| - default:
|
| - return false;
|
| - }
|
| - const unsigned numElements = byteLength / elementByteSize;
|
| - const unsigned remainingElements =
|
| - (arrayBuffer->byteLength() - byteOffset) / elementByteSize;
|
| - if (byteOffset % elementByteSize || byteOffset > arrayBuffer->byteLength() ||
|
| - numElements > remainingElements)
|
| - return false;
|
| -
|
| - v8::Local<v8::Object> creationContext = m_scriptState->context()->Global();
|
| - switch (subTag) {
|
| - case ByteArrayTag:
|
| - *value = ToV8(DOMInt8Array::create(arrayBuffer, byteOffset, numElements),
|
| - creationContext, isolate());
|
| - break;
|
| - case UnsignedByteArrayTag:
|
| - *value = ToV8(DOMUint8Array::create(arrayBuffer, byteOffset, numElements),
|
| - creationContext, isolate());
|
| - break;
|
| - case UnsignedByteClampedArrayTag:
|
| - *value = ToV8(
|
| - DOMUint8ClampedArray::create(arrayBuffer, byteOffset, numElements),
|
| - creationContext, isolate());
|
| - break;
|
| - case ShortArrayTag:
|
| - *value = ToV8(DOMInt16Array::create(arrayBuffer, byteOffset, numElements),
|
| - creationContext, isolate());
|
| - break;
|
| - case UnsignedShortArrayTag:
|
| - *value =
|
| - ToV8(DOMUint16Array::create(arrayBuffer, byteOffset, numElements),
|
| - creationContext, isolate());
|
| - break;
|
| - case IntArrayTag:
|
| - *value = ToV8(DOMInt32Array::create(arrayBuffer, byteOffset, numElements),
|
| - creationContext, isolate());
|
| - break;
|
| - case UnsignedIntArrayTag:
|
| - *value =
|
| - ToV8(DOMUint32Array::create(arrayBuffer, byteOffset, numElements),
|
| - creationContext, isolate());
|
| - break;
|
| - case FloatArrayTag:
|
| - *value =
|
| - ToV8(DOMFloat32Array::create(arrayBuffer, byteOffset, numElements),
|
| - creationContext, isolate());
|
| - break;
|
| - case DoubleArrayTag:
|
| - *value =
|
| - ToV8(DOMFloat64Array::create(arrayBuffer, byteOffset, numElements),
|
| - creationContext, isolate());
|
| - break;
|
| - case DataViewTag:
|
| - *value = ToV8(DOMDataView::create(arrayBuffer, byteOffset, byteLength),
|
| - creationContext, isolate());
|
| - break;
|
| - }
|
| - return !value->IsEmpty();
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readRegExp(v8::Local<v8::Value>* value) {
|
| - v8::Local<v8::Value> pattern;
|
| - if (!readString(&pattern))
|
| - return false;
|
| - uint32_t flags;
|
| - if (!doReadUint32(&flags))
|
| - return false;
|
| - if (!v8::RegExp::New(getScriptState()->context(), pattern.As<v8::String>(),
|
| - static_cast<v8::RegExp::Flags>(flags))
|
| - .ToLocal(value))
|
| - return false;
|
| - return true;
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readBlob(v8::Local<v8::Value>* value,
|
| - bool isIndexed) {
|
| - if (m_version < 3)
|
| - return false;
|
| - Blob* blob = nullptr;
|
| - if (isIndexed) {
|
| - if (m_version < 6)
|
| - return false;
|
| - ASSERT(m_blobInfo);
|
| - uint32_t index;
|
| - if (!doReadUint32(&index) || index >= m_blobInfo->size())
|
| - return false;
|
| - const WebBlobInfo& info = (*m_blobInfo)[index];
|
| - blob = Blob::create(
|
| - getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
|
| - } else {
|
| - ASSERT(!m_blobInfo);
|
| - String uuid;
|
| - String type;
|
| - uint64_t size;
|
| - ASSERT(!m_blobInfo);
|
| - if (!readWebCoreString(&uuid))
|
| - return false;
|
| - if (!readWebCoreString(&type))
|
| - return false;
|
| - if (!doReadUint64(&size))
|
| - return false;
|
| - blob = Blob::create(getOrCreateBlobDataHandle(uuid, type, size));
|
| - }
|
| - *value = ToV8(blob, m_scriptState->context()->Global(), isolate());
|
| - return !value->IsEmpty();
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readFile(v8::Local<v8::Value>* value,
|
| - bool isIndexed) {
|
| - File* file = nullptr;
|
| - if (isIndexed) {
|
| - if (m_version < 6)
|
| - return false;
|
| - file = readFileIndexHelper();
|
| - } else {
|
| - file = readFileHelper();
|
| - }
|
| - if (!file)
|
| - return false;
|
| - *value = ToV8(file, m_scriptState->context()->Global(), isolate());
|
| - return !value->IsEmpty();
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::readFileList(v8::Local<v8::Value>* value,
|
| - bool isIndexed) {
|
| - if (m_version < 3)
|
| - return false;
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - FileList* fileList = FileList::create();
|
| - for (unsigned i = 0; i < length; ++i) {
|
| - File* file = nullptr;
|
| - if (isIndexed) {
|
| - if (m_version < 6)
|
| - return false;
|
| - file = readFileIndexHelper();
|
| - } else {
|
| - file = readFileHelper();
|
| - }
|
| - if (!file)
|
| - return false;
|
| - fileList->append(file);
|
| - }
|
| - *value = ToV8(fileList, m_scriptState->context()->Global(), isolate());
|
| - return !value->IsEmpty();
|
| -}
|
| -
|
| -File* SerializedScriptValueReader::readFileHelper() {
|
| - if (m_version < 3)
|
| - return nullptr;
|
| - ASSERT(!m_blobInfo);
|
| - String path;
|
| - String name;
|
| - String relativePath;
|
| - String uuid;
|
| - String type;
|
| - uint32_t hasSnapshot = 0;
|
| - uint64_t size = 0;
|
| - double lastModifiedMS = 0;
|
| - if (!readWebCoreString(&path))
|
| - return nullptr;
|
| - if (m_version >= 4 && !readWebCoreString(&name))
|
| - return nullptr;
|
| - if (m_version >= 4 && !readWebCoreString(&relativePath))
|
| - return nullptr;
|
| - if (!readWebCoreString(&uuid))
|
| - return nullptr;
|
| - if (!readWebCoreString(&type))
|
| - return nullptr;
|
| - if (m_version >= 4 && !doReadUint32(&hasSnapshot))
|
| - return nullptr;
|
| - if (hasSnapshot) {
|
| - if (!doReadUint64(&size))
|
| - return nullptr;
|
| - if (!doReadNumber(&lastModifiedMS))
|
| - return nullptr;
|
| - if (m_version < 8)
|
| - lastModifiedMS *= msPerSecond;
|
| - }
|
| - uint32_t isUserVisible = 1;
|
| - if (m_version >= 7 && !doReadUint32(&isUserVisible))
|
| - return nullptr;
|
| - const File::UserVisibility userVisibility =
|
| - (isUserVisible > 0) ? File::IsUserVisible : File::IsNotUserVisible;
|
| - return File::createFromSerialization(path, name, relativePath, userVisibility,
|
| - hasSnapshot > 0, size, lastModifiedMS,
|
| - getOrCreateBlobDataHandle(uuid, type));
|
| -}
|
| -
|
| -File* SerializedScriptValueReader::readFileIndexHelper() {
|
| - if (m_version < 3)
|
| - return nullptr;
|
| - ASSERT(m_blobInfo);
|
| - uint32_t index;
|
| - if (!doReadUint32(&index) || index >= m_blobInfo->size())
|
| - return nullptr;
|
| - const WebBlobInfo& info = (*m_blobInfo)[index];
|
| - // FIXME: transition WebBlobInfo.lastModified to be milliseconds-based also.
|
| - double lastModifiedMS = info.lastModified() * msPerSecond;
|
| - return File::createFromIndexedSerialization(
|
| - info.filePath(), info.fileName(), info.size(), lastModifiedMS,
|
| - getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::doReadUint32(uint32_t* value) {
|
| - return doReadUintHelper(value);
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::doReadUint64(uint64_t* value) {
|
| - return doReadUintHelper(value);
|
| -}
|
| -
|
| -bool SerializedScriptValueReader::doReadNumber(double* number) {
|
| - if (m_position + sizeof(double) > m_length)
|
| - return false;
|
| - uint8_t* numberAsByteArray = reinterpret_cast<uint8_t*>(number);
|
| - for (unsigned i = 0; i < sizeof(double); ++i)
|
| - numberAsByteArray[i] = m_buffer[m_position++];
|
| - return true;
|
| -}
|
| -
|
| -PassRefPtr<BlobDataHandle>
|
| -SerializedScriptValueReader::getOrCreateBlobDataHandle(const String& uuid,
|
| - const String& type,
|
| - long long size) {
|
| - // The containing ssv may have a BDH for this uuid if this ssv is just being
|
| - // passed from main to worker thread (for example). We use those values when
|
| - // creating the new blob instead of cons'ing up a new BDH.
|
| - //
|
| - // FIXME: Maybe we should require that it work that way where the ssv must
|
| - // have a BDH for any blobs it comes across during deserialization. Would
|
| - // require callers to explicitly populate the collection of BDH's for blobs to
|
| - // work, which would encourage lifetimes to be considered when passing ssv's
|
| - // around cross process. At present, we get 'lucky' in some cases because the
|
| - // blob in the src process happens to still exist at the time the dest process
|
| - // is deserializing.
|
| - // For example in sharedWorker.postMessage(...).
|
| - BlobDataHandleMap::const_iterator it = m_blobDataHandles.find(uuid);
|
| - if (it != m_blobDataHandles.end()) {
|
| - // make assertions about type and size?
|
| - return it->value;
|
| - }
|
| - return BlobDataHandle::create(uuid, type, size);
|
| -}
|
| -
|
| -v8::Local<v8::Value> ScriptValueDeserializer::deserialize() {
|
| - v8::Isolate* isolate = m_reader.getScriptState()->isolate();
|
| - if (!m_reader.readVersion(m_version) ||
|
| - m_version > SerializedScriptValue::wireFormatVersion)
|
| - return v8::Null(isolate);
|
| - m_reader.setVersion(m_version);
|
| - v8::EscapableHandleScope scope(isolate);
|
| - while (!m_reader.isEof()) {
|
| - if (!doDeserialize())
|
| - return v8::Null(isolate);
|
| - }
|
| - if (stackDepth() != 1 || m_openCompositeReferenceStack.size())
|
| - return v8::Null(isolate);
|
| - v8::Local<v8::Value> result = scope.Escape(element(0));
|
| - return result;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::newSparseArray(uint32_t) {
|
| - v8::Local<v8::Array> array =
|
| - v8::Array::New(m_reader.getScriptState()->isolate(), 0);
|
| - openComposite(array);
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::newDenseArray(uint32_t length) {
|
| - v8::Local<v8::Array> array =
|
| - v8::Array::New(m_reader.getScriptState()->isolate(), length);
|
| - openComposite(array);
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::newMap() {
|
| - v8::Local<v8::Map> map = v8::Map::New(m_reader.getScriptState()->isolate());
|
| - openComposite(map);
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::newSet() {
|
| - v8::Local<v8::Set> set = v8::Set::New(m_reader.getScriptState()->isolate());
|
| - openComposite(set);
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::consumeTopOfStack(v8::Local<v8::Value>* object) {
|
| - if (stackDepth() < 1)
|
| - return false;
|
| - *object = element(stackDepth() - 1);
|
| - pop(1);
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::newObject() {
|
| - v8::Local<v8::Object> object =
|
| - v8::Object::New(m_reader.getScriptState()->isolate());
|
| - if (object.IsEmpty())
|
| - return false;
|
| - openComposite(object);
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::completeObject(uint32_t numProperties,
|
| - v8::Local<v8::Value>* value) {
|
| - v8::Local<v8::Object> object;
|
| - if (m_version > 0) {
|
| - v8::Local<v8::Value> composite;
|
| - if (!closeComposite(&composite))
|
| - return false;
|
| - object = composite.As<v8::Object>();
|
| - } else {
|
| - object = v8::Object::New(m_reader.getScriptState()->isolate());
|
| - }
|
| - if (object.IsEmpty())
|
| - return false;
|
| - return initializeObject(object, numProperties, value);
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::completeSparseArray(uint32_t numProperties,
|
| - uint32_t length,
|
| - v8::Local<v8::Value>* value) {
|
| - v8::Local<v8::Array> array;
|
| - if (m_version > 0) {
|
| - v8::Local<v8::Value> composite;
|
| - if (!closeComposite(&composite))
|
| - return false;
|
| - array = composite.As<v8::Array>();
|
| - } else {
|
| - array = v8::Array::New(m_reader.getScriptState()->isolate());
|
| - }
|
| - if (array.IsEmpty())
|
| - return false;
|
| - return initializeObject(array, numProperties, value);
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::completeDenseArray(uint32_t numProperties,
|
| - uint32_t length,
|
| - v8::Local<v8::Value>* value) {
|
| - v8::Local<v8::Array> array;
|
| - if (m_version > 0) {
|
| - v8::Local<v8::Value> composite;
|
| - if (!closeComposite(&composite))
|
| - return false;
|
| - array = composite.As<v8::Array>();
|
| - }
|
| - if (array.IsEmpty())
|
| - return false;
|
| - if (!initializeObject(array, numProperties, value))
|
| - return false;
|
| - if (length > stackDepth())
|
| - return false;
|
| - v8::Local<v8::Context> context = m_reader.getScriptState()->context();
|
| - for (unsigned i = 0, stackPos = stackDepth() - length; i < length;
|
| - i++, stackPos++) {
|
| - v8::Local<v8::Value> elem = element(stackPos);
|
| - if (!elem->IsUndefined()) {
|
| - if (!v8CallBoolean(array->CreateDataProperty(context, i, elem)))
|
| - return false;
|
| - }
|
| - }
|
| - pop(length);
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::completeMap(uint32_t length,
|
| - v8::Local<v8::Value>* value) {
|
| - ASSERT(m_version > 0);
|
| - v8::Local<v8::Value> composite;
|
| - if (!closeComposite(&composite))
|
| - return false;
|
| - v8::Local<v8::Map> map = composite.As<v8::Map>();
|
| - if (map.IsEmpty())
|
| - return false;
|
| - v8::Local<v8::Context> context = m_reader.getScriptState()->context();
|
| - ASSERT(length % 2 == 0);
|
| - for (unsigned i = stackDepth() - length; i + 1 < stackDepth(); i += 2) {
|
| - v8::Local<v8::Value> key = element(i);
|
| - v8::Local<v8::Value> val = element(i + 1);
|
| - if (map->Set(context, key, val).IsEmpty())
|
| - return false;
|
| - }
|
| - pop(length);
|
| - *value = map;
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::completeSet(uint32_t length,
|
| - v8::Local<v8::Value>* value) {
|
| - ASSERT(m_version > 0);
|
| - v8::Local<v8::Value> composite;
|
| - if (!closeComposite(&composite))
|
| - return false;
|
| - v8::Local<v8::Set> set = composite.As<v8::Set>();
|
| - if (set.IsEmpty())
|
| - return false;
|
| - v8::Local<v8::Context> context = m_reader.getScriptState()->context();
|
| - for (unsigned i = stackDepth() - length; i < stackDepth(); i++) {
|
| - v8::Local<v8::Value> key = element(i);
|
| - if (set->Add(context, key).IsEmpty())
|
| - return false;
|
| - }
|
| - pop(length);
|
| - *value = set;
|
| - return true;
|
| -}
|
| -
|
| -void ScriptValueDeserializer::pushObjectReference(
|
| - const v8::Local<v8::Value>& object) {
|
| - m_objectPool.push_back(object);
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::tryGetTransferredMessagePort(
|
| - uint32_t index,
|
| - v8::Local<v8::Value>* object) {
|
| - if (!m_transferredMessagePorts)
|
| - return false;
|
| - if (index >= m_transferredMessagePorts->size())
|
| - return false;
|
| - v8::Local<v8::Object> creationContext =
|
| - m_reader.getScriptState()->context()->Global();
|
| - *object = ToV8(m_transferredMessagePorts->at(index).get(), creationContext,
|
| - m_reader.getScriptState()->isolate());
|
| - return !object->IsEmpty();
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::tryGetTransferredArrayBuffer(
|
| - uint32_t index,
|
| - v8::Local<v8::Value>* object) {
|
| - if (!m_arrayBufferContents)
|
| - return false;
|
| - if (index >= m_arrayBuffers.size())
|
| - return false;
|
| - v8::Local<v8::Value> result = m_arrayBuffers.at(index);
|
| - if (result.IsEmpty()) {
|
| - DOMArrayBuffer* buffer =
|
| - DOMArrayBuffer::create(m_arrayBufferContents->at(index));
|
| - v8::Isolate* isolate = m_reader.getScriptState()->isolate();
|
| - v8::Local<v8::Object> creationContext =
|
| - m_reader.getScriptState()->context()->Global();
|
| - result = ToV8(buffer, creationContext, isolate);
|
| - if (result.IsEmpty())
|
| - return false;
|
| - m_arrayBuffers[index] = result;
|
| - }
|
| - *object = result;
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::tryGetTransferredImageBitmap(
|
| - uint32_t index,
|
| - v8::Local<v8::Value>* object) {
|
| - if (!m_imageBitmapContents)
|
| - return false;
|
| - if (index >= m_imageBitmaps.size())
|
| - return false;
|
| - v8::Local<v8::Value> result = m_imageBitmaps.at(index);
|
| - if (result.IsEmpty()) {
|
| - ImageBitmap* bitmap = ImageBitmap::create(m_imageBitmapContents->at(index));
|
| - v8::Isolate* isolate = m_reader.getScriptState()->isolate();
|
| - v8::Local<v8::Object> creationContext =
|
| - m_reader.getScriptState()->context()->Global();
|
| - result = ToV8(bitmap, creationContext, isolate);
|
| - if (result.IsEmpty())
|
| - return false;
|
| - m_imageBitmaps[index] = result;
|
| - }
|
| - *object = result;
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::tryGetTransferredSharedArrayBuffer(
|
| - uint32_t index,
|
| - v8::Local<v8::Value>* object) {
|
| - ASSERT(RuntimeEnabledFeatures::sharedArrayBufferEnabled());
|
| - if (!m_arrayBufferContents)
|
| - return false;
|
| - if (index >= m_arrayBuffers.size())
|
| - return false;
|
| - v8::Local<v8::Value> result = m_arrayBuffers.at(index);
|
| - if (result.IsEmpty()) {
|
| - DOMSharedArrayBuffer* buffer =
|
| - DOMSharedArrayBuffer::create(m_arrayBufferContents->at(index));
|
| - v8::Isolate* isolate = m_reader.getScriptState()->isolate();
|
| - v8::Local<v8::Object> creationContext =
|
| - m_reader.getScriptState()->context()->Global();
|
| - result = ToV8(buffer, creationContext, isolate);
|
| - if (result.IsEmpty())
|
| - return false;
|
| - m_arrayBuffers[index] = result;
|
| - }
|
| - *object = result;
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::tryGetTransferredOffscreenCanvas(
|
| - uint32_t width,
|
| - uint32_t height,
|
| - uint32_t canvasId,
|
| - uint32_t clientId,
|
| - uint32_t sinkId,
|
| - v8::Local<v8::Value>* object) {
|
| - OffscreenCanvas* offscreenCanvas = OffscreenCanvas::create(width, height);
|
| - offscreenCanvas->setPlaceholderCanvasId(canvasId);
|
| - offscreenCanvas->setFrameSinkId(clientId, sinkId);
|
| - *object = ToV8(offscreenCanvas, m_reader.getScriptState());
|
| - if ((*object).IsEmpty())
|
| - return false;
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::tryGetObjectFromObjectReference(
|
| - uint32_t reference,
|
| - v8::Local<v8::Value>* object) {
|
| - if (reference >= m_objectPool.size())
|
| - return false;
|
| - *object = m_objectPool[reference];
|
| - return object;
|
| -}
|
| -
|
| -uint32_t ScriptValueDeserializer::objectReferenceCount() {
|
| - return m_objectPool.size();
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::initializeObject(v8::Local<v8::Object> object,
|
| - uint32_t numProperties,
|
| - v8::Local<v8::Value>* value) {
|
| - unsigned length = 2 * numProperties;
|
| - if (length > stackDepth())
|
| - return false;
|
| - v8::Local<v8::Context> context = m_reader.getScriptState()->context();
|
| - for (unsigned i = stackDepth() - length; i < stackDepth(); i += 2) {
|
| - v8::Local<v8::Value> propertyName = element(i);
|
| - v8::Local<v8::Value> propertyValue = element(i + 1);
|
| - bool result = false;
|
| - if (propertyName->IsString())
|
| - result = v8CallBoolean(object->CreateDataProperty(
|
| - context, propertyName.As<v8::String>(), propertyValue));
|
| - else if (propertyName->IsUint32())
|
| - result = v8CallBoolean(object->CreateDataProperty(
|
| - context, propertyName.As<v8::Uint32>()->Value(), propertyValue));
|
| - else
|
| - ASSERT_NOT_REACHED();
|
| - if (!result)
|
| - return false;
|
| - }
|
| - pop(length);
|
| - *value = object;
|
| - return true;
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::read(v8::Local<v8::Value>* value) {
|
| - return m_reader.read(value, *this);
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::doDeserialize() {
|
| - v8::Local<v8::Value> value;
|
| - if (!read(&value))
|
| - return false;
|
| - if (!value.IsEmpty())
|
| - push(value);
|
| - return true;
|
| -}
|
| -
|
| -v8::Local<v8::Value> ScriptValueDeserializer::element(unsigned index) {
|
| - SECURITY_DCHECK(index < m_stack.size());
|
| - return m_stack[index];
|
| -}
|
| -
|
| -void ScriptValueDeserializer::openComposite(
|
| - const v8::Local<v8::Value>& object) {
|
| - uint32_t newObjectReference = m_objectPool.size();
|
| - m_openCompositeReferenceStack.push_back(newObjectReference);
|
| - m_objectPool.push_back(object);
|
| -}
|
| -
|
| -bool ScriptValueDeserializer::closeComposite(v8::Local<v8::Value>* object) {
|
| - if (!m_openCompositeReferenceStack.size())
|
| - return false;
|
| - uint32_t objectReference =
|
| - m_openCompositeReferenceStack[m_openCompositeReferenceStack.size() - 1];
|
| - m_openCompositeReferenceStack.shrink(m_openCompositeReferenceStack.size() -
|
| - 1);
|
| - if (objectReference >= m_objectPool.size())
|
| - return false;
|
| - *object = m_objectPool[objectReference];
|
| - return true;
|
| -}
|
| -
|
| -} // namespace blink
|
|
|