/* * 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 "ArgumentEncoder.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&& 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(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(object); for (const auto& keyValuePair : dictionary.map()) { if (!keyValuePair.value) continue; if (shouldTransform(*keyValuePair.value, transformer)) return true; } } return transformer.shouldTransformObject(object); } static RefPtr transformGraph(API::Object& object, const UserData::Transformer& transformer) { if (object.type() == API::Object::Type::Array) { auto& array = static_cast(object); Vector> 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(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 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::ArgumentEncoder& encoder) const { encode(encoder, m_object.get()); } bool UserData::decode(IPC::ArgumentDecoder& decoder, UserData& userData) { return decode(decoder, userData.m_object); } void UserData::encode(IPC::ArgumentEncoder& encoder, const API::Object* object) { if (!object) { encoder.encodeEnum(API::Object::Type::Null); return; } encode(encoder, *object); } void UserData::encode(IPC::ArgumentEncoder& 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(object); encoder << static_cast(array.size()); for (size_t i = 0; i < array.size(); ++i) encode(encoder, array.at(i)); break; } case API::Object::Type::Boolean: static_cast(object).encode(encoder); break; case API::Object::Type::CertificateInfo: { const auto& certificateInfo = static_cast(object); encoder << certificateInfo.certificateInfo(); break; } case API::Object::Type::Data: static_cast(object).encode(encoder); break; case API::Object::Type::Dictionary: { auto& dictionary = static_cast(object); auto& map = dictionary.map(); encoder << static_cast(map.size()); for (const auto& keyValuePair : map) { encoder << keyValuePair.key; encode(encoder, keyValuePair.value.get()); } break; } case API::Object::Type::Double: static_cast(object).encode(encoder); break; case API::Object::Type::Error: static_cast(object).encode(encoder); break; case API::Object::Type::FrameHandle: static_cast(object).encode(encoder); break; case API::Object::Type::Image: { auto& image = static_cast(object); ShareableBitmap::Handle handle; ASSERT(!image.bitmap() || image.bitmap()->isBackedBySharedMemory()); if (!image.bitmap() || !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(object).encode(encoder); break; case API::Object::Type::PageHandle: static_cast(object).encode(encoder); break; case API::Object::Type::Point: static_cast(object).encode(encoder); break; case API::Object::Type::Rect: static_cast(object).encode(encoder); break; case API::Object::Type::RenderLayer: { auto& renderLayer = static_cast(object); encode(encoder, renderLayer.renderer()); encoder << renderLayer.isReflection(); encoder << renderLayer.isClipping(); encoder << renderLayer.isClipped(); encoder << static_cast(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(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(object); encoder << serializedScriptValue.dataReference(); break; } case API::Object::Type::Size: static_cast(object).encode(encoder); break; case API::Object::Type::String: { auto& string = static_cast(object); encoder << string.string(); break; } case API::Object::Type::URL: static_cast(object).encode(encoder); break; case API::Object::Type::URLRequest: static_cast(object).encode(encoder); break; case API::Object::Type::URLResponse: static_cast(object).encode(encoder); break; case API::Object::Type::UInt64: static_cast(object).encode(encoder); break; case API::Object::Type::UserContentURLPattern: { auto& urlPattern = static_cast(object); encoder << urlPattern.patternString(); break; } #if PLATFORM(COCOA) case API::Object::Type::ObjCObjectGraph: static_cast(object).encode(encoder); break; #endif default: ASSERT_NOT_REACHED(); } } bool UserData::decode(IPC::ArgumentDecoder& decoder, RefPtr& 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> elements; for (size_t i = 0; i < size; ++i) { RefPtr 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 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; result = WebImage::create(ShareableBitmap::create(handle)); 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 renderer; bool isReflection; bool isClipping; bool isClipped; uint32_t compositingLayerTypeAsUInt32; WebCore::IntRect absoluteBoundingBox; double backingStoreMemoryEstimate; RefPtr negativeZOrderList; RefPtr normalFlowList; RefPtr positiveZOrderList; RefPtr 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(renderer), isReflection, isClipping, isClipped, static_cast(compositingLayerTypeAsUInt32), absoluteBoundingBox, backingStoreMemoryEstimate, static_pointer_cast(negativeZOrderList), static_pointer_cast(normalFlowList), static_pointer_cast(positiveZOrderList), static_pointer_cast(frameContentsLayer)); break; } case API::Object::Type::RenderObject: { String name; String textSnippet; String elementTagName; String elementID; unsigned textLength; RefPtr elementClassNames; WebCore::IntPoint absolutePosition; WebCore::IntRect frameRect; RefPtr 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(elementClassNames), absolutePosition, frameRect, textSnippet, textLength, static_pointer_cast(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