blob: bf51c07e7a95a71dacae0cd886afa27f6c2c109b [file] [log] [blame]
/*
* Copyright (C) 2012 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.
*/
#import "config.h"
#import "ObjCObjectGraphCoders.h"
#import "ArgumentCodersMac.h"
#import "WKTypeRefWrapper.h"
// For UIProcess side encoding/decoding
#import "WKAPICast.h"
#import "WKBrowsingContextControllerInternal.h"
#import "WebContextUserMessageCoders.h"
#import "WebPageProxy.h"
#import "WebProcessProxy.h"
// For WebProcess side encoding/decoding
#import "InjectedBundleUserMessageCoders.h"
#import "WKBundleAPICast.h"
#import "WKWebProcessPlugInBrowserContextControllerInternal.h"
#import "WKWebProcessPlugInInternal.h"
#import "WebPage.h"
#import "WebProcess.h"
namespace WebKit {
enum WebKitNSType {
NullType,
NSDictionaryType,
NSArrayType,
NSStringType,
NSNumberType,
NSDateType,
NSDataType,
#if WK_API_ENABLED
WKBrowsingContextControllerType,
WKTypeRefWrapperType,
#endif
UnknownType,
};
static WebKitNSType typeFromObject(id object)
{
ASSERT(object);
if ([object isKindOfClass:[NSDictionary class]])
return NSDictionaryType;
if ([object isKindOfClass:[NSString class]])
return NSStringType;
if ([object isKindOfClass:[NSArray class]])
return NSArrayType;
if ([object isKindOfClass:[NSNumber class]])
return NSNumberType;
if ([object isKindOfClass:[NSDate class]])
return NSDateType;
if ([object isKindOfClass:[NSData class]])
return NSDataType;
#if WK_API_ENABLED
if ([object isKindOfClass:[WKBrowsingContextController class]] || [object isKindOfClass:[WKWebProcessPlugInBrowserContextController class]])
return WKBrowsingContextControllerType;
if ([object isKindOfClass:[WKTypeRefWrapper class]])
return WKTypeRefWrapperType;
#endif
return UnknownType;
}
template<typename Owner>
class ObjCObjectGraphEncoder {
public:
bool baseEncode(IPC::ArgumentEncoder& encoder, const Owner& coder, WebKitNSType& type) const
{
if (!m_root) {
encoder << static_cast<uint32_t>(NullType);
return true;
}
type = typeFromObject(m_root);
if (type == UnknownType) {
[NSException raise:NSInvalidArgumentException format:@"Can not encode objects of class type '%@'", static_cast<NSString *>(NSStringFromClass([m_root class]))];
}
encoder << static_cast<uint32_t>(type);
switch (type) {
case NSStringType: {
IPC::encode(encoder, static_cast<NSString *>(m_root));
return true;
}
case NSArrayType: {
NSArray *array = static_cast<NSArray *>(m_root);
NSUInteger size = [array count];
encoder << static_cast<uint64_t>(size);
for (NSUInteger i = 0; i < size; ++i)
encoder << Owner(coder, [array objectAtIndex:i]);
return true;
}
case NSDictionaryType: {
NSDictionary* dictionary = static_cast<NSDictionary *>(m_root);
NSUInteger size = [dictionary count];
encoder << static_cast<uint64_t>(size);
NSArray *keys = [dictionary allKeys];
NSArray *values = [dictionary allValues];
for (NSUInteger i = 0; i < size; ++i) {
encoder << Owner(coder, [keys objectAtIndex:i]);
encoder << Owner(coder, [values objectAtIndex:i]);
}
return true;
}
case NSNumberType: {
IPC::encode(encoder, static_cast<NSNumber *>(m_root));
return true;
}
case NSDateType: {
IPC::encode(encoder, static_cast<NSDate *>(m_root));
return true;
}
case NSDataType: {
IPC::encode(encoder, static_cast<NSData *>(m_root));
return true;
}
default:
break;
}
return false;
}
protected:
ObjCObjectGraphEncoder(id root)
: m_root(root)
{
}
id m_root;
};
template<typename Owner>
class ObjCObjectGraphDecoder {
public:
static bool baseDecode(IPC::ArgumentDecoder& decoder, Owner& coder, WebKitNSType& type)
{
uint32_t typeAsUInt32;
if (!decoder.decode(typeAsUInt32))
return false;
type = static_cast<WebKitNSType>(typeAsUInt32);
switch (type) {
case NSStringType: {
RetainPtr<NSString> string;
if (!IPC::decode(decoder, string))
return false;
coder.m_root = string;
break;
}
case NSArrayType: {
uint64_t size;
if (!decoder.decode(size))
return false;
RetainPtr<NSMutableArray> array = adoptNS([[NSMutableArray alloc] initWithCapacity:size]);
for (uint64_t i = 0; i < size; ++i) {
RetainPtr<id> value;
Owner messageCoder(coder, value);
if (!decoder.decode(messageCoder))
return false;
[array addObject:value.get()];
}
coder.m_root = array;
break;
}
case NSDictionaryType: {
uint64_t size;
if (!decoder.decode(size))
return false;
RetainPtr<NSMutableDictionary> dictionary = adoptNS([[NSMutableDictionary alloc] initWithCapacity:size]);
for (uint64_t i = 0; i < size; ++i) {
// Try to decode the key name.
RetainPtr<id> key;
Owner keyMessageCoder(coder, key);
if (!decoder.decode(keyMessageCoder))
return false;
RetainPtr<id> value;
Owner valueMessageCoder(coder, value);
if (!decoder.decode(valueMessageCoder))
return false;
[dictionary setObject:value.get() forKey:key.get()];
}
coder.m_root = dictionary;
break;
}
case NSNumberType: {
RetainPtr<NSNumber> number;
if (!IPC::decode(decoder, number))
return false;
coder.m_root = number;
break;
}
case NSDateType: {
RetainPtr<NSDate> date;
if (!IPC::decode(decoder, date))
return false;
coder.m_root = date;
break;
}
case NSDataType: {
RetainPtr<NSData> data;
if (!IPC::decode(decoder, data))
return false;
coder.m_root = data;
break;
}
default:
break;
}
return true;
}
protected:
ObjCObjectGraphDecoder(RetainPtr<id>& root)
: m_root(root)
{
}
RetainPtr<id>& m_root;
};
// WebContext Additions
class WebContextObjCObjectGraphEncoderImpl : public ObjCObjectGraphEncoder<WebContextObjCObjectGraphEncoderImpl> {
public:
typedef ObjCObjectGraphEncoder<WebContextObjCObjectGraphEncoderImpl> Base;
explicit WebContextObjCObjectGraphEncoderImpl(id root, WebProcessProxy& process)
: Base(root)
, m_process(process)
{
}
WebContextObjCObjectGraphEncoderImpl(const WebContextObjCObjectGraphEncoderImpl& userMessageEncoder, id root)
: Base(root)
, m_process(userMessageEncoder.m_process)
{
}
void encode(IPC::ArgumentEncoder& encoder) const
{
WebKitNSType type = NullType;
if (baseEncode(encoder, *this, type))
return;
switch (type) {
#if WK_API_ENABLED
case WKBrowsingContextControllerType: {
WKBrowsingContextController *browsingContextController = static_cast<WKBrowsingContextController *>(m_root);
encoder << toImpl(browsingContextController._pageRef)->pageID();
break;
}
case WKTypeRefWrapperType: {
WKTypeRefWrapper *wrapper = static_cast<WKTypeRefWrapper *>(m_root);
encoder << WebContextUserMessageEncoder(toImpl(wrapper.object), m_process);
break;
}
#endif
default:
ASSERT_NOT_REACHED();
break;
}
}
private:
WebProcessProxy& m_process;
};
class WebContextObjCObjectGraphDecoderImpl : public ObjCObjectGraphDecoder<WebContextObjCObjectGraphDecoderImpl> {
public:
typedef ObjCObjectGraphDecoder<WebContextObjCObjectGraphDecoderImpl> Base;
WebContextObjCObjectGraphDecoderImpl(RetainPtr<id>& root, WebProcessProxy& process)
: Base(root)
, m_process(process)
{
}
WebContextObjCObjectGraphDecoderImpl(WebContextObjCObjectGraphDecoderImpl& userMessageDecoder, RetainPtr<id>& root)
: Base(root)
, m_process(userMessageDecoder.m_process)
{
}
static bool decode(IPC::ArgumentDecoder& decoder, WebContextObjCObjectGraphDecoderImpl& coder)
{
WebKitNSType type = NullType;
if (!Base::baseDecode(decoder, coder, type))
return false;
if (coder.m_root)
return true;
if (type == NullType || type == UnknownType) {
coder.m_root = [NSNull null];
return true;
}
switch (type) {
#if WK_API_ENABLED
case WKBrowsingContextControllerType: {
uint64_t pageID;
if (!decoder.decode(pageID))
return false;
WebPageProxy* webPage = coder.m_process.webPage(pageID);
if (!webPage)
coder.m_root = [NSNull null];
else
coder.m_root = [WKBrowsingContextController _browsingContextControllerForPageRef:toAPI(webPage)];
break;
}
case WKTypeRefWrapperType: {
RefPtr<API::Object> object;
WebContextUserMessageDecoder objectDecoder(object, coder.m_process);
if (!decoder.decode(objectDecoder))
return false;
coder.m_root = adoptNS([[WKTypeRefWrapper alloc] initWithObject:toAPI(object.get())]);
break;
}
#endif
default:
return false;
}
return true;
}
private:
WebProcessProxy& m_process;
};
// InjectedBundle Additions
class InjectedBundleObjCObjectGraphEncoderImpl : public ObjCObjectGraphEncoder<InjectedBundleObjCObjectGraphEncoderImpl> {
public:
typedef ObjCObjectGraphEncoder<InjectedBundleObjCObjectGraphEncoderImpl> Base;
explicit InjectedBundleObjCObjectGraphEncoderImpl(id root, WebProcess& process)
: Base(root)
, m_process(process)
{
}
explicit InjectedBundleObjCObjectGraphEncoderImpl(const InjectedBundleObjCObjectGraphEncoderImpl& encoder, id root)
: Base(root)
, m_process(encoder.m_process)
{
}
void encode(IPC::ArgumentEncoder& encoder) const
{
WebKitNSType type = NullType;
if (baseEncode(encoder, *this, type))
return;
switch (type) {
#if WK_API_ENABLED
case WKBrowsingContextControllerType: {
WKWebProcessPlugInBrowserContextController *browserContextController = static_cast<WKWebProcessPlugInBrowserContextController *>(m_root);
encoder << toImpl(browserContextController._bundlePageRef)->pageID();
break;
}
case WKTypeRefWrapperType: {
WKTypeRefWrapper *wrapper = static_cast<WKTypeRefWrapper *>(m_root);
encoder << InjectedBundleUserMessageEncoder(toImpl(wrapper.object));
}
#endif
default:
ASSERT_NOT_REACHED();
break;
}
}
private:
WebProcess& m_process;
};
class InjectedBundleObjCObjectGraphDecoderImpl : public ObjCObjectGraphDecoder<InjectedBundleObjCObjectGraphDecoderImpl> {
public:
typedef ObjCObjectGraphDecoder<InjectedBundleObjCObjectGraphDecoderImpl> Base;
InjectedBundleObjCObjectGraphDecoderImpl(RetainPtr<id>& root, WebProcess& process)
: Base(root)
, m_process(process)
{
}
InjectedBundleObjCObjectGraphDecoderImpl(InjectedBundleObjCObjectGraphDecoderImpl& userMessageDecoder, RetainPtr<id>& root)
: Base(root)
, m_process(userMessageDecoder.m_process)
{
}
static bool decode(IPC::ArgumentDecoder& decoder, InjectedBundleObjCObjectGraphDecoderImpl& coder)
{
WebKitNSType type = NullType;
if (!Base::baseDecode(decoder, coder, type))
return false;
if (coder.m_root)
return true;
if (type == NullType || type == UnknownType) {
coder.m_root = [NSNull null];
return true;
}
switch (type) {
#if WK_API_ENABLED
case WKBrowsingContextControllerType: {
uint64_t pageID;
if (!decoder.decode(pageID))
return false;
WebPage* webPage = coder.m_process.webPage(pageID);
if (!webPage)
coder.m_root = [NSNull null];
else
coder.m_root = wrapper(*webPage);
break;
}
case WKTypeRefWrapperType: {
RefPtr<API::Object> object;
InjectedBundleUserMessageDecoder objectDecoder(object);
if (!decoder.decode(objectDecoder))
return false;
coder.m_root = adoptNS([[WKTypeRefWrapper alloc] initWithObject:toAPI(object.get())]);
break;
}
#endif
default:
return false;
}
return true;
}
private:
WebProcess& m_process;
};
// Adaptors
WebContextObjCObjectGraphEncoder::WebContextObjCObjectGraphEncoder(ObjCObjectGraph* objectGraph, WebProcessProxy& process)
: m_objectGraph(objectGraph)
, m_process(process)
{
}
void WebContextObjCObjectGraphEncoder::encode(IPC::ArgumentEncoder& encoder) const
{
encoder << WebContextObjCObjectGraphEncoderImpl(m_objectGraph->rootObject(), m_process);
}
WebContextObjCObjectGraphDecoder::WebContextObjCObjectGraphDecoder(RefPtr<ObjCObjectGraph>& objectGraph, WebProcessProxy& process)
: m_objectGraph(objectGraph)
, m_process(process)
{
}
bool WebContextObjCObjectGraphDecoder::decode(IPC::ArgumentDecoder& decoder, WebContextObjCObjectGraphDecoder& coder)
{
RetainPtr<id> root;
WebContextObjCObjectGraphDecoderImpl coderImpl(root, coder.m_process);
if (!decoder.decode(coderImpl))
return false;
coder.m_objectGraph = ObjCObjectGraph::create(root.get());
return true;
}
InjectedBundleObjCObjectGraphEncoder::InjectedBundleObjCObjectGraphEncoder(ObjCObjectGraph* objectGraph, WebProcess& process)
: m_objectGraph(objectGraph)
, m_process(process)
{
}
void InjectedBundleObjCObjectGraphEncoder::encode(IPC::ArgumentEncoder& encoder) const
{
encoder << InjectedBundleObjCObjectGraphEncoderImpl(m_objectGraph->rootObject(), m_process);
}
InjectedBundleObjCObjectGraphDecoder::InjectedBundleObjCObjectGraphDecoder(RefPtr<ObjCObjectGraph>& objectGraph, WebProcess& process)
: m_objectGraph(objectGraph)
, m_process(process)
{
}
bool InjectedBundleObjCObjectGraphDecoder::decode(IPC::ArgumentDecoder& decoder, InjectedBundleObjCObjectGraphDecoder& coder)
{
RetainPtr<id> root;
InjectedBundleObjCObjectGraphDecoderImpl coderImpl(root, coder.m_process);
if (!decoder.decode(coderImpl))
return false;
coder.m_objectGraph = ObjCObjectGraph::create(root.get());
return true;
}
} // namespace WebKit