blob: 533373c16919b4e7419ac0d80c6a0a61c5c40a78 [file] [log] [blame]
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "UserData.h"
#include "APIArray.h"
#include "APIData.h"
#include "APIDictionary.h"
#include "APIError.h"
#include "APIFrameHandle.h"
#include "APIGeometry.h"
#include "APINumber.h"
#include "APIPageGroupHandle.h"
#include "APIPageHandle.h"
#include "APISerializedScriptValue.h"
#include "APIString.h"
#include "APIURL.h"
#include "APIURLRequest.h"
#include "APIURLResponse.h"
#include "APIUserContentURLPattern.h"
#include "ArgumentCoders.h"
#include "Encoder.h"
#include "ShareableBitmap.h"
#include "WebCertificateInfo.h"
#include "WebImage.h"
#include "WebRenderLayer.h"
#include "WebRenderObject.h"
#if PLATFORM(COCOA)
#include "ObjCObjectGraph.h"
#endif
namespace WebKit {
UserData::UserData()
{
}
UserData::UserData(RefPtr<API::Object>&& object)
: m_object(WTFMove(object))
{
}
UserData::~UserData()
{
}
static bool shouldTransform(const API::Object& object, const UserData::Transformer& transformer)
{
if (object.type() == API::Object::Type::Array) {
const auto& array = static_cast<const API::Array&>(object);
for (const auto& element : array.elements()) {
if (!element)
continue;
if (shouldTransform(*element, transformer))
return true;
}
}
if (object.type() == API::Object::Type::Dictionary) {
const auto& dictionary = static_cast<const API::Dictionary&>(object);
for (const auto& keyValuePair : dictionary.map()) {
if (!keyValuePair.value)
continue;
if (shouldTransform(*keyValuePair.value, transformer))
return true;
}
}
return transformer.shouldTransformObject(object);
}
static RefPtr<API::Object> transformGraph(API::Object& object, const UserData::Transformer& transformer)
{
if (object.type() == API::Object::Type::Array) {
auto& array = static_cast<API::Array&>(object);
Vector<RefPtr<API::Object>> elements;
elements.reserveInitialCapacity(array.elements().size());
for (const auto& element : array.elements()) {
if (!element)
elements.uncheckedAppend(nullptr);
else
elements.uncheckedAppend(transformGraph(*element, transformer));
}
return API::Array::create(WTFMove(elements));
}
if (object.type() == API::Object::Type::Dictionary) {
auto& dictionary = static_cast<API::Dictionary&>(object);
API::Dictionary::MapType map;
for (const auto& keyValuePair : dictionary.map()) {
if (!keyValuePair.value)
map.add(keyValuePair.key, nullptr);
else
map.add(keyValuePair.key, transformGraph(*keyValuePair.value, transformer));
}
return API::Dictionary::create(WTFMove(map));
}
return transformer.transformObject(object);
}
RefPtr<API::Object> UserData::transform(API::Object* object, const Transformer& transformer)
{
if (!object)
return nullptr;
if (!shouldTransform(*object, transformer))
return object;
return transformGraph(*object, transformer);
}
void UserData::encode(IPC::Encoder& encoder) const
{
encode(encoder, m_object.get());
}
bool UserData::decode(IPC::Decoder& decoder, UserData& userData)
{
return decode(decoder, userData.m_object);
}
void UserData::encode(IPC::Encoder& encoder, const API::Object* object)
{
if (!object) {
encoder.encodeEnum(API::Object::Type::Null);
return;
}
encode(encoder, *object);
}
void UserData::encode(IPC::Encoder& encoder, const API::Object& object)
{
API::Object::Type type = object.type();
encoder.encodeEnum(type);
switch (object.type()) {
case API::Object::Type::Array: {
auto& array = static_cast<const API::Array&>(object);
encoder << static_cast<uint64_t>(array.size());
for (size_t i = 0; i < array.size(); ++i)
encode(encoder, array.at(i));
break;
}
case API::Object::Type::Boolean:
static_cast<const API::Boolean&>(object).encode(encoder);
break;
case API::Object::Type::CertificateInfo: {
const auto& certificateInfo = static_cast<const WebCertificateInfo&>(object);
encoder << certificateInfo.certificateInfo();
break;
}
case API::Object::Type::Data:
static_cast<const API::Data&>(object).encode(encoder);
break;
case API::Object::Type::Dictionary: {
auto& dictionary = static_cast<const API::Dictionary&>(object);
auto& map = dictionary.map();
encoder << static_cast<uint64_t>(map.size());
for (const auto& keyValuePair : map) {
encoder << keyValuePair.key;
encode(encoder, keyValuePair.value.get());
}
break;
}
case API::Object::Type::Double:
static_cast<const API::Double&>(object).encode(encoder);
break;
case API::Object::Type::Error:
static_cast<const API::Error&>(object).encode(encoder);
break;
case API::Object::Type::FrameHandle:
static_cast<const API::FrameHandle&>(object).encode(encoder);
break;
case API::Object::Type::Image: {
auto& image = static_cast<const WebImage&>(object);
ShareableBitmap::Handle handle;
ASSERT(image.bitmap().isBackedBySharedMemory());
if (!image.bitmap().isBackedBySharedMemory() || !image.bitmap().createHandle(handle)) {
// Initial false indicates no allocated bitmap or is not shareable.
encoder << false;
break;
}
// Initial true indicates a bitmap was allocated and is shareable.
encoder << true;
encoder << handle;
break;
}
case API::Object::Type::PageGroupHandle:
static_cast<const API::PageGroupHandle&>(object).encode(encoder);
break;
case API::Object::Type::PageHandle:
static_cast<const API::PageHandle&>(object).encode(encoder);
break;
case API::Object::Type::Point:
static_cast<const API::Point&>(object).encode(encoder);
break;
case API::Object::Type::Rect:
static_cast<const API::Rect&>(object).encode(encoder);
break;
case API::Object::Type::RenderLayer: {
auto& renderLayer = static_cast<const WebRenderLayer&>(object);
encode(encoder, renderLayer.renderer());
encoder << renderLayer.isReflection();
encoder << renderLayer.isClipping();
encoder << renderLayer.isClipped();
encoder << static_cast<uint32_t>(renderLayer.compositingLayerType());
encoder << renderLayer.absoluteBoundingBox();
encoder << renderLayer.backingStoreMemoryEstimate();
encode(encoder, renderLayer.negativeZOrderList());
encode(encoder, renderLayer.normalFlowList());
encode(encoder, renderLayer.positiveZOrderList());
encode(encoder, renderLayer.frameContentsLayer());
break;
}
case API::Object::Type::RenderObject: {
auto& renderObject = static_cast<const WebRenderObject&>(object);
encoder << renderObject.name();
encoder << renderObject.elementTagName();
encoder << renderObject.elementID();
encode(encoder, renderObject.elementClassNames());
encoder << renderObject.absolutePosition();
encoder << renderObject.frameRect();
encoder << renderObject.textSnippet();
encoder << renderObject.textLength();
encode(encoder, renderObject.children());
break;
}
case API::Object::Type::SerializedScriptValue: {
auto& serializedScriptValue = static_cast<const API::SerializedScriptValue&>(object);
encoder << serializedScriptValue.dataReference();
break;
}
case API::Object::Type::Size:
static_cast<const API::Size&>(object).encode(encoder);
break;
case API::Object::Type::String: {
auto& string = static_cast<const API::String&>(object);
encoder << string.string();
break;
}
case API::Object::Type::URL:
static_cast<const API::URL&>(object).encode(encoder);
break;
case API::Object::Type::URLRequest:
static_cast<const API::URLRequest&>(object).encode(encoder);
break;
case API::Object::Type::URLResponse:
static_cast<const API::URLResponse&>(object).encode(encoder);
break;
case API::Object::Type::UInt64:
static_cast<const API::UInt64&>(object).encode(encoder);
break;
case API::Object::Type::UserContentURLPattern: {
auto& urlPattern = static_cast<const API::UserContentURLPattern&>(object);
encoder << urlPattern.patternString();
break;
}
#if PLATFORM(COCOA)
case API::Object::Type::ObjCObjectGraph:
static_cast<const ObjCObjectGraph&>(object).encode(encoder);
break;
#endif
default:
ASSERT_NOT_REACHED();
}
}
bool UserData::decode(IPC::Decoder& decoder, RefPtr<API::Object>& result)
{
API::Object::Type type;
if (!decoder.decodeEnum(type))
return false;
switch (type) {
case API::Object::Type::Array: {
uint64_t size;
if (!decoder.decode(size))
return false;
Vector<RefPtr<API::Object>> elements;
for (size_t i = 0; i < size; ++i) {
RefPtr<API::Object> element;
if (!decode(decoder, element))
return false;
elements.append(WTFMove(element));
}
result = API::Array::create(WTFMove(elements));
break;
}
case API::Object::Type::Boolean:
if (!API::Boolean::decode(decoder, result))
return false;
break;
case API::Object::Type::CertificateInfo: {
WebCore::CertificateInfo certificateInfo;
if (!decoder.decode(certificateInfo))
return false;
result = WebCertificateInfo::create(certificateInfo);
break;
}
case API::Object::Type::Data:
if (!API::Data::decode(decoder, result))
return false;
break;
case API::Object::Type::Dictionary: {
uint64_t size;
if (!decoder.decode(size))
return false;
API::Dictionary::MapType map;
for (size_t i = 0; i < size; ++i) {
String key;
if (!decoder.decode(key))
return false;
RefPtr<API::Object> value;
if (!decode(decoder, value))
return false;
if (!map.add(WTFMove(key), WTFMove(value)).isNewEntry)
return false;
}
result = API::Dictionary::create(WTFMove(map));
break;
}
case API::Object::Type::Double:
if (!API::Double::decode(decoder, result))
return false;
break;
case API::Object::Type::Error:
if (!API::Error::decode(decoder, result))
return false;
break;
case API::Object::Type::FrameHandle:
if (!API::FrameHandle::decode(decoder, result))
return false;
break;
case API::Object::Type::Image: {
bool didEncode = false;
if (!decoder.decode(didEncode))
return false;
if (!didEncode)
break;
ShareableBitmap::Handle handle;
if (!decoder.decode(handle))
return false;
auto bitmap = ShareableBitmap::create(handle);
if (!bitmap)
return false;
result = WebImage::create(bitmap.releaseNonNull());
break;
}
case API::Object::Type::Null:
result = nullptr;
break;
case API::Object::Type::PageGroupHandle:
if (!API::PageGroupHandle::decode(decoder, result))
return false;
break;
case API::Object::Type::PageHandle:
if (!API::PageHandle::decode(decoder, result))
return false;
break;
case API::Object::Type::Point:
if (!API::Point::decode(decoder, result))
return false;
break;
case API::Object::Type::Rect:
if (!API::Rect::decode(decoder, result))
return false;
break;
case API::Object::Type::RenderLayer: {
RefPtr<API::Object> renderer;
bool isReflection;
bool isClipping;
bool isClipped;
uint32_t compositingLayerTypeAsUInt32;
WebCore::IntRect absoluteBoundingBox;
double backingStoreMemoryEstimate;
RefPtr<API::Object> negativeZOrderList;
RefPtr<API::Object> normalFlowList;
RefPtr<API::Object> positiveZOrderList;
RefPtr<API::Object> frameContentsLayer;
if (!decode(decoder, renderer))
return false;
if (renderer->type() != API::Object::Type::RenderObject)
return false;
if (!decoder.decode(isReflection))
return false;
if (!decoder.decode(isClipping))
return false;
if (!decoder.decode(isClipped))
return false;
if (!decoder.decode(compositingLayerTypeAsUInt32))
return false;
if (!decoder.decode(absoluteBoundingBox))
return false;
if (!decoder.decode(backingStoreMemoryEstimate))
return false;
if (!decode(decoder, negativeZOrderList))
return false;
if (!decode(decoder, normalFlowList))
return false;
if (!decode(decoder, positiveZOrderList))
return false;
if (!decode(decoder, frameContentsLayer))
return false;
result = WebRenderLayer::create(static_pointer_cast<WebRenderObject>(renderer), isReflection, isClipping, isClipped, static_cast<WebRenderLayer::CompositingLayerType>(compositingLayerTypeAsUInt32), absoluteBoundingBox, backingStoreMemoryEstimate, static_pointer_cast<API::Array>(negativeZOrderList), static_pointer_cast<API::Array>(normalFlowList), static_pointer_cast<API::Array>(positiveZOrderList), static_pointer_cast<WebRenderLayer>(frameContentsLayer));
break;
}
case API::Object::Type::RenderObject: {
String name;
String textSnippet;
String elementTagName;
String elementID;
unsigned textLength;
RefPtr<API::Object> elementClassNames;
WebCore::IntPoint absolutePosition;
WebCore::IntRect frameRect;
RefPtr<API::Object> children;
if (!decoder.decode(name))
return false;
if (!decoder.decode(elementTagName))
return false;
if (!decoder.decode(elementID))
return false;
if (!decode(decoder, elementClassNames))
return false;
if (!decoder.decode(absolutePosition))
return false;
if (!decoder.decode(frameRect))
return false;
if (!decoder.decode(textSnippet))
return false;
if (!decoder.decode(textLength))
return false;
if (!decode(decoder, children))
return false;
if (children && children->type() != API::Object::Type::Array)
return false;
result = WebRenderObject::create(name, elementTagName, elementID, static_pointer_cast<API::Array>(elementClassNames), absolutePosition, frameRect, textSnippet, textLength, static_pointer_cast<API::Array>(children));
break;
}
case API::Object::Type::SerializedScriptValue: {
IPC::DataReference dataReference;
if (!decoder.decode(dataReference))
return false;
result = API::SerializedScriptValue::adopt(dataReference.vector());
break;
}
case API::Object::Type::Size:
if (!API::Size::decode(decoder, result))
return false;
break;
case API::Object::Type::String: {
String string;
if (!decoder.decode(string))
return false;
result = API::String::create(string);
break;
}
case API::Object::Type::URL:
if (!API::URL::decode(decoder, result))
return false;
break;
case API::Object::Type::URLRequest:
if (!API::URLRequest::decode(decoder, result))
return false;
break;
case API::Object::Type::URLResponse:
if (!API::URLResponse::decode(decoder, result))
return false;
break;
case API::Object::Type::UInt64:
if (!API::UInt64::decode(decoder, result))
return false;
break;
case API::Object::Type::UserContentURLPattern: {
String string;
if (!decoder.decode(string))
return false;
result = API::UserContentURLPattern::create(string);
break;
}
#if PLATFORM(COCOA)
case API::Object::Type::ObjCObjectGraph:
if (!ObjCObjectGraph::decode(decoder, result))
return false;
break;
#endif
default:
ASSERT_NOT_REACHED();
}
return true;
}
} // namespace WebKit