diff options
Diffstat (limited to 'Source/WebKit2/Scripts/webkit2')
-rw-r--r-- | Source/WebKit2/Scripts/webkit2/__init__.py | 23 | ||||
-rw-r--r-- | Source/WebKit2/Scripts/webkit2/messages.py | 519 | ||||
-rw-r--r-- | Source/WebKit2/Scripts/webkit2/messages_unittest.py | 592 |
3 files changed, 1134 insertions, 0 deletions
diff --git a/Source/WebKit2/Scripts/webkit2/__init__.py b/Source/WebKit2/Scripts/webkit2/__init__.py new file mode 100644 index 0000000..27e3fc3 --- /dev/null +++ b/Source/WebKit2/Scripts/webkit2/__init__.py @@ -0,0 +1,23 @@ +# Copyright (C) 2010 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. + +# Required for Python to search this directory for module files diff --git a/Source/WebKit2/Scripts/webkit2/messages.py b/Source/WebKit2/Scripts/webkit2/messages.py new file mode 100644 index 0000000..8fc0eaa --- /dev/null +++ b/Source/WebKit2/Scripts/webkit2/messages.py @@ -0,0 +1,519 @@ +# Copyright (C) 2010 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 collections +import itertools +import re + + +_license_header = """/* + * Copyright (C) 2010 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. + */ +""" + +class MessageReceiver(object): + def __init__(self, name, messages, condition): + self.name = name + self.messages = messages + self.condition = condition + + def iterparameters(self): + return itertools.chain((parameter for message in self.messages for parameter in message.parameters), + (reply_parameter for message in self.messages if message.reply_parameters for reply_parameter in message.reply_parameters)) + + @classmethod + def parse(cls, file): + destination = None + messages = [] + condition = None + master_condition = None + for line in file: + match = re.search(r'messages -> ([A-Za-z_0-9]+) {', line) + if match: + if condition: + master_condition = condition + condition = None + destination = match.group(1) + continue + if line.startswith('#'): + if line.startswith('#if '): + condition = line.rstrip()[4:] + elif line.startswith('#endif'): + condition = None + continue + match = re.search(r'([A-Za-z_0-9]+)\((.*?)\)(?:(?:\s+->\s+)\((.*?)\)(?:\s+(delayed))?)?', line) + if match: + name, parameters_string, reply_parameters_string, delayed_string = match.groups() + if parameters_string: + parameters = parse_parameter_string(parameters_string) + else: + parameters = [] + + delayed = delayed_string == 'delayed' + + if reply_parameters_string: + reply_parameters = parse_parameter_string(reply_parameters_string) + elif reply_parameters_string == '': + reply_parameters = [] + else: + reply_parameters = None + + messages.append(Message(name, parameters, reply_parameters, delayed, condition)) + return MessageReceiver(destination, messages, master_condition) + + +class Message(object): + def __init__(self, name, parameters, reply_parameters, delayed, condition): + self.name = name + self.parameters = parameters + self.reply_parameters = reply_parameters + if self.reply_parameters is not None: + self.delayed = delayed + self.condition = condition + if len(self.parameters) != 0: + self.is_variadic = parameter_type_is_variadic(self.parameters[-1].type) + else: + self.is_variadic = False + + def id(self): + return '%sID' % self.name + + +class Parameter(object): + def __init__(self, type, name): + self.type = type + self.name = name + + +def parse_parameter_string(parameter_string): + return [Parameter(*type_and_name.rsplit(' ', 1)) for type_and_name in parameter_string.split(', ')] + + +def messages_header_filename(receiver): + return '%sMessages.h' % receiver.name + + +def surround_in_condition(string, condition): + if not condition: + return string + return '#if %s\n%s#endif\n' % (condition, string) + + +def messages_to_kind_enum(messages): + result = [] + result.append('enum Kind {\n') + result += [surround_in_condition(' %s,\n' % message.id(), message.condition) for message in messages] + result.append('};\n') + return ''.join(result) + + +def parameter_type_is_variadic(type): + variadic_types = frozenset([ + 'WebKit::InjectedBundleUserMessageEncoder', + 'WebKit::WebContextUserMessageEncoder', + ]) + + return type in variadic_types + +def function_parameter_type(type): + # Don't use references for built-in types. + builtin_types = frozenset([ + 'bool', + 'float', + 'double', + 'uint8_t', + 'uint16_t', + 'uint32_t', + 'uint64_t', + 'int8_t', + 'int16_t', + 'int32_t', + 'int64_t', + ]) + + if type in builtin_types: + return type + + return 'const %s&' % type + + +def reply_parameter_type(type): + return '%s&' % type + + +def arguments_type(parameters, parameter_type_function): + arguments_type = 'CoreIPC::Arguments%d' % len(parameters) + if len(parameters): + arguments_type = '%s<%s>' % (arguments_type, ', '.join(parameter_type_function(parameter.type) for parameter in parameters)) + return arguments_type + + +def base_class(message): + return arguments_type(message.parameters, function_parameter_type) + + +def reply_type(message): + return arguments_type(message.reply_parameters, reply_parameter_type) + + +def decode_type(message): + if message.is_variadic: + return arguments_type(message.parameters[:-1], reply_parameter_type) + return base_class(message) + + +def delayed_reply_type(message): + return arguments_type(message.reply_parameters, function_parameter_type) + + +def message_to_struct_declaration(message): + result = [] + function_parameters = [(function_parameter_type(x.type), x.name) for x in message.parameters] + result.append('struct %s : %s' % (message.name, base_class(message))) + result.append(' {\n') + result.append(' static const Kind messageID = %s;\n' % message.id()) + if message.reply_parameters != None: + if message.delayed: + send_parameters = [(function_parameter_type(x.type), x.name) for x in message.reply_parameters] + result.append(' struct DelayedReply {\n') + result.append(' DelayedReply(PassRefPtr<CoreIPC::Connection> connection, PassOwnPtr<CoreIPC::ArgumentDecoder> arguments)\n') + result.append(' : m_connection(connection)\n') + result.append(' , m_arguments(arguments)\n') + result.append(' {\n') + result.append(' }\n') + result.append('\n') + result.append(' bool send(%s)\n' % ', '.join([' '.join(x) for x in send_parameters])) + result.append(' {\n') + result.append(' ASSERT(m_arguments);\n') + result += [' m_arguments->encode(%s);\n' % x.name for x in message.reply_parameters] + result.append(' bool result = m_connection->sendSyncReply(m_arguments.release());\n') + result.append(' m_connection = nullptr;\n') + result.append(' return result;\n') + result.append(' }\n') + result.append('\n') + result.append(' private:\n') + result.append(' RefPtr<CoreIPC::Connection> m_connection;\n') + result.append(' OwnPtr<CoreIPC::ArgumentDecoder> m_arguments;\n') + result.append(' };\n\n') + else: + result.append(' typedef %s Reply;\n' % reply_type(message)) + + result.append(' typedef %s DecodeType;\n' % decode_type(message)) + if len(function_parameters): + result.append(' %s%s(%s)' % (len(function_parameters) == 1 and 'explicit ' or '', message.name, ', '.join([' '.join(x) for x in function_parameters]))) + result.append('\n : %s(%s)\n' % (base_class(message), ', '.join([x[1] for x in function_parameters]))) + result.append(' {\n') + result.append(' }\n') + result.append('};\n') + return surround_in_condition(''.join(result), message.condition) + + +def struct_or_class(namespace, type): + structs = frozenset([ + 'WebCore::CompositionUnderline', + 'WebCore::KeypressCommand', + 'WebCore::PluginInfo', + 'WebCore::PrintInfo', + 'WebCore::ViewportArguments', + 'WebCore::WindowFeatures', + 'WebKit::DrawingAreaInfo', + 'WebKit::PlatformPopupMenuData', + 'WebKit::PluginProcessCreationParameters', + 'WebKit::WebNavigationDataStore', + 'WebKit::WebOpenPanelParameters::Data', + 'WebKit::WebPageCreationParameters', + 'WebKit::WebPreferencesStore', + 'WebKit::WebProcessCreationParameters', + ]) + + qualified_name = '%s::%s' % (namespace, type) + if qualified_name in structs: + return 'struct %s' % type + + return 'class %s' % type + +def forward_declarations_for_namespace(namespace, types): + result = [] + result.append('namespace %s {\n' % namespace) + result += [' %s;\n' % struct_or_class(namespace, x) for x in types] + result.append('}\n') + return ''.join(result) + + +def forward_declarations_and_headers(receiver): + types_by_namespace = collections.defaultdict(set) + + headers = set([ + '"Arguments.h"', + '"MessageID.h"', + ]) + + for parameter in receiver.iterparameters(): + type = parameter.type + + if type.find('<') != -1: + # Don't forward declare class templates. + headers.update(headers_for_type(type)) + continue + + split = type.split('::') + + if len(split) == 2: + namespace = split[0] + inner_type = split[1] + types_by_namespace[namespace].add(inner_type) + elif len(split) > 2: + # We probably have a nested struct, which means we can't forward declare it. + # Include its header instead. + headers.update(headers_for_type(type)) + + forward_declarations = '\n'.join([forward_declarations_for_namespace(namespace, types) for (namespace, types) in sorted(types_by_namespace.iteritems())]) + headers = ['#include %s\n' % header for header in sorted(headers)] + + return (forward_declarations, headers) + +def generate_messages_header(file): + receiver = MessageReceiver.parse(file) + header_guard = messages_header_filename(receiver).replace('.', '_') + + result = [] + + result.append(_license_header) + result.append('\n') + + result.append('#ifndef %s\n' % header_guard) + result.append('#define %s\n\n' % header_guard) + + if receiver.condition: + result.append('#if %s\n\n' % receiver.condition) + + forward_declarations, headers = forward_declarations_and_headers(receiver) + + result += headers + result.append('\n') + + result.append(forward_declarations) + result.append('\n') + + result.append('namespace Messages {\n\nnamespace %s {\n\n' % receiver.name) + result.append(messages_to_kind_enum(receiver.messages)) + result.append('\n') + result.append('\n'.join([message_to_struct_declaration(x) for x in receiver.messages])) + result.append('\n} // namespace %s\n\n} // namespace Messages\n' % receiver.name) + + result.append('\nnamespace CoreIPC {\n\n') + result.append('template<> struct MessageKindTraits<Messages::%s::Kind> {\n' % receiver.name) + result.append(' static const MessageClass messageClass = MessageClass%s;\n' % receiver.name) + result.append('};\n') + result.append('\n} // namespace CoreIPC\n') + + if receiver.condition: + result.append('\n#endif // %s\n' % receiver.condition) + + result.append('\n#endif // %s\n' % header_guard) + + return ''.join(result) + + +def handler_function(receiver, message): + return '%s::%s' % (receiver.name, message.name[0].lower() + message.name[1:]) + + +def async_case_statement(receiver, message): + dispatch_function = 'handleMessage' + if message.is_variadic: + dispatch_function += 'Variadic' + + result = [] + result.append(' case Messages::%s::%s:\n' % (receiver.name, message.id())) + result.append(' CoreIPC::%s<Messages::%s::%s>(arguments, this, &%s);\n' % (dispatch_function, receiver.name, message.name, handler_function(receiver, message))) + result.append(' return;\n') + return surround_in_condition(''.join(result), message.condition) + + +def sync_case_statement(receiver, message): + result = [] + result.append(' case Messages::%s::%s:\n' % (receiver.name, message.id())) + result.append(' CoreIPC::handleMessage<Messages::%s::%s>(arguments, reply, this, &%s);\n' % (receiver.name, message.name, handler_function(receiver, message))) + # FIXME: Handle delayed replies + result.append(' return CoreIPC::AutomaticReply;\n') + return surround_in_condition(''.join(result), message.condition) + + +def argument_coder_headers_for_type(type): + # Check for Vector. + match = re.search(r'Vector<(.+)>', type) + if match: + element_type = match.groups()[0].strip() + return ['"ArgumentCoders.h"'] + argument_coder_headers_for_type(element_type) + + special_cases = { + 'WTF::String': '"ArgumentCoders.h"', + 'WebKit::InjectedBundleUserMessageEncoder': '"InjectedBundleUserMessageCoders.h"', + 'WebKit::WebContextUserMessageEncoder': '"WebContextUserMessageCoders.h"', + } + + if type in special_cases: + return [special_cases[type]] + + split = type.split('::') + if len(split) < 2: + return [] + if split[0] == 'WebCore': + return ['"WebCoreArgumentCoders.h"'] + + return [] + + +def headers_for_type(type): + # Check for Vector. + match = re.search(r'Vector<(.+)>', type) + if match: + element_type = match.groups()[0].strip() + return ['<wtf/Vector.h>'] + headers_for_type(element_type) + + special_cases = { + 'WTF::String': '<wtf/text/WTFString.h>', + 'WebCore::CompositionUnderline': '<WebCore/Editor.h>', + 'WebCore::KeypressCommand': '<WebCore/KeyboardEvent.h>', + 'WebCore::PluginInfo': '<WebCore/PluginData.h>', + 'WebCore::TextCheckingResult': '<WebCore/EditorClient.h>', + 'WebKit::WebKeyboardEvent': '"WebEvent.h"', + 'WebKit::WebMouseEvent': '"WebEvent.h"', + 'WebKit::WebTouchEvent': '"WebEvent.h"', + 'WebKit::WebWheelEvent': '"WebEvent.h"', + } + if type in special_cases: + return [special_cases[type]] + + # We assume that we must include a header for a type iff it has a scope + # resolution operator (::). + split = type.split('::') + if len(split) < 2: + return [] + if split[0] == 'WebKit' or split[0] == 'CoreIPC': + return ['"%s.h"' % split[1]] + return ['<%s/%s.h>' % tuple(split)] + + +def generate_message_handler(file): + receiver = MessageReceiver.parse(file) + headers = set([ + '"%s"' % messages_header_filename(receiver), + '"HandleMessage.h"', + '"ArgumentDecoder.h"', + ]) + + for parameter in receiver.iterparameters(): + type = parameter.type + argument_encoder_headers = argument_coder_headers_for_type(parameter.type) + if argument_encoder_headers: + headers.update(argument_encoder_headers) + continue + + type_headers = headers_for_type(type) + headers.update(type_headers) + + for message in receiver.messages: + if message.reply_parameters is not None: + for reply_parameter in message.reply_parameters: + type = reply_parameter.type + argument_encoder_headers = argument_coder_headers_for_type(type) + if argument_encoder_headers: + headers.update(argument_encoder_headers) + continue + + type_headers = headers_for_type(type) + headers.update(type_headers) + + result = [] + + result.append(_license_header) + result.append('\n') + + if receiver.condition: + result.append('#if %s\n\n' % receiver.condition) + + result.append('#include "%s.h"\n\n' % receiver.name) + result += ['#include %s\n' % header for header in sorted(headers)] + result.append('\n') + + result.append('namespace WebKit {\n\n') + + async_messages = [] + sync_messages = [] + for message in receiver.messages: + if message.reply_parameters is not None: + sync_messages.append(message) + else: + async_messages.append(message) + + if async_messages: + result.append('void %s::didReceive%sMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)\n' % (receiver.name, receiver.name)) + result.append('{\n') + result.append(' switch (messageID.get<Messages::%s::Kind>()) {\n' % receiver.name) + result += [async_case_statement(receiver, message) for message in async_messages] + result.append(' default:\n') + result.append(' break;\n') + result.append(' }\n\n') + result.append(' ASSERT_NOT_REACHED();\n') + result.append('}\n') + + if sync_messages: + result.append('\n') + result.append('CoreIPC::SyncReplyMode %s::didReceiveSync%sMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply)\n' % (receiver.name, receiver.name)) + result.append('{\n') + result.append(' switch (messageID.get<Messages::%s::Kind>()) {\n' % receiver.name) + result += [sync_case_statement(receiver, message) for message in sync_messages] + result.append(' default:\n') + result.append(' break;\n') + result.append(' }\n\n') + result.append(' ASSERT_NOT_REACHED();\n') + result.append(' return CoreIPC::AutomaticReply;\n') + result.append('}\n') + + result.append('\n} // namespace WebKit\n') + + if receiver.condition: + result.append('\n#endif // %s\n' % receiver.condition) + + return ''.join(result) diff --git a/Source/WebKit2/Scripts/webkit2/messages_unittest.py b/Source/WebKit2/Scripts/webkit2/messages_unittest.py new file mode 100644 index 0000000..25123c0 --- /dev/null +++ b/Source/WebKit2/Scripts/webkit2/messages_unittest.py @@ -0,0 +1,592 @@ +# Copyright (C) 2010 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 unittest +from StringIO import StringIO + +import messages + +_messages_file_contents = """# Copyright (C) 2010 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. + +#if ENABLE(WEBKIT2) + +messages -> WebPage { + LoadURL(WTF::String url) +#if ENABLE(TOUCH_EVENTS) + TouchEvent(WebKit::WebTouchEvent event) +#endif + DidReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, uint32_t policyAction) + Close() + + PreferencesDidChange(WebKit::WebPreferencesStore store) + SendDoubleAndFloat(double d, float f) + SendInts(Vector<uint64_t> ints, Vector<Vector<uint64_t> > intVectors) + + CreatePlugin(uint64_t pluginInstanceID, WebKit::Plugin::Parameters parameters) -> (bool result) + RunJavaScriptAlert(uint64_t frameID, WTF::String message) -> () + GetPlugins(bool refresh) -> (Vector<WebCore::PluginInfo> plugins) + GetPluginProcessConnection(WTF::String pluginPath) -> (CoreIPC::Connection::Handle connectionHandle) delayed + + DidCreateWebProcessConnection(CoreIPC::MachPort connectionIdentifier) + +#if PLATFORM(MAC) + # Keyboard support + InterpretKeyEvent(uint32_t type) -> (Vector<WebCore::KeypressCommand> commandName) +#endif +} + +#endif +""" + +_expected_results = { + 'name': 'WebPage', + 'condition': 'ENABLE(WEBKIT2)', + 'messages': ( + { + 'name': 'LoadURL', + 'parameters': ( + ('WTF::String', 'url'), + ), + 'condition': None, + }, + { + 'name': 'TouchEvent', + 'parameters': ( + ('WebKit::WebTouchEvent', 'event'), + ), + 'condition': 'ENABLE(TOUCH_EVENTS)', + }, + { + 'name': 'DidReceivePolicyDecision', + 'parameters': ( + ('uint64_t', 'frameID'), + ('uint64_t', 'listenerID'), + ('uint32_t', 'policyAction'), + ), + 'condition': None, + }, + { + 'name': 'Close', + 'parameters': (), + 'condition': None, + }, + { + 'name': 'PreferencesDidChange', + 'parameters': ( + ('WebKit::WebPreferencesStore', 'store'), + ), + 'condition': None, + }, + { + 'name': 'SendDoubleAndFloat', + 'parameters': ( + ('double', 'd'), + ('float', 'f'), + ), + 'condition': None, + }, + { + 'name': 'SendInts', + 'parameters': ( + ('Vector<uint64_t>', 'ints'), + ('Vector<Vector<uint64_t> >', 'intVectors') + ), + 'condition': None, + }, + { + 'name': 'CreatePlugin', + 'parameters': ( + ('uint64_t', 'pluginInstanceID'), + ('WebKit::Plugin::Parameters', 'parameters') + ), + 'reply_parameters': ( + ('bool', 'result'), + ), + 'condition': None, + }, + { + 'name': 'RunJavaScriptAlert', + 'parameters': ( + ('uint64_t', 'frameID'), + ('WTF::String', 'message') + ), + 'reply_parameters': (), + 'condition': None, + }, + { + 'name': 'GetPlugins', + 'parameters': ( + ('bool', 'refresh'), + ), + 'reply_parameters': ( + ('Vector<WebCore::PluginInfo>', 'plugins'), + ), + 'condition': None, + }, + { + 'name': 'GetPluginProcessConnection', + 'parameters': ( + ('WTF::String', 'pluginPath'), + ), + 'reply_parameters': ( + ('CoreIPC::Connection::Handle', 'connectionHandle'), + ), + 'condition': None, + }, + { + 'name': 'DidCreateWebProcessConnection', + 'parameters': ( + ('CoreIPC::MachPort', 'connectionIdentifier'), + ), + 'condition': None, + }, + { + 'name': 'InterpretKeyEvent', + 'parameters': ( + ('uint32_t', 'type'), + ), + 'reply_parameters': ( + ('Vector<WebCore::KeypressCommand>', 'commandName'), + ), + 'condition': 'PLATFORM(MAC)', + }, + ), +} + + +class MessagesTest(unittest.TestCase): + def setUp(self): + self.receiver = messages.MessageReceiver.parse(StringIO(_messages_file_contents)) + + +class ParsingTest(MessagesTest): + def check_message(self, message, expected_message): + self.assertEquals(message.name, expected_message['name']) + self.assertEquals(len(message.parameters), len(expected_message['parameters'])) + for index, parameter in enumerate(message.parameters): + self.assertEquals(parameter.type, expected_message['parameters'][index][0]) + self.assertEquals(parameter.name, expected_message['parameters'][index][1]) + if message.reply_parameters != None: + for index, parameter in enumerate(message.reply_parameters): + self.assertEquals(parameter.type, expected_message['reply_parameters'][index][0]) + self.assertEquals(parameter.name, expected_message['reply_parameters'][index][1]) + else: + self.assertFalse('reply_parameters' in expected_message) + self.assertEquals(message.condition, expected_message['condition']) + + def test_receiver(self): + """Receiver should be parsed as expected""" + self.assertEquals(self.receiver.name, _expected_results['name']) + self.assertEquals(self.receiver.condition, _expected_results['condition']) + self.assertEquals(len(self.receiver.messages), len(_expected_results['messages'])) + for index, message in enumerate(self.receiver.messages): + self.check_message(message, _expected_results['messages'][index]) + +_expected_header = """/* + * Copyright (C) 2010 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. + */ + +#ifndef WebPageMessages_h +#define WebPageMessages_h + +#if ENABLE(WEBKIT2) + +#include "Arguments.h" +#include "Connection.h" +#include "MessageID.h" +#include "Plugin.h" +#include <WebCore/KeyboardEvent.h> +#include <WebCore/PluginData.h> +#include <wtf/Vector.h> + +namespace CoreIPC { + class MachPort; +} + +namespace WTF { + class String; +} + +namespace WebKit { + struct WebPreferencesStore; + class WebTouchEvent; +} + +namespace Messages { + +namespace WebPage { + +enum Kind { + LoadURLID, +#if ENABLE(TOUCH_EVENTS) + TouchEventID, +#endif + DidReceivePolicyDecisionID, + CloseID, + PreferencesDidChangeID, + SendDoubleAndFloatID, + SendIntsID, + CreatePluginID, + RunJavaScriptAlertID, + GetPluginsID, + GetPluginProcessConnectionID, + DidCreateWebProcessConnectionID, +#if PLATFORM(MAC) + InterpretKeyEventID, +#endif +}; + +struct LoadURL : CoreIPC::Arguments1<const WTF::String&> { + static const Kind messageID = LoadURLID; + typedef CoreIPC::Arguments1<const WTF::String&> DecodeType; + explicit LoadURL(const WTF::String& url) + : CoreIPC::Arguments1<const WTF::String&>(url) + { + } +}; + +#if ENABLE(TOUCH_EVENTS) +struct TouchEvent : CoreIPC::Arguments1<const WebKit::WebTouchEvent&> { + static const Kind messageID = TouchEventID; + typedef CoreIPC::Arguments1<const WebKit::WebTouchEvent&> DecodeType; + explicit TouchEvent(const WebKit::WebTouchEvent& event) + : CoreIPC::Arguments1<const WebKit::WebTouchEvent&>(event) + { + } +}; +#endif + +struct DidReceivePolicyDecision : CoreIPC::Arguments3<uint64_t, uint64_t, uint32_t> { + static const Kind messageID = DidReceivePolicyDecisionID; + typedef CoreIPC::Arguments3<uint64_t, uint64_t, uint32_t> DecodeType; + DidReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, uint32_t policyAction) + : CoreIPC::Arguments3<uint64_t, uint64_t, uint32_t>(frameID, listenerID, policyAction) + { + } +}; + +struct Close : CoreIPC::Arguments0 { + static const Kind messageID = CloseID; + typedef CoreIPC::Arguments0 DecodeType; +}; + +struct PreferencesDidChange : CoreIPC::Arguments1<const WebKit::WebPreferencesStore&> { + static const Kind messageID = PreferencesDidChangeID; + typedef CoreIPC::Arguments1<const WebKit::WebPreferencesStore&> DecodeType; + explicit PreferencesDidChange(const WebKit::WebPreferencesStore& store) + : CoreIPC::Arguments1<const WebKit::WebPreferencesStore&>(store) + { + } +}; + +struct SendDoubleAndFloat : CoreIPC::Arguments2<double, float> { + static const Kind messageID = SendDoubleAndFloatID; + typedef CoreIPC::Arguments2<double, float> DecodeType; + SendDoubleAndFloat(double d, float f) + : CoreIPC::Arguments2<double, float>(d, f) + { + } +}; + +struct SendInts : CoreIPC::Arguments2<const Vector<uint64_t>&, const Vector<Vector<uint64_t> >&> { + static const Kind messageID = SendIntsID; + typedef CoreIPC::Arguments2<const Vector<uint64_t>&, const Vector<Vector<uint64_t> >&> DecodeType; + SendInts(const Vector<uint64_t>& ints, const Vector<Vector<uint64_t> >& intVectors) + : CoreIPC::Arguments2<const Vector<uint64_t>&, const Vector<Vector<uint64_t> >&>(ints, intVectors) + { + } +}; + +struct CreatePlugin : CoreIPC::Arguments2<uint64_t, const WebKit::Plugin::Parameters&> { + static const Kind messageID = CreatePluginID; + typedef CoreIPC::Arguments1<bool&> Reply; + typedef CoreIPC::Arguments2<uint64_t, const WebKit::Plugin::Parameters&> DecodeType; + CreatePlugin(uint64_t pluginInstanceID, const WebKit::Plugin::Parameters& parameters) + : CoreIPC::Arguments2<uint64_t, const WebKit::Plugin::Parameters&>(pluginInstanceID, parameters) + { + } +}; + +struct RunJavaScriptAlert : CoreIPC::Arguments2<uint64_t, const WTF::String&> { + static const Kind messageID = RunJavaScriptAlertID; + typedef CoreIPC::Arguments0 Reply; + typedef CoreIPC::Arguments2<uint64_t, const WTF::String&> DecodeType; + RunJavaScriptAlert(uint64_t frameID, const WTF::String& message) + : CoreIPC::Arguments2<uint64_t, const WTF::String&>(frameID, message) + { + } +}; + +struct GetPlugins : CoreIPC::Arguments1<bool> { + static const Kind messageID = GetPluginsID; + typedef CoreIPC::Arguments1<Vector<WebCore::PluginInfo>&> Reply; + typedef CoreIPC::Arguments1<bool> DecodeType; + explicit GetPlugins(bool refresh) + : CoreIPC::Arguments1<bool>(refresh) + { + } +}; + +struct GetPluginProcessConnection : CoreIPC::Arguments1<const WTF::String&> { + static const Kind messageID = GetPluginProcessConnectionID; + struct DelayedReply { + DelayedReply(PassRefPtr<CoreIPC::Connection> connection, PassOwnPtr<CoreIPC::ArgumentDecoder> arguments) + : m_connection(connection) + , m_arguments(arguments) + { + } + + bool send(const CoreIPC::Connection::Handle& connectionHandle) + { + ASSERT(m_arguments); + m_arguments->encode(connectionHandle); + bool result = m_connection->sendSyncReply(m_arguments.release()); + m_connection = nullptr; + return result; + } + + private: + RefPtr<CoreIPC::Connection> m_connection; + OwnPtr<CoreIPC::ArgumentDecoder> m_arguments; + }; + + typedef CoreIPC::Arguments1<const WTF::String&> DecodeType; + explicit GetPluginProcessConnection(const WTF::String& pluginPath) + : CoreIPC::Arguments1<const WTF::String&>(pluginPath) + { + } +}; + +struct DidCreateWebProcessConnection : CoreIPC::Arguments1<const CoreIPC::MachPort&> { + static const Kind messageID = DidCreateWebProcessConnectionID; + typedef CoreIPC::Arguments1<const CoreIPC::MachPort&> DecodeType; + explicit DidCreateWebProcessConnection(const CoreIPC::MachPort& connectionIdentifier) + : CoreIPC::Arguments1<const CoreIPC::MachPort&>(connectionIdentifier) + { + } +}; + +#if PLATFORM(MAC) +struct InterpretKeyEvent : CoreIPC::Arguments1<uint32_t> { + static const Kind messageID = InterpretKeyEventID; + typedef CoreIPC::Arguments1<Vector<WebCore::KeypressCommand>&> Reply; + typedef CoreIPC::Arguments1<uint32_t> DecodeType; + explicit InterpretKeyEvent(uint32_t type) + : CoreIPC::Arguments1<uint32_t>(type) + { + } +}; +#endif + +} // namespace WebPage + +} // namespace Messages + +namespace CoreIPC { + +template<> struct MessageKindTraits<Messages::WebPage::Kind> { + static const MessageClass messageClass = MessageClassWebPage; +}; + +} // namespace CoreIPC + +#endif // ENABLE(WEBKIT2) + +#endif // WebPageMessages_h +""" + +_expected_receiver_implementation = """/* + * Copyright (C) 2010 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. + */ + +#if ENABLE(WEBKIT2) + +#include "WebPage.h" + +#include "ArgumentCoders.h" +#include "ArgumentDecoder.h" +#include "Connection.h" +#include "HandleMessage.h" +#include "MachPort.h" +#include "Plugin.h" +#include "WebCoreArgumentCoders.h" +#include "WebEvent.h" +#include "WebPageMessages.h" +#include "WebPreferencesStore.h" + +namespace WebKit { + +void WebPage::didReceiveWebPageMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments) +{ + switch (messageID.get<Messages::WebPage::Kind>()) { + case Messages::WebPage::LoadURLID: + CoreIPC::handleMessage<Messages::WebPage::LoadURL>(arguments, this, &WebPage::loadURL); + return; +#if ENABLE(TOUCH_EVENTS) + case Messages::WebPage::TouchEventID: + CoreIPC::handleMessage<Messages::WebPage::TouchEvent>(arguments, this, &WebPage::touchEvent); + return; +#endif + case Messages::WebPage::DidReceivePolicyDecisionID: + CoreIPC::handleMessage<Messages::WebPage::DidReceivePolicyDecision>(arguments, this, &WebPage::didReceivePolicyDecision); + return; + case Messages::WebPage::CloseID: + CoreIPC::handleMessage<Messages::WebPage::Close>(arguments, this, &WebPage::close); + return; + case Messages::WebPage::PreferencesDidChangeID: + CoreIPC::handleMessage<Messages::WebPage::PreferencesDidChange>(arguments, this, &WebPage::preferencesDidChange); + return; + case Messages::WebPage::SendDoubleAndFloatID: + CoreIPC::handleMessage<Messages::WebPage::SendDoubleAndFloat>(arguments, this, &WebPage::sendDoubleAndFloat); + return; + case Messages::WebPage::SendIntsID: + CoreIPC::handleMessage<Messages::WebPage::SendInts>(arguments, this, &WebPage::sendInts); + return; + case Messages::WebPage::DidCreateWebProcessConnectionID: + CoreIPC::handleMessage<Messages::WebPage::DidCreateWebProcessConnection>(arguments, this, &WebPage::didCreateWebProcessConnection); + return; + default: + break; + } + + ASSERT_NOT_REACHED(); +} + +CoreIPC::SyncReplyMode WebPage::didReceiveSyncWebPageMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply) +{ + switch (messageID.get<Messages::WebPage::Kind>()) { + case Messages::WebPage::CreatePluginID: + CoreIPC::handleMessage<Messages::WebPage::CreatePlugin>(arguments, reply, this, &WebPage::createPlugin); + return CoreIPC::AutomaticReply; + case Messages::WebPage::RunJavaScriptAlertID: + CoreIPC::handleMessage<Messages::WebPage::RunJavaScriptAlert>(arguments, reply, this, &WebPage::runJavaScriptAlert); + return CoreIPC::AutomaticReply; + case Messages::WebPage::GetPluginsID: + CoreIPC::handleMessage<Messages::WebPage::GetPlugins>(arguments, reply, this, &WebPage::getPlugins); + return CoreIPC::AutomaticReply; + case Messages::WebPage::GetPluginProcessConnectionID: + CoreIPC::handleMessage<Messages::WebPage::GetPluginProcessConnection>(arguments, reply, this, &WebPage::getPluginProcessConnection); + return CoreIPC::AutomaticReply; +#if PLATFORM(MAC) + case Messages::WebPage::InterpretKeyEventID: + CoreIPC::handleMessage<Messages::WebPage::InterpretKeyEvent>(arguments, reply, this, &WebPage::interpretKeyEvent); + return CoreIPC::AutomaticReply; +#endif + default: + break; + } + + ASSERT_NOT_REACHED(); + return CoreIPC::AutomaticReply; +} + +} // namespace WebKit + +#endif // ENABLE(WEBKIT2) +""" + + +class GeneratedFileContentsTest(unittest.TestCase): + def assertGeneratedFileContentsEqual(self, first, second): + first_list = first.split('\n') + second_list = second.split('\n') + + for index, first_line in enumerate(first_list): + self.assertEquals(first_line, second_list[index]) + + self.assertEquals(len(first_list), len(second_list)) + + +class HeaderTest(GeneratedFileContentsTest): + def test_header(self): + file_contents = messages.generate_messages_header(StringIO(_messages_file_contents)) + self.assertGeneratedFileContentsEqual(file_contents, _expected_header) + + +class ReceiverImplementationTest(GeneratedFileContentsTest): + def test_receiver_implementation(self): + file_contents = messages.generate_message_handler(StringIO(_messages_file_contents)) + self.assertGeneratedFileContentsEqual(file_contents, _expected_receiver_implementation) + + +if __name__ == '__main__': + unittest.main() |