| /* |
| * 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 |