Merge from Chromium at DEPS revision r198571
This commit was generated by merge_to_master.py.
Change-Id: I3a7f89ea6b8c017335bd52739166aed708cad1e5
diff --git a/Source/core/inspector/BindingVisitors.h b/Source/core/inspector/BindingVisitors.h
new file mode 100644
index 0000000..c885703
--- /dev/null
+++ b/Source/core/inspector/BindingVisitors.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 BindingVisitors_h
+#define BindingVisitors_h
+
+namespace WTF {
+class ArrayBufferView;
+class StringImpl;
+}
+
+namespace WebCore {
+
+class Node;
+
+class WrappedNodeVisitor {
+public:
+ virtual void visitNode(Node*) = 0;
+protected:
+ virtual ~WrappedNodeVisitor() { }
+};
+
+class ExternalStringVisitor {
+public:
+ virtual void visitJSExternalString(WTF::StringImpl*) = 0;
+protected:
+ virtual ~ExternalStringVisitor() { }
+};
+
+
+class ExternalArrayVisitor {
+public:
+ virtual void visitJSExternalArray(WTF::ArrayBufferView*) = 0;
+protected:
+ virtual ~ExternalArrayVisitor() { }
+};
+
+} // namespace WebCore
+
+#endif // BindingVisitors_h
diff --git a/Source/core/inspector/CodeGeneratorInspector.py b/Source/core/inspector/CodeGeneratorInspector.py
new file mode 100755
index 0000000..481682b
--- /dev/null
+++ b/Source/core/inspector/CodeGeneratorInspector.py
@@ -0,0 +1,2268 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Copyright (c) 2012 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER OR 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 os.path
+import sys
+import string
+import optparse
+import re
+try:
+ import json
+except ImportError:
+ import simplejson as json
+
+import CodeGeneratorInspectorStrings
+
+# Manually-filled map of type name replacements.
+TYPE_NAME_FIX_MAP = {
+ "RGBA": "Rgba", # RGBA is reported to be conflicting with a define name in Windows CE.
+ "": "Empty",
+}
+
+
+TYPES_WITH_RUNTIME_CAST_SET = frozenset(["Runtime.RemoteObject", "Runtime.PropertyDescriptor", "Runtime.InternalPropertyDescriptor",
+ "Debugger.FunctionDetails", "Debugger.CallFrame",
+ "Canvas.TraceLog", "Canvas.ResourceInfo", "Canvas.ResourceState",
+ # This should be a temporary hack. TimelineEvent should be created via generated C++ API.
+ "Timeline.TimelineEvent"])
+
+TYPES_WITH_OPEN_FIELD_LIST_SET = frozenset(["Timeline.TimelineEvent",
+ # InspectorStyleSheet not only creates this property but wants to read it and modify it.
+ "CSS.CSSProperty",
+ # InspectorResourceAgent needs to update mime-type.
+ "Network.Response"])
+
+EXACTLY_INT_SUPPORTED = False
+
+cmdline_parser = optparse.OptionParser()
+cmdline_parser.add_option("--output_h_dir")
+cmdline_parser.add_option("--output_cpp_dir")
+
+try:
+ arg_options, arg_values = cmdline_parser.parse_args()
+ if (len(arg_values) != 1):
+ raise Exception("Exactly one plain argument expected (found %s)" % len(arg_values))
+ input_json_filename = arg_values[0]
+ output_header_dirname = arg_options.output_h_dir
+ output_cpp_dirname = arg_options.output_cpp_dir
+ if not output_header_dirname:
+ raise Exception("Output .h directory must be specified")
+ if not output_cpp_dirname:
+ raise Exception("Output .cpp directory must be specified")
+except Exception:
+ # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
+ exc = sys.exc_info()[1]
+ sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc)
+ sys.stderr.write("Usage: <script> protocol.json --output_h_dir <output_header_dir> --output_cpp_dir <output_cpp_dir>\n")
+ exit(1)
+
+
+# FIXME: move this methods under Capitalizer class below and remove duplications.
+def dash_to_camelcase(word):
+ return ''.join(x.capitalize() or '-' for x in word.split('-'))
+
+
+def fix_camel_case(name):
+ refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name)
+ refined = to_title_case(refined)
+ return re.sub(r'(?i)HTML|XML|WML|API', lambda pat: pat.group(0).upper(), refined)
+
+
+def to_title_case(name):
+ return name[:1].upper() + name[1:]
+
+
+class Capitalizer:
+ @staticmethod
+ def lower_camel_case_to_upper(str):
+ if len(str) > 0 and str[0].islower():
+ str = str[0].upper() + str[1:]
+ return str
+
+ @staticmethod
+ def upper_camel_case_to_lower(str):
+ pos = 0
+ while pos < len(str) and str[pos].isupper():
+ pos += 1
+ if pos == 0:
+ return str
+ if pos == 1:
+ return str[0].lower() + str[1:]
+ if pos < len(str):
+ pos -= 1
+ possible_abbreviation = str[0:pos]
+ if possible_abbreviation not in Capitalizer.ABBREVIATION:
+ raise Exception("Unknown abbreviation %s" % possible_abbreviation)
+ str = possible_abbreviation.lower() + str[pos:]
+ return str
+
+ @staticmethod
+ def camel_case_to_capitalized_with_underscores(str):
+ if len(str) == 0:
+ return str
+ output = Capitalizer.split_camel_case_(str)
+ return "_".join(output).upper()
+
+ @staticmethod
+ def split_camel_case_(str):
+ output = []
+ pos_being = 0
+ pos = 1
+ has_oneletter = False
+ while pos < len(str):
+ if str[pos].isupper():
+ output.append(str[pos_being:pos].upper())
+ if pos - pos_being == 1:
+ has_oneletter = True
+ pos_being = pos
+ pos += 1
+ output.append(str[pos_being:])
+ if has_oneletter:
+ array_pos = 0
+ while array_pos < len(output) - 1:
+ if len(output[array_pos]) == 1:
+ array_pos_end = array_pos + 1
+ while array_pos_end < len(output) and len(output[array_pos_end]) == 1:
+ array_pos_end += 1
+ if array_pos_end - array_pos > 1:
+ possible_abbreviation = "".join(output[array_pos:array_pos_end])
+ if possible_abbreviation.upper() in Capitalizer.ABBREVIATION:
+ output[array_pos:array_pos_end] = [possible_abbreviation]
+ else:
+ array_pos = array_pos_end - 1
+ array_pos += 1
+ return output
+
+ ABBREVIATION = frozenset(["XHR", "DOM", "CSS"])
+
+VALIDATOR_IFDEF_NAME = "!ASSERT_DISABLED"
+
+
+class DomainNameFixes:
+ @classmethod
+ def get_fixed_data(cls, domain_name):
+ field_name_res = Capitalizer.upper_camel_case_to_lower(domain_name) + "Agent"
+
+ class Res(object):
+ agent_field_name = field_name_res
+
+ return Res
+
+
+class RawTypes(object):
+ @staticmethod
+ def get(json_type):
+ if json_type == "boolean":
+ return RawTypes.Bool
+ elif json_type == "string":
+ return RawTypes.String
+ elif json_type == "array":
+ return RawTypes.Array
+ elif json_type == "object":
+ return RawTypes.Object
+ elif json_type == "integer":
+ return RawTypes.Int
+ elif json_type == "number":
+ return RawTypes.Number
+ elif json_type == "any":
+ return RawTypes.Any
+ else:
+ raise Exception("Unknown type: %s" % json_type)
+
+ # For output parameter all values are passed by pointer except RefPtr-based types.
+ class OutputPassModel:
+ class ByPointer:
+ @staticmethod
+ def get_argument_prefix():
+ return "&"
+
+ @staticmethod
+ def get_parameter_type_suffix():
+ return "*"
+
+ class ByReference:
+ @staticmethod
+ def get_argument_prefix():
+ return ""
+
+ @staticmethod
+ def get_parameter_type_suffix():
+ return "&"
+
+ class BaseType(object):
+ need_internal_runtime_cast_ = False
+
+ @classmethod
+ def request_raw_internal_runtime_cast(cls):
+ if not cls.need_internal_runtime_cast_:
+ cls.need_internal_runtime_cast_ = True
+
+ @classmethod
+ def get_raw_validator_call_text(cls):
+ return "RuntimeCastHelper::assertType<InspectorValue::Type%s>" % cls.get_validate_method_params().template_type
+
+ class String(BaseType):
+ @staticmethod
+ def get_getter_name():
+ return "String"
+
+ get_setter_name = get_getter_name
+
+ @staticmethod
+ def get_c_initializer():
+ return "\"\""
+
+ @staticmethod
+ def get_validate_method_params():
+ class ValidateMethodParams:
+ template_type = "String"
+ return ValidateMethodParams
+
+ @staticmethod
+ def get_output_pass_model():
+ return RawTypes.OutputPassModel.ByPointer
+
+ @staticmethod
+ def is_heavy_value():
+ return True
+
+ @staticmethod
+ def get_array_item_raw_c_type_text():
+ return "String"
+
+ @staticmethod
+ def get_raw_type_model():
+ return TypeModel.String
+
+ class Int(BaseType):
+ @staticmethod
+ def get_getter_name():
+ return "Int"
+
+ @staticmethod
+ def get_setter_name():
+ return "Number"
+
+ @staticmethod
+ def get_c_initializer():
+ return "0"
+
+ @classmethod
+ def get_raw_validator_call_text(cls):
+ return "RuntimeCastHelper::assertInt"
+
+ @staticmethod
+ def get_output_pass_model():
+ return RawTypes.OutputPassModel.ByPointer
+
+ @staticmethod
+ def is_heavy_value():
+ return False
+
+ @staticmethod
+ def get_array_item_raw_c_type_text():
+ return "int"
+
+ @staticmethod
+ def get_raw_type_model():
+ return TypeModel.Int
+
+ class Number(BaseType):
+ @staticmethod
+ def get_getter_name():
+ return "Double"
+
+ @staticmethod
+ def get_setter_name():
+ return "Number"
+
+ @staticmethod
+ def get_c_initializer():
+ return "0"
+
+ @staticmethod
+ def get_validate_method_params():
+ class ValidateMethodParams:
+ template_type = "Number"
+ return ValidateMethodParams
+
+ @staticmethod
+ def get_output_pass_model():
+ return RawTypes.OutputPassModel.ByPointer
+
+ @staticmethod
+ def is_heavy_value():
+ return False
+
+ @staticmethod
+ def get_array_item_raw_c_type_text():
+ return "double"
+
+ @staticmethod
+ def get_raw_type_model():
+ return TypeModel.Number
+
+ class Bool(BaseType):
+ @staticmethod
+ def get_getter_name():
+ return "Boolean"
+
+ get_setter_name = get_getter_name
+
+ @staticmethod
+ def get_c_initializer():
+ return "false"
+
+ @staticmethod
+ def get_validate_method_params():
+ class ValidateMethodParams:
+ template_type = "Boolean"
+ return ValidateMethodParams
+
+ @staticmethod
+ def get_output_pass_model():
+ return RawTypes.OutputPassModel.ByPointer
+
+ @staticmethod
+ def is_heavy_value():
+ return False
+
+ @staticmethod
+ def get_array_item_raw_c_type_text():
+ return "bool"
+
+ @staticmethod
+ def get_raw_type_model():
+ return TypeModel.Bool
+
+ class Object(BaseType):
+ @staticmethod
+ def get_getter_name():
+ return "Object"
+
+ @staticmethod
+ def get_setter_name():
+ return "Value"
+
+ @staticmethod
+ def get_c_initializer():
+ return "InspectorObject::create()"
+
+ @staticmethod
+ def get_output_argument_prefix():
+ return ""
+
+ @staticmethod
+ def get_validate_method_params():
+ class ValidateMethodParams:
+ template_type = "Object"
+ return ValidateMethodParams
+
+ @staticmethod
+ def get_output_pass_model():
+ return RawTypes.OutputPassModel.ByReference
+
+ @staticmethod
+ def is_heavy_value():
+ return True
+
+ @staticmethod
+ def get_array_item_raw_c_type_text():
+ return "InspectorObject"
+
+ @staticmethod
+ def get_raw_type_model():
+ return TypeModel.Object
+
+ class Any(BaseType):
+ @staticmethod
+ def get_getter_name():
+ return "Value"
+
+ get_setter_name = get_getter_name
+
+ @staticmethod
+ def get_c_initializer():
+ raise Exception("Unsupported")
+
+ @staticmethod
+ def get_raw_validator_call_text():
+ return "RuntimeCastHelper::assertAny"
+
+ @staticmethod
+ def get_output_pass_model():
+ return RawTypes.OutputPassModel.ByReference
+
+ @staticmethod
+ def is_heavy_value():
+ return True
+
+ @staticmethod
+ def get_array_item_raw_c_type_text():
+ return "InspectorValue"
+
+ @staticmethod
+ def get_raw_type_model():
+ return TypeModel.Any
+
+ class Array(BaseType):
+ @staticmethod
+ def get_getter_name():
+ return "Array"
+
+ @staticmethod
+ def get_setter_name():
+ return "Value"
+
+ @staticmethod
+ def get_c_initializer():
+ return "InspectorArray::create()"
+
+ @staticmethod
+ def get_output_argument_prefix():
+ return ""
+
+ @staticmethod
+ def get_validate_method_params():
+ class ValidateMethodParams:
+ template_type = "Array"
+ return ValidateMethodParams
+
+ @staticmethod
+ def get_output_pass_model():
+ return RawTypes.OutputPassModel.ByReference
+
+ @staticmethod
+ def is_heavy_value():
+ return True
+
+ @staticmethod
+ def get_array_item_raw_c_type_text():
+ return "InspectorArray"
+
+ @staticmethod
+ def get_raw_type_model():
+ return TypeModel.Array
+
+
+def replace_right_shift(input_str):
+ return input_str.replace(">>", "> >")
+
+
+class CommandReturnPassModel:
+ class ByReference:
+ def __init__(self, var_type, set_condition):
+ self.var_type = var_type
+ self.set_condition = set_condition
+
+ def get_return_var_type(self):
+ return self.var_type
+
+ @staticmethod
+ def get_output_argument_prefix():
+ return ""
+
+ @staticmethod
+ def get_output_to_raw_expression():
+ return "%s"
+
+ def get_output_parameter_type(self):
+ return self.var_type + "&"
+
+ def get_set_return_condition(self):
+ return self.set_condition
+
+ class ByPointer:
+ def __init__(self, var_type):
+ self.var_type = var_type
+
+ def get_return_var_type(self):
+ return self.var_type
+
+ @staticmethod
+ def get_output_argument_prefix():
+ return "&"
+
+ @staticmethod
+ def get_output_to_raw_expression():
+ return "%s"
+
+ def get_output_parameter_type(self):
+ return self.var_type + "*"
+
+ @staticmethod
+ def get_set_return_condition():
+ return None
+
+ class OptOutput:
+ def __init__(self, var_type):
+ self.var_type = var_type
+
+ def get_return_var_type(self):
+ return "TypeBuilder::OptOutput<%s>" % self.var_type
+
+ @staticmethod
+ def get_output_argument_prefix():
+ return "&"
+
+ @staticmethod
+ def get_output_to_raw_expression():
+ return "%s.getValue()"
+
+ def get_output_parameter_type(self):
+ return "TypeBuilder::OptOutput<%s>*" % self.var_type
+
+ @staticmethod
+ def get_set_return_condition():
+ return "%s.isAssigned()"
+
+
+class TypeModel:
+ class RefPtrBased(object):
+ def __init__(self, class_name):
+ self.class_name = class_name
+ self.optional = False
+
+ def get_optional(self):
+ result = TypeModel.RefPtrBased(self.class_name)
+ result.optional = True
+ return result
+
+ def get_command_return_pass_model(self):
+ if self.optional:
+ set_condition = "%s"
+ else:
+ set_condition = None
+ return CommandReturnPassModel.ByReference(replace_right_shift("RefPtr<%s>" % self.class_name), set_condition)
+
+ def get_input_param_type_text(self):
+ return replace_right_shift("PassRefPtr<%s>" % self.class_name)
+
+ @staticmethod
+ def get_event_setter_expression_pattern():
+ return "%s"
+
+ class Enum(object):
+ def __init__(self, base_type_name):
+ self.type_name = base_type_name + "::Enum"
+
+ def get_optional(base_self):
+ class EnumOptional:
+ @classmethod
+ def get_optional(cls):
+ return cls
+
+ @staticmethod
+ def get_command_return_pass_model():
+ return CommandReturnPassModel.OptOutput(base_self.type_name)
+
+ @staticmethod
+ def get_input_param_type_text():
+ return base_self.type_name + "*"
+
+ @staticmethod
+ def get_event_setter_expression_pattern():
+ raise Exception("TODO")
+ return EnumOptional
+
+ def get_command_return_pass_model(self):
+ return CommandReturnPassModel.ByPointer(self.type_name)
+
+ def get_input_param_type_text(self):
+ return self.type_name
+
+ @staticmethod
+ def get_event_setter_expression_pattern():
+ return "%s"
+
+ class ValueType(object):
+ def __init__(self, type_name, is_heavy):
+ self.type_name = type_name
+ self.is_heavy = is_heavy
+
+ def get_optional(self):
+ return self.ValueOptional(self)
+
+ def get_command_return_pass_model(self):
+ return CommandReturnPassModel.ByPointer(self.type_name)
+
+ def get_input_param_type_text(self):
+ if self.is_heavy:
+ return "const %s&" % self.type_name
+ else:
+ return self.type_name
+
+ def get_opt_output_type_(self):
+ return self.type_name
+
+ @staticmethod
+ def get_event_setter_expression_pattern():
+ return "%s"
+
+ class ValueOptional:
+ def __init__(self, base):
+ self.base = base
+
+ def get_optional(self):
+ return self
+
+ def get_command_return_pass_model(self):
+ return CommandReturnPassModel.OptOutput(self.base.get_opt_output_type_())
+
+ def get_input_param_type_text(self):
+ return "const %s* const" % self.base.type_name
+
+ @staticmethod
+ def get_event_setter_expression_pattern():
+ return "*%s"
+
+ class ExactlyInt(ValueType):
+ def __init__(self):
+ TypeModel.ValueType.__init__(self, "int", False)
+
+ def get_input_param_type_text(self):
+ return "TypeBuilder::ExactlyInt"
+
+ def get_opt_output_type_(self):
+ return "TypeBuilder::ExactlyInt"
+
+ @classmethod
+ def init_class(cls):
+ cls.Bool = cls.ValueType("bool", False)
+ if EXACTLY_INT_SUPPORTED:
+ cls.Int = cls.ExactlyInt()
+ else:
+ cls.Int = cls.ValueType("int", False)
+ cls.Number = cls.ValueType("double", False)
+ cls.String = cls.ValueType("String", True,)
+ cls.Object = cls.RefPtrBased("InspectorObject")
+ cls.Array = cls.RefPtrBased("InspectorArray")
+ cls.Any = cls.RefPtrBased("InspectorValue")
+
+TypeModel.init_class()
+
+
+# Collection of InspectorObject class methods that are likely to be overloaded in generated class.
+# We must explicitly import all overloaded methods or they won't be available to user.
+INSPECTOR_OBJECT_SETTER_NAMES = frozenset(["setValue", "setBoolean", "setNumber", "setString", "setValue", "setObject", "setArray"])
+
+
+def fix_type_name(json_name):
+ if json_name in TYPE_NAME_FIX_MAP:
+ fixed = TYPE_NAME_FIX_MAP[json_name]
+
+ class Result(object):
+ class_name = fixed
+
+ @staticmethod
+ def output_comment(writer):
+ writer.newline("// Type originally was named '%s'.\n" % json_name)
+ else:
+
+ class Result(object):
+ class_name = json_name
+
+ @staticmethod
+ def output_comment(writer):
+ pass
+
+ return Result
+
+
+class Writer:
+ def __init__(self, output, indent):
+ self.output = output
+ self.indent = indent
+
+ def newline(self, str):
+ if (self.indent):
+ self.output.append(self.indent)
+ self.output.append(str)
+
+ def append(self, str):
+ self.output.append(str)
+
+ def newline_multiline(self, str):
+ parts = str.split('\n')
+ self.newline(parts[0])
+ for p in parts[1:]:
+ self.output.append('\n')
+ if p:
+ self.newline(p)
+
+ def append_multiline(self, str):
+ parts = str.split('\n')
+ self.append(parts[0])
+ for p in parts[1:]:
+ self.output.append('\n')
+ if p:
+ self.newline(p)
+
+ def get_indent(self):
+ return self.indent
+
+ def get_indented(self, additional_indent):
+ return Writer(self.output, self.indent + additional_indent)
+
+ def insert_writer(self, additional_indent):
+ new_output = []
+ self.output.append(new_output)
+ return Writer(new_output, self.indent + additional_indent)
+
+
+class EnumConstants:
+ map_ = {}
+ constants_ = []
+
+ @classmethod
+ def add_constant(cls, value):
+ if value in cls.map_:
+ return cls.map_[value]
+ else:
+ pos = len(cls.map_)
+ cls.map_[value] = pos
+ cls.constants_.append(value)
+ return pos
+
+ @classmethod
+ def get_enum_constant_code(cls):
+ output = []
+ for item in cls.constants_:
+ output.append(" \"" + item + "\"")
+ return ",\n".join(output) + "\n"
+
+
+# Typebuilder code is generated in several passes: first typedefs, then other classes.
+# Manual pass management is needed because we cannot have forward declarations for typedefs.
+class TypeBuilderPass:
+ TYPEDEF = "typedef"
+ MAIN = "main"
+
+
+class TypeBindings:
+ @staticmethod
+ def create_named_type_declaration(json_typable, context_domain_name, type_data):
+ json_type = type_data.get_json_type()
+
+ class Helper:
+ is_ad_hoc = False
+ full_name_prefix_for_use = "TypeBuilder::" + context_domain_name + "::"
+ full_name_prefix_for_impl = "TypeBuilder::" + context_domain_name + "::"
+
+ @staticmethod
+ def write_doc(writer):
+ if "description" in json_type:
+ writer.newline("/* ")
+ writer.append(json_type["description"])
+ writer.append(" */\n")
+
+ @staticmethod
+ def add_to_forward_listener(forward_listener):
+ forward_listener.add_type_data(type_data)
+
+
+ fixed_type_name = fix_type_name(json_type["id"])
+ return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper)
+
+ @staticmethod
+ def create_ad_hoc_type_declaration(json_typable, context_domain_name, ad_hoc_type_context):
+ class Helper:
+ is_ad_hoc = True
+ full_name_prefix_for_use = ad_hoc_type_context.container_relative_name_prefix
+ full_name_prefix_for_impl = ad_hoc_type_context.container_full_name_prefix
+
+ @staticmethod
+ def write_doc(writer):
+ pass
+
+ @staticmethod
+ def add_to_forward_listener(forward_listener):
+ pass
+ fixed_type_name = ad_hoc_type_context.get_type_name_fix()
+ return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper)
+
+ @staticmethod
+ def create_type_declaration_(json_typable, context_domain_name, fixed_type_name, helper):
+ if json_typable["type"] == "string":
+ if "enum" in json_typable:
+
+ class EnumBinding:
+ need_user_runtime_cast_ = False
+ need_internal_runtime_cast_ = False
+
+ @classmethod
+ def resolve_inner(cls, resolve_context):
+ pass
+
+ @classmethod
+ def request_user_runtime_cast(cls, request):
+ if request:
+ cls.need_user_runtime_cast_ = True
+ request.acknowledge()
+
+ @classmethod
+ def request_internal_runtime_cast(cls):
+ cls.need_internal_runtime_cast_ = True
+
+ @classmethod
+ def get_code_generator(enum_binding_cls):
+ #FIXME: generate ad-hoc enums too once we figure out how to better implement them in C++.
+ comment_out = helper.is_ad_hoc
+
+ class CodeGenerator:
+ @staticmethod
+ def generate_type_builder(writer, generate_context):
+ enum = json_typable["enum"]
+ helper.write_doc(writer)
+ enum_name = fixed_type_name.class_name
+ fixed_type_name.output_comment(writer)
+ writer.newline("struct ")
+ writer.append(enum_name)
+ writer.append(" {\n")
+ writer.newline(" enum Enum {\n")
+ for enum_item in enum:
+ enum_pos = EnumConstants.add_constant(enum_item)
+
+ item_c_name = enum_item.replace('-', '_')
+ item_c_name = Capitalizer.lower_camel_case_to_upper(item_c_name)
+ if item_c_name in TYPE_NAME_FIX_MAP:
+ item_c_name = TYPE_NAME_FIX_MAP[item_c_name]
+ writer.newline(" ")
+ writer.append(item_c_name)
+ writer.append(" = ")
+ writer.append("%s" % enum_pos)
+ writer.append(",\n")
+ writer.newline(" };\n")
+ if enum_binding_cls.need_user_runtime_cast_:
+ raise Exception("Not yet implemented")
+
+ if enum_binding_cls.need_internal_runtime_cast_:
+ writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
+ writer.newline(" static void assertCorrectValue(InspectorValue* value);\n")
+ writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME)
+
+ validator_writer = generate_context.validator_writer
+
+ domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name)
+
+ validator_writer.newline("void %s%s::assertCorrectValue(InspectorValue* value)\n" % (helper.full_name_prefix_for_impl, enum_name))
+ validator_writer.newline("{\n")
+ validator_writer.newline(" WTF::String s;\n")
+ validator_writer.newline(" bool cast_res = value->asString(&s);\n")
+ validator_writer.newline(" ASSERT(cast_res);\n")
+ if len(enum) > 0:
+ condition_list = []
+ for enum_item in enum:
+ enum_pos = EnumConstants.add_constant(enum_item)
+ condition_list.append("s == \"%s\"" % enum_item)
+ validator_writer.newline(" ASSERT(%s);\n" % " || ".join(condition_list))
+ validator_writer.newline("}\n")
+
+ validator_writer.newline("\n\n")
+
+ writer.newline("}; // struct ")
+ writer.append(enum_name)
+ writer.append("\n\n")
+
+ @staticmethod
+ def register_use(forward_listener):
+ pass
+
+ @staticmethod
+ def get_generate_pass_id():
+ return TypeBuilderPass.MAIN
+
+ return CodeGenerator
+
+ @classmethod
+ def get_validator_call_text(cls):
+ return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue"
+
+ @classmethod
+ def get_array_item_c_type_text(cls):
+ return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::Enum"
+
+ @staticmethod
+ def get_setter_value_expression_pattern():
+ return "TypeBuilder::getEnumConstantValue(%s)"
+
+ @staticmethod
+ def reduce_to_raw_type():
+ return RawTypes.String
+
+ @staticmethod
+ def get_type_model():
+ return TypeModel.Enum(helper.full_name_prefix_for_use + fixed_type_name.class_name)
+
+ return EnumBinding
+ else:
+ if helper.is_ad_hoc:
+
+ class PlainString:
+ @classmethod
+ def resolve_inner(cls, resolve_context):
+ pass
+
+ @staticmethod
+ def request_user_runtime_cast(request):
+ raise Exception("Unsupported")
+
+ @staticmethod
+ def request_internal_runtime_cast():
+ pass
+
+ @staticmethod
+ def get_code_generator():
+ return None
+
+ @classmethod
+ def get_validator_call_text(cls):
+ return RawTypes.String.get_raw_validator_call_text()
+
+ @staticmethod
+ def reduce_to_raw_type():
+ return RawTypes.String
+
+ @staticmethod
+ def get_type_model():
+ return TypeModel.String
+
+ @staticmethod
+ def get_setter_value_expression_pattern():
+ return None
+
+ @classmethod
+ def get_array_item_c_type_text(cls):
+ return cls.reduce_to_raw_type().get_array_item_raw_c_type_text()
+
+ return PlainString
+
+ else:
+
+ class TypedefString:
+ @classmethod
+ def resolve_inner(cls, resolve_context):
+ pass
+
+ @staticmethod
+ def request_user_runtime_cast(request):
+ raise Exception("Unsupported")
+
+ @staticmethod
+ def request_internal_runtime_cast():
+ RawTypes.String.request_raw_internal_runtime_cast()
+
+ @staticmethod
+ def get_code_generator():
+ class CodeGenerator:
+ @staticmethod
+ def generate_type_builder(writer, generate_context):
+ helper.write_doc(writer)
+ fixed_type_name.output_comment(writer)
+ writer.newline("typedef String ")
+ writer.append(fixed_type_name.class_name)
+ writer.append(";\n\n")
+
+ @staticmethod
+ def register_use(forward_listener):
+ pass
+
+ @staticmethod
+ def get_generate_pass_id():
+ return TypeBuilderPass.TYPEDEF
+
+ return CodeGenerator
+
+ @classmethod
+ def get_validator_call_text(cls):
+ return RawTypes.String.get_raw_validator_call_text()
+
+ @staticmethod
+ def reduce_to_raw_type():
+ return RawTypes.String
+
+ @staticmethod
+ def get_type_model():
+ return TypeModel.ValueType("%s%s" % (helper.full_name_prefix_for_use, fixed_type_name.class_name), True)
+
+ @staticmethod
+ def get_setter_value_expression_pattern():
+ return None
+
+ @classmethod
+ def get_array_item_c_type_text(cls):
+ return "const %s%s&" % (helper.full_name_prefix_for_use, fixed_type_name.class_name)
+
+ return TypedefString
+
+ elif json_typable["type"] == "object":
+ if "properties" in json_typable:
+
+ class ClassBinding:
+ resolve_data_ = None
+ need_user_runtime_cast_ = False
+ need_internal_runtime_cast_ = False
+
+ @classmethod
+ def resolve_inner(cls, resolve_context):
+ if cls.resolve_data_:
+ return
+
+ properties = json_typable["properties"]
+ main = []
+ optional = []
+
+ ad_hoc_type_list = []
+
+ for prop in properties:
+ prop_name = prop["name"]
+ ad_hoc_type_context = cls.AdHocTypeContextImpl(prop_name, fixed_type_name.class_name, resolve_context, ad_hoc_type_list, helper.full_name_prefix_for_impl)
+ binding = resolve_param_type(prop, context_domain_name, ad_hoc_type_context)
+
+ code_generator = binding.get_code_generator()
+ if code_generator:
+ code_generator.register_use(resolve_context.forward_listener)
+
+ class PropertyData:
+ param_type_binding = binding
+ p = prop
+
+ if prop.get("optional"):
+ optional.append(PropertyData)
+ else:
+ main.append(PropertyData)
+
+ class ResolveData:
+ main_properties = main
+ optional_properties = optional
+ ad_hoc_types = ad_hoc_type_list
+
+ cls.resolve_data_ = ResolveData
+
+ for ad_hoc in ad_hoc_type_list:
+ ad_hoc.resolve_inner(resolve_context)
+
+ @classmethod
+ def request_user_runtime_cast(cls, request):
+ if not request:
+ return
+ cls.need_user_runtime_cast_ = True
+ request.acknowledge()
+ cls.request_internal_runtime_cast()
+
+ @classmethod
+ def request_internal_runtime_cast(cls):
+ if cls.need_internal_runtime_cast_:
+ return
+ cls.need_internal_runtime_cast_ = True
+ for p in cls.resolve_data_.main_properties:
+ p.param_type_binding.request_internal_runtime_cast()
+ for p in cls.resolve_data_.optional_properties:
+ p.param_type_binding.request_internal_runtime_cast()
+
+ @classmethod
+ def get_code_generator(class_binding_cls):
+ class CodeGenerator:
+ @classmethod
+ def generate_type_builder(cls, writer, generate_context):
+ resolve_data = class_binding_cls.resolve_data_
+ helper.write_doc(writer)
+ class_name = fixed_type_name.class_name
+
+ is_open_type = (context_domain_name + "." + class_name) in TYPES_WITH_OPEN_FIELD_LIST_SET
+
+ fixed_type_name.output_comment(writer)
+ writer.newline("class ")
+ writer.append(class_name)
+ writer.append(" : public ")
+ if is_open_type:
+ writer.append("InspectorObject")
+ else:
+ writer.append("InspectorObjectBase")
+ writer.append(" {\n")
+ writer.newline("public:\n")
+ ad_hoc_type_writer = writer.insert_writer(" ")
+
+ for ad_hoc_type in resolve_data.ad_hoc_types:
+ code_generator = ad_hoc_type.get_code_generator()
+ if code_generator:
+ code_generator.generate_type_builder(ad_hoc_type_writer, generate_context)
+
+ writer.newline_multiline(
+""" enum {
+ NoFieldsSet = 0,
+""")
+
+ state_enum_items = []
+ if len(resolve_data.main_properties) > 0:
+ pos = 0
+ for prop_data in resolve_data.main_properties:
+ item_name = Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]) + "Set"
+ state_enum_items.append(item_name)
+ writer.newline(" %s = 1 << %s,\n" % (item_name, pos))
+ pos += 1
+ all_fields_set_value = "(" + (" | ".join(state_enum_items)) + ")"
+ else:
+ all_fields_set_value = "0"
+
+ writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_1
+ % (all_fields_set_value, class_name, class_name))
+
+ pos = 0
+ for prop_data in resolve_data.main_properties:
+ prop_name = prop_data.p["name"]
+
+ param_type_binding = prop_data.param_type_binding
+ param_raw_type = param_type_binding.reduce_to_raw_type()
+
+ writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_2
+ % (state_enum_items[pos],
+ Capitalizer.lower_camel_case_to_upper(prop_name),
+ param_type_binding.get_type_model().get_input_param_type_text(),
+ state_enum_items[pos], prop_name,
+ param_raw_type.get_setter_name(), prop_name,
+ format_setter_value_expression(param_type_binding, "value"),
+ state_enum_items[pos]))
+
+ pos += 1
+
+ writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_3
+ % (class_name, class_name, class_name, class_name, class_name))
+
+ writer.newline(" /*\n")
+ writer.newline(" * Synthetic constructor:\n")
+ writer.newline(" * RefPtr<%s> result = %s::create()" % (class_name, class_name))
+ for prop_data in resolve_data.main_properties:
+ writer.append_multiline("\n * .set%s(...)" % Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]))
+ writer.append_multiline(";\n */\n")
+
+ writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_4)
+
+ writer.newline(" typedef TypeBuilder::StructItemTraits ItemTraits;\n")
+
+ for prop_data in resolve_data.optional_properties:
+ prop_name = prop_data.p["name"]
+ param_type_binding = prop_data.param_type_binding
+ setter_name = "set%s" % Capitalizer.lower_camel_case_to_upper(prop_name)
+
+ writer.append_multiline("\n void %s" % setter_name)
+ writer.append("(%s value)\n" % param_type_binding.get_type_model().get_input_param_type_text())
+ writer.newline(" {\n")
+ writer.newline(" this->set%s(\"%s\", %s);\n"
+ % (param_type_binding.reduce_to_raw_type().get_setter_name(), prop_data.p["name"],
+ format_setter_value_expression(param_type_binding, "value")))
+ writer.newline(" }\n")
+
+
+ if setter_name in INSPECTOR_OBJECT_SETTER_NAMES:
+ writer.newline(" using InspectorObjectBase::%s;\n\n" % setter_name)
+
+ if class_binding_cls.need_user_runtime_cast_:
+ writer.newline(" static PassRefPtr<%s> runtimeCast(PassRefPtr<InspectorValue> value)\n" % class_name)
+ writer.newline(" {\n")
+ writer.newline(" RefPtr<InspectorObject> object;\n")
+ writer.newline(" bool castRes = value->asObject(&object);\n")
+ writer.newline(" ASSERT_UNUSED(castRes, castRes);\n")
+ writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
+ writer.newline(" assertCorrectValue(object.get());\n")
+ writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME)
+ writer.newline(" COMPILE_ASSERT(sizeof(%s) == sizeof(InspectorObjectBase), type_cast_problem);\n" % class_name)
+ writer.newline(" return static_cast<%s*>(static_cast<InspectorObjectBase*>(object.get()));\n" % class_name)
+ writer.newline(" }\n")
+ writer.append("\n")
+
+ if class_binding_cls.need_internal_runtime_cast_:
+ writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
+ writer.newline(" static void assertCorrectValue(InspectorValue* value);\n")
+ writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME)
+
+ closed_field_set = (context_domain_name + "." + class_name) not in TYPES_WITH_OPEN_FIELD_LIST_SET
+
+ validator_writer = generate_context.validator_writer
+
+ domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name)
+
+ validator_writer.newline("void %s%s::assertCorrectValue(InspectorValue* value)\n" % (helper.full_name_prefix_for_impl, class_name))
+ validator_writer.newline("{\n")
+ validator_writer.newline(" RefPtr<InspectorObject> object;\n")
+ validator_writer.newline(" bool castRes = value->asObject(&object);\n")
+ validator_writer.newline(" ASSERT_UNUSED(castRes, castRes);\n")
+ for prop_data in resolve_data.main_properties:
+ validator_writer.newline(" {\n")
+ it_name = "%sPos" % prop_data.p["name"]
+ validator_writer.newline(" InspectorObject::iterator %s;\n" % it_name)
+ validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
+ validator_writer.newline(" ASSERT(%s != object->end());\n" % it_name)
+ validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name))
+ validator_writer.newline(" }\n")
+
+ if closed_field_set:
+ validator_writer.newline(" int foundPropertiesCount = %s;\n" % len(resolve_data.main_properties))
+
+ for prop_data in resolve_data.optional_properties:
+ validator_writer.newline(" {\n")
+ it_name = "%sPos" % prop_data.p["name"]
+ validator_writer.newline(" InspectorObject::iterator %s;\n" % it_name)
+ validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
+ validator_writer.newline(" if (%s != object->end()) {\n" % it_name)
+ validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name))
+ if closed_field_set:
+ validator_writer.newline(" ++foundPropertiesCount;\n")
+ validator_writer.newline(" }\n")
+ validator_writer.newline(" }\n")
+
+ if closed_field_set:
+ validator_writer.newline(" if (foundPropertiesCount != object->size()) {\n")
+ validator_writer.newline(" FATAL(\"Unexpected properties in object: %s\\n\", object->toJSONString().ascii().data());\n")
+ validator_writer.newline(" }\n")
+ validator_writer.newline("}\n")
+
+ validator_writer.newline("\n\n")
+
+ if is_open_type:
+ cpp_writer = generate_context.cpp_writer
+ writer.append("\n")
+ writer.newline(" // Property names for type generated as open.\n")
+ for prop_data in resolve_data.main_properties + resolve_data.optional_properties:
+ prop_name = prop_data.p["name"]
+ prop_field_name = Capitalizer.lower_camel_case_to_upper(prop_name)
+ writer.newline(" static const char* %s;\n" % (prop_field_name))
+ cpp_writer.newline("const char* %s%s::%s = \"%s\";\n" % (helper.full_name_prefix_for_impl, class_name, prop_field_name, prop_name))
+
+
+ writer.newline("};\n\n")
+
+ @staticmethod
+ def generate_forward_declaration(writer):
+ class_name = fixed_type_name.class_name
+ writer.newline("class ")
+ writer.append(class_name)
+ writer.append(";\n")
+
+ @staticmethod
+ def register_use(forward_listener):
+ helper.add_to_forward_listener(forward_listener)
+
+ @staticmethod
+ def get_generate_pass_id():
+ return TypeBuilderPass.MAIN
+
+ return CodeGenerator
+
+ @staticmethod
+ def get_validator_call_text():
+ return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue"
+
+ @classmethod
+ def get_array_item_c_type_text(cls):
+ return helper.full_name_prefix_for_use + fixed_type_name.class_name
+
+ @staticmethod
+ def get_setter_value_expression_pattern():
+ return None
+
+ @staticmethod
+ def reduce_to_raw_type():
+ return RawTypes.Object
+
+ @staticmethod
+ def get_type_model():
+ return TypeModel.RefPtrBased(helper.full_name_prefix_for_use + fixed_type_name.class_name)
+
+ class AdHocTypeContextImpl:
+ def __init__(self, property_name, class_name, resolve_context, ad_hoc_type_list, parent_full_name_prefix):
+ self.property_name = property_name
+ self.class_name = class_name
+ self.resolve_context = resolve_context
+ self.ad_hoc_type_list = ad_hoc_type_list
+ self.container_full_name_prefix = parent_full_name_prefix + class_name + "::"
+ self.container_relative_name_prefix = ""
+
+ def get_type_name_fix(self):
+ class NameFix:
+ class_name = Capitalizer.lower_camel_case_to_upper(self.property_name)
+
+ @staticmethod
+ def output_comment(writer):
+ writer.newline("// Named after property name '%s' while generating %s.\n" % (self.property_name, self.class_name))
+
+ return NameFix
+
+ def add_type(self, binding):
+ self.ad_hoc_type_list.append(binding)
+
+ return ClassBinding
+ else:
+
+ class PlainObjectBinding:
+ @classmethod
+ def resolve_inner(cls, resolve_context):
+ pass
+
+ @staticmethod
+ def request_user_runtime_cast(request):
+ pass
+
+ @staticmethod
+ def request_internal_runtime_cast():
+ RawTypes.Object.request_raw_internal_runtime_cast()
+
+ @staticmethod
+ def get_code_generator():
+ pass
+
+ @staticmethod
+ def get_validator_call_text():
+ return "RuntimeCastHelper::assertType<InspectorValue::TypeObject>"
+
+ @classmethod
+ def get_array_item_c_type_text(cls):
+ return cls.reduce_to_raw_type().get_array_item_raw_c_type_text()
+
+ @staticmethod
+ def get_setter_value_expression_pattern():
+ return None
+
+ @staticmethod
+ def reduce_to_raw_type():
+ return RawTypes.Object
+
+ @staticmethod
+ def get_type_model():
+ return TypeModel.Object
+
+ return PlainObjectBinding
+ elif json_typable["type"] == "array":
+ if "items" in json_typable:
+
+ ad_hoc_types = []
+
+ class AdHocTypeContext:
+ container_full_name_prefix = "<not yet defined>"
+ container_relative_name_prefix = ""
+
+ @staticmethod
+ def get_type_name_fix():
+ return fixed_type_name
+
+ @staticmethod
+ def add_type(binding):
+ ad_hoc_types.append(binding)
+
+ item_binding = resolve_param_type(json_typable["items"], context_domain_name, AdHocTypeContext)
+
+ class ArrayBinding:
+ resolve_data_ = None
+ need_internal_runtime_cast_ = False
+
+ @classmethod
+ def resolve_inner(cls, resolve_context):
+ if cls.resolve_data_:
+ return
+
+ class ResolveData:
+ item_type_binding = item_binding
+ ad_hoc_type_list = ad_hoc_types
+
+ cls.resolve_data_ = ResolveData
+
+ for t in ad_hoc_types:
+ t.resolve_inner(resolve_context)
+
+ @classmethod
+ def request_user_runtime_cast(cls, request):
+ raise Exception("Not implemented yet")
+
+ @classmethod
+ def request_internal_runtime_cast(cls):
+ if cls.need_internal_runtime_cast_:
+ return
+ cls.need_internal_runtime_cast_ = True
+ cls.resolve_data_.item_type_binding.request_internal_runtime_cast()
+
+ @classmethod
+ def get_code_generator(array_binding_cls):
+
+ class CodeGenerator:
+ @staticmethod
+ def generate_type_builder(writer, generate_context):
+ ad_hoc_type_writer = writer
+
+ resolve_data = array_binding_cls.resolve_data_
+
+ for ad_hoc_type in resolve_data.ad_hoc_type_list:
+ code_generator = ad_hoc_type.get_code_generator()
+ if code_generator:
+ code_generator.generate_type_builder(ad_hoc_type_writer, generate_context)
+
+ @staticmethod
+ def generate_forward_declaration(writer):
+ pass
+
+ @staticmethod
+ def register_use(forward_listener):
+ item_code_generator = item_binding.get_code_generator()
+ if item_code_generator:
+ item_code_generator.register_use(forward_listener)
+
+ @staticmethod
+ def get_generate_pass_id():
+ return TypeBuilderPass.MAIN
+
+ return CodeGenerator
+
+ @classmethod
+ def get_validator_call_text(cls):
+ return cls.get_array_item_c_type_text() + "::assertCorrectValue"
+
+ @classmethod
+ def get_array_item_c_type_text(cls):
+ return replace_right_shift("TypeBuilder::Array<%s>" % cls.resolve_data_.item_type_binding.get_array_item_c_type_text())
+
+ @staticmethod
+ def get_setter_value_expression_pattern():
+ return None
+
+ @staticmethod
+ def reduce_to_raw_type():
+ return RawTypes.Array
+
+ @classmethod
+ def get_type_model(cls):
+ return TypeModel.RefPtrBased(cls.get_array_item_c_type_text())
+
+ return ArrayBinding
+ else:
+ # Fall-through to raw type.
+ pass
+
+ raw_type = RawTypes.get(json_typable["type"])
+
+ return RawTypeBinding(raw_type)
+
+
+class RawTypeBinding:
+ def __init__(self, raw_type):
+ self.raw_type_ = raw_type
+
+ def resolve_inner(self, resolve_context):
+ pass
+
+ def request_user_runtime_cast(self, request):
+ raise Exception("Unsupported")
+
+ def request_internal_runtime_cast(self):
+ self.raw_type_.request_raw_internal_runtime_cast()
+
+ def get_code_generator(self):
+ return None
+
+ def get_validator_call_text(self):
+ return self.raw_type_.get_raw_validator_call_text()
+
+ def get_array_item_c_type_text(self):
+ return self.raw_type_.get_array_item_raw_c_type_text()
+
+ def get_setter_value_expression_pattern(self):
+ return None
+
+ def reduce_to_raw_type(self):
+ return self.raw_type_
+
+ def get_type_model(self):
+ return self.raw_type_.get_raw_type_model()
+
+
+class TypeData(object):
+ def __init__(self, json_type, json_domain, domain_data):
+ self.json_type_ = json_type
+ self.json_domain_ = json_domain
+ self.domain_data_ = domain_data
+
+ if "type" not in json_type:
+ raise Exception("Unknown type")
+
+ json_type_name = json_type["type"]
+ raw_type = RawTypes.get(json_type_name)
+ self.raw_type_ = raw_type
+ self.binding_being_resolved_ = False
+ self.binding_ = None
+
+ def get_raw_type(self):
+ return self.raw_type_
+
+ def get_binding(self):
+ if not self.binding_:
+ if self.binding_being_resolved_:
+ raise Error("Type %s is already being resolved" % self.json_type_["type"])
+ # Resolve only lazily, because resolving one named type may require resolving some other named type.
+ self.binding_being_resolved_ = True
+ try:
+ self.binding_ = TypeBindings.create_named_type_declaration(self.json_type_, self.json_domain_["domain"], self)
+ finally:
+ self.binding_being_resolved_ = False
+
+ return self.binding_
+
+ def get_json_type(self):
+ return self.json_type_
+
+ def get_name(self):
+ return self.json_type_["id"]
+
+ def get_domain_name(self):
+ return self.json_domain_["domain"]
+
+
+class DomainData:
+ def __init__(self, json_domain):
+ self.json_domain = json_domain
+ self.types_ = []
+
+ def add_type(self, type_data):
+ self.types_.append(type_data)
+
+ def name(self):
+ return self.json_domain["domain"]
+
+ def types(self):
+ return self.types_
+
+
+class TypeMap:
+ def __init__(self, api):
+ self.map_ = {}
+ self.domains_ = []
+ for json_domain in api["domains"]:
+ domain_name = json_domain["domain"]
+
+ domain_map = {}
+ self.map_[domain_name] = domain_map
+
+ domain_data = DomainData(json_domain)
+ self.domains_.append(domain_data)
+
+ if "types" in json_domain:
+ for json_type in json_domain["types"]:
+ type_name = json_type["id"]
+ type_data = TypeData(json_type, json_domain, domain_data)
+ domain_map[type_name] = type_data
+ domain_data.add_type(type_data)
+
+ def domains(self):
+ return self.domains_
+
+ def get(self, domain_name, type_name):
+ return self.map_[domain_name][type_name]
+
+
+def resolve_param_type(json_parameter, scope_domain_name, ad_hoc_type_context):
+ if "$ref" in json_parameter:
+ json_ref = json_parameter["$ref"]
+ type_data = get_ref_data(json_ref, scope_domain_name)
+ return type_data.get_binding()
+ elif "type" in json_parameter:
+ result = TypeBindings.create_ad_hoc_type_declaration(json_parameter, scope_domain_name, ad_hoc_type_context)
+ ad_hoc_type_context.add_type(result)
+ return result
+ else:
+ raise Exception("Unknown type")
+
+def resolve_param_raw_type(json_parameter, scope_domain_name):
+ if "$ref" in json_parameter:
+ json_ref = json_parameter["$ref"]
+ type_data = get_ref_data(json_ref, scope_domain_name)
+ return type_data.get_raw_type()
+ elif "type" in json_parameter:
+ json_type = json_parameter["type"]
+ return RawTypes.get(json_type)
+ else:
+ raise Exception("Unknown type")
+
+
+def get_ref_data(json_ref, scope_domain_name):
+ dot_pos = json_ref.find(".")
+ if dot_pos == -1:
+ domain_name = scope_domain_name
+ type_name = json_ref
+ else:
+ domain_name = json_ref[:dot_pos]
+ type_name = json_ref[dot_pos + 1:]
+
+ return type_map.get(domain_name, type_name)
+
+
+input_file = open(input_json_filename, "r")
+json_string = input_file.read()
+json_api = json.loads(json_string)
+
+
+class Templates:
+ def get_this_script_path_(absolute_path):
+ absolute_path = os.path.abspath(absolute_path)
+ components = []
+
+ def fill_recursive(path_part, depth):
+ if depth <= 0 or path_part == '/':
+ return
+ fill_recursive(os.path.dirname(path_part), depth - 1)
+ components.append(os.path.basename(path_part))
+
+ # Typical path is /Source/WebCore/inspector/CodeGeneratorInspector.py
+ # Let's take 4 components from the real path then.
+ fill_recursive(absolute_path, 4)
+
+ return "/".join(components)
+
+ file_header_ = ("// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) +
+"""// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+""")
+
+ frontend_domain_class = string.Template(CodeGeneratorInspectorStrings.frontend_domain_class)
+ backend_method = string.Template(CodeGeneratorInspectorStrings.backend_method)
+ frontend_method = string.Template(CodeGeneratorInspectorStrings.frontend_method)
+ callback_method = string.Template(CodeGeneratorInspectorStrings.callback_method)
+ frontend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_h)
+ backend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_h)
+ backend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_cpp)
+ frontend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_cpp)
+ typebuilder_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_h)
+ typebuilder_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_cpp)
+ param_container_access_code = CodeGeneratorInspectorStrings.param_container_access_code
+
+
+
+
+
+type_map = TypeMap(json_api)
+
+
+class NeedRuntimeCastRequest:
+ def __init__(self):
+ self.ack_ = None
+
+ def acknowledge(self):
+ self.ack_ = True
+
+ def is_acknowledged(self):
+ return self.ack_
+
+
+def resolve_all_types():
+ runtime_cast_generate_requests = {}
+ for type_name in TYPES_WITH_RUNTIME_CAST_SET:
+ runtime_cast_generate_requests[type_name] = NeedRuntimeCastRequest()
+
+ class ForwardListener:
+ type_data_set = set()
+ already_declared_set = set()
+
+ @classmethod
+ def add_type_data(cls, type_data):
+ if type_data not in cls.already_declared_set:
+ cls.type_data_set.add(type_data)
+
+ class ResolveContext:
+ forward_listener = ForwardListener
+
+ for domain_data in type_map.domains():
+ for type_data in domain_data.types():
+ # Do not generate forwards for this type any longer.
+ ForwardListener.already_declared_set.add(type_data)
+
+ binding = type_data.get_binding()
+ binding.resolve_inner(ResolveContext)
+
+ for domain_data in type_map.domains():
+ for type_data in domain_data.types():
+ full_type_name = "%s.%s" % (type_data.get_domain_name(), type_data.get_name())
+ request = runtime_cast_generate_requests.pop(full_type_name, None)
+ binding = type_data.get_binding()
+ if request:
+ binding.request_user_runtime_cast(request)
+
+ if request and not request.is_acknowledged():
+ raise Exception("Failed to generate runtimeCast in " + full_type_name)
+
+ for full_type_name in runtime_cast_generate_requests:
+ raise Exception("Failed to generate runtimeCast. Type " + full_type_name + " not found")
+
+ return ForwardListener
+
+
+global_forward_listener = resolve_all_types()
+
+
+def get_annotated_type_text(raw_type, annotated_type):
+ if annotated_type != raw_type:
+ return "/*%s*/ %s" % (annotated_type, raw_type)
+ else:
+ return raw_type
+
+
+def format_setter_value_expression(param_type_binding, value_ref):
+ pattern = param_type_binding.get_setter_value_expression_pattern()
+ if pattern:
+ return pattern % value_ref
+ else:
+ return value_ref
+
+class Generator:
+ frontend_class_field_lines = []
+ frontend_domain_class_lines = []
+
+ method_name_enum_list = []
+ backend_method_declaration_list = []
+ backend_method_implementation_list = []
+ backend_method_name_declaration_list = []
+ method_handler_list = []
+ frontend_method_list = []
+
+ backend_virtual_setters_list = []
+ backend_agent_interface_list = []
+ backend_setters_list = []
+ backend_constructor_init_list = []
+ backend_field_list = []
+ frontend_constructor_init_list = []
+ type_builder_fragments = []
+ type_builder_forwards = []
+ validator_impl_list = []
+ type_builder_impl_list = []
+
+
+ @staticmethod
+ def go():
+ Generator.process_types(type_map)
+
+ first_cycle_guardable_list_list = [
+ Generator.backend_method_declaration_list,
+ Generator.backend_method_implementation_list,
+ Generator.backend_method_name_declaration_list,
+ Generator.backend_agent_interface_list,
+ Generator.frontend_class_field_lines,
+ Generator.frontend_constructor_init_list,
+ Generator.frontend_domain_class_lines,
+ Generator.frontend_method_list,
+ Generator.method_handler_list,
+ Generator.method_name_enum_list,
+ Generator.backend_constructor_init_list,
+ Generator.backend_virtual_setters_list,
+ Generator.backend_setters_list,
+ Generator.backend_field_list]
+
+ for json_domain in json_api["domains"]:
+ domain_name = json_domain["domain"]
+ domain_name_lower = domain_name.lower()
+
+ domain_fixes = DomainNameFixes.get_fixed_data(domain_name)
+
+ agent_field_name = domain_fixes.agent_field_name
+
+ frontend_method_declaration_lines = []
+
+ if "events" in json_domain:
+ for json_event in json_domain["events"]:
+ Generator.process_event(json_event, domain_name, frontend_method_declaration_lines)
+
+ Generator.frontend_class_field_lines.append(" %s m_%s;\n" % (domain_name, domain_name_lower))
+ if Generator.frontend_constructor_init_list:
+ Generator.frontend_constructor_init_list.append(" , ")
+ Generator.frontend_constructor_init_list.append("m_%s(inspectorFrontendChannel)\n" % domain_name_lower)
+ Generator.frontend_domain_class_lines.append(Templates.frontend_domain_class.substitute(None,
+ domainClassName=domain_name,
+ domainFieldName=domain_name_lower,
+ frontendDomainMethodDeclarations="".join(flatten_list(frontend_method_declaration_lines))))
+
+ agent_interface_name = Capitalizer.lower_camel_case_to_upper(domain_name) + "CommandHandler"
+ Generator.backend_agent_interface_list.append(" class %s {\n" % agent_interface_name)
+ Generator.backend_agent_interface_list.append(" public:\n")
+ if "commands" in json_domain:
+ for json_command in json_domain["commands"]:
+ Generator.process_command(json_command, domain_name, agent_field_name, agent_interface_name)
+ Generator.backend_agent_interface_list.append("\n protected:\n")
+ Generator.backend_agent_interface_list.append(" virtual ~%s() { }\n" % agent_interface_name)
+ Generator.backend_agent_interface_list.append(" };\n\n")
+
+ Generator.backend_constructor_init_list.append(" , m_%s(0)" % agent_field_name)
+ Generator.backend_virtual_setters_list.append(" virtual void registerAgent(%s* %s) = 0;" % (agent_interface_name, agent_field_name))
+ Generator.backend_setters_list.append(" virtual void registerAgent(%s* %s) { ASSERT(!m_%s); m_%s = %s; }" % (agent_interface_name, agent_field_name, agent_field_name, agent_field_name, agent_field_name))
+ Generator.backend_field_list.append(" %s* m_%s;" % (agent_interface_name, agent_field_name))
+
+ @staticmethod
+ def process_event(json_event, domain_name, frontend_method_declaration_lines):
+ event_name = json_event["name"]
+
+ ad_hoc_type_output = []
+ frontend_method_declaration_lines.append(ad_hoc_type_output)
+ ad_hoc_type_writer = Writer(ad_hoc_type_output, " ")
+
+ decl_parameter_list = []
+
+ json_parameters = json_event.get("parameters")
+ Generator.generate_send_method(json_parameters, event_name, domain_name, ad_hoc_type_writer,
+ decl_parameter_list,
+ Generator.EventMethodStructTemplate,
+ Generator.frontend_method_list, Templates.frontend_method, {"eventName": event_name})
+
+ frontend_method_declaration_lines.append(
+ " void %s(%s);\n" % (event_name, ", ".join(decl_parameter_list)))
+
+ class EventMethodStructTemplate:
+ @staticmethod
+ def append_prolog(line_list):
+ line_list.append(" RefPtr<InspectorObject> paramsObject = InspectorObject::create();\n")
+
+ @staticmethod
+ def append_epilog(line_list):
+ line_list.append(" jsonMessage->setObject(\"params\", paramsObject);\n")
+
+ container_name = "paramsObject"
+
+ @staticmethod
+ def process_command(json_command, domain_name, agent_field_name, agent_interface_name):
+ json_command_name = json_command["name"]
+
+ cmd_enum_name = "k%s_%sCmd" % (domain_name, json_command["name"])
+
+ Generator.method_name_enum_list.append(" %s," % cmd_enum_name)
+ Generator.method_handler_list.append(" &InspectorBackendDispatcherImpl::%s_%s," % (domain_name, json_command_name))
+ Generator.backend_method_declaration_list.append(" void %s_%s(long callId, InspectorObject* requestMessageObject);" % (domain_name, json_command_name))
+
+ ad_hoc_type_output = []
+ Generator.backend_agent_interface_list.append(ad_hoc_type_output)
+ ad_hoc_type_writer = Writer(ad_hoc_type_output, " ")
+
+ Generator.backend_agent_interface_list.append(" virtual void %s(ErrorString*" % json_command_name)
+
+ method_in_code = ""
+ method_out_code = ""
+ agent_call_param_list = []
+ response_cook_list = []
+ request_message_param = ""
+ if "parameters" in json_command:
+ json_params = json_command["parameters"]
+ method_in_code += Templates.param_container_access_code
+ request_message_param = " requestMessageObject"
+ js_param_list = []
+
+ for json_parameter in json_params:
+ json_param_name = json_parameter["name"]
+ param_raw_type = resolve_param_raw_type(json_parameter, domain_name)
+
+ getter_name = param_raw_type.get_getter_name()
+
+ optional = json_parameter.get("optional")
+
+ non_optional_type_model = param_raw_type.get_raw_type_model()
+ if optional:
+ type_model = non_optional_type_model.get_optional()
+ else:
+ type_model = non_optional_type_model
+
+ if optional:
+ code = (" bool %s_valueFound = false;\n"
+ " %s in_%s = get%s(paramsContainerPtr, \"%s\", &%s_valueFound, protocolErrorsPtr);\n" %
+ (json_param_name, non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name, json_param_name))
+ param = ", %s_valueFound ? &in_%s : 0" % (json_param_name, json_param_name)
+ # FIXME: pass optional refptr-values as PassRefPtr
+ formal_param_type_pattern = "const %s*"
+ else:
+ code = (" %s in_%s = get%s(paramsContainerPtr, \"%s\", 0, protocolErrorsPtr);\n" %
+ (non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name))
+ param = ", in_%s" % json_param_name
+ # FIXME: pass not-optional refptr-values as NonNullPassRefPtr
+ if param_raw_type.is_heavy_value():
+ formal_param_type_pattern = "const %s&"
+ else:
+ formal_param_type_pattern = "%s"
+
+ method_in_code += code
+ agent_call_param_list.append(param)
+ Generator.backend_agent_interface_list.append(", %s in_%s" % (formal_param_type_pattern % non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name))
+
+ response_cook_text = ""
+ if json_command.get("async") == True:
+ callback_name = Capitalizer.lower_camel_case_to_upper(json_command_name) + "Callback"
+
+ callback_output = []
+ callback_writer = Writer(callback_output, ad_hoc_type_writer.get_indent())
+
+ decl_parameter_list = []
+ Generator.generate_send_method(json_command.get("returns"), json_command_name, domain_name, ad_hoc_type_writer,
+ decl_parameter_list,
+ Generator.CallbackMethodStructTemplate,
+ Generator.backend_method_implementation_list, Templates.callback_method,
+ {"callbackName": callback_name, "agentName": agent_interface_name})
+
+ callback_writer.newline("class " + callback_name + " : public CallbackBase {\n")
+ callback_writer.newline("public:\n")
+ callback_writer.newline(" " + callback_name + "(PassRefPtr<InspectorBackendDispatcherImpl>, int id);\n")
+ callback_writer.newline(" void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n")
+ callback_writer.newline("};\n")
+
+ ad_hoc_type_output.append(callback_output)
+
+ method_out_code += " RefPtr<" + agent_interface_name + "::" + callback_name + "> callback = adoptRef(new " + agent_interface_name + "::" + callback_name + "(this, callId));\n"
+ agent_call_param_list.append(", callback")
+ response_cook_text += " if (!error.length()) \n"
+ response_cook_text += " return;\n"
+ response_cook_text += " callback->disable();\n"
+ Generator.backend_agent_interface_list.append(", PassRefPtr<%s> callback" % callback_name)
+ else:
+ if "returns" in json_command:
+ method_out_code += "\n"
+ for json_return in json_command["returns"]:
+
+ json_return_name = json_return["name"]
+
+ optional = bool(json_return.get("optional"))
+
+ return_type_binding = Generator.resolve_type_and_generate_ad_hoc(json_return, json_command_name, domain_name, ad_hoc_type_writer, agent_interface_name + "::")
+
+ raw_type = return_type_binding.reduce_to_raw_type()
+ setter_type = raw_type.get_setter_name()
+ initializer = raw_type.get_c_initializer()
+
+ type_model = return_type_binding.get_type_model()
+ if optional:
+ type_model = type_model.get_optional()
+
+ code = " %s out_%s;\n" % (type_model.get_command_return_pass_model().get_return_var_type(), json_return_name)
+ param = ", %sout_%s" % (type_model.get_command_return_pass_model().get_output_argument_prefix(), json_return_name)
+ var_name = "out_%s" % json_return_name
+ setter_argument = type_model.get_command_return_pass_model().get_output_to_raw_expression() % var_name
+ if return_type_binding.get_setter_value_expression_pattern():
+ setter_argument = return_type_binding.get_setter_value_expression_pattern() % setter_argument
+
+ cook = " result->set%s(\"%s\", %s);\n" % (setter_type, json_return_name,
+ setter_argument)
+
+ set_condition_pattern = type_model.get_command_return_pass_model().get_set_return_condition()
+ if set_condition_pattern:
+ cook = (" if (%s)\n " % (set_condition_pattern % var_name)) + cook
+ annotated_type = type_model.get_command_return_pass_model().get_output_parameter_type()
+
+ param_name = "out_%s" % json_return_name
+ if optional:
+ param_name = "opt_" + param_name
+
+ Generator.backend_agent_interface_list.append(", %s %s" % (annotated_type, param_name))
+ response_cook_list.append(cook)
+
+ method_out_code += code
+ agent_call_param_list.append(param)
+
+ response_cook_text = "".join(response_cook_list)
+
+ if len(response_cook_text) != 0:
+ response_cook_text = " if (!error.length()) {\n" + response_cook_text + " }"
+
+ Generator.backend_method_implementation_list.append(Templates.backend_method.substitute(None,
+ domainName=domain_name, methodName=json_command_name,
+ agentField="m_" + agent_field_name,
+ methodInCode=method_in_code,
+ methodOutCode=method_out_code,
+ agentCallParams="".join(agent_call_param_list),
+ requestMessageObject=request_message_param,
+ responseCook=response_cook_text,
+ commandNameIndex=cmd_enum_name))
+ Generator.backend_method_name_declaration_list.append(" \"%s.%s\"," % (domain_name, json_command_name))
+
+ Generator.backend_agent_interface_list.append(") = 0;\n")
+
+ class CallbackMethodStructTemplate:
+ @staticmethod
+ def append_prolog(line_list):
+ pass
+
+ @staticmethod
+ def append_epilog(line_list):
+ pass
+
+ container_name = "jsonMessage"
+
+ # Generates common code for event sending and callback response data sending.
+ @staticmethod
+ def generate_send_method(parameters, event_name, domain_name, ad_hoc_type_writer, decl_parameter_list,
+ method_struct_template,
+ generator_method_list, method_template, template_params):
+ method_line_list = []
+ if parameters:
+ method_struct_template.append_prolog(method_line_list)
+ for json_parameter in parameters:
+ parameter_name = json_parameter["name"]
+
+ param_type_binding = Generator.resolve_type_and_generate_ad_hoc(json_parameter, event_name, domain_name, ad_hoc_type_writer, "")
+
+ raw_type = param_type_binding.reduce_to_raw_type()
+ raw_type_binding = RawTypeBinding(raw_type)
+
+ optional = bool(json_parameter.get("optional"))
+
+ setter_type = raw_type.get_setter_name()
+
+ type_model = param_type_binding.get_type_model()
+ raw_type_model = raw_type_binding.get_type_model()
+ if optional:
+ type_model = type_model.get_optional()
+ raw_type_model = raw_type_model.get_optional()
+
+ annotated_type = type_model.get_input_param_type_text()
+ mode_type_binding = param_type_binding
+
+ decl_parameter_list.append("%s %s" % (annotated_type, parameter_name))
+
+ setter_argument = raw_type_model.get_event_setter_expression_pattern() % parameter_name
+ if mode_type_binding.get_setter_value_expression_pattern():
+ setter_argument = mode_type_binding.get_setter_value_expression_pattern() % setter_argument
+
+ setter_code = " %s->set%s(\"%s\", %s);\n" % (method_struct_template.container_name, setter_type, parameter_name, setter_argument)
+ if optional:
+ setter_code = (" if (%s)\n " % parameter_name) + setter_code
+ method_line_list.append(setter_code)
+
+ method_struct_template.append_epilog(method_line_list)
+
+ generator_method_list.append(method_template.substitute(None,
+ domainName=domain_name,
+ parameters=", ".join(decl_parameter_list),
+ code="".join(method_line_list), **template_params))
+
+ @staticmethod
+ def resolve_type_and_generate_ad_hoc(json_param, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
+ param_name = json_param["name"]
+ ad_hoc_type_list = []
+
+ class AdHocTypeContext:
+ container_full_name_prefix = "<not yet defined>"
+ container_relative_name_prefix = container_relative_name_prefix_param
+
+ @staticmethod
+ def get_type_name_fix():
+ class NameFix:
+ class_name = Capitalizer.lower_camel_case_to_upper(param_name)
+
+ @staticmethod
+ def output_comment(writer):
+ writer.newline("// Named after parameter '%s' while generating command/event %s.\n" % (param_name, method_name))
+
+ return NameFix
+
+ @staticmethod
+ def add_type(binding):
+ ad_hoc_type_list.append(binding)
+
+ type_binding = resolve_param_type(json_param, domain_name, AdHocTypeContext)
+
+ class InterfaceForwardListener:
+ @staticmethod
+ def add_type_data(type_data):
+ pass
+
+ class InterfaceResolveContext:
+ forward_listener = InterfaceForwardListener
+
+ for type in ad_hoc_type_list:
+ type.resolve_inner(InterfaceResolveContext)
+
+ class InterfaceGenerateContext:
+ validator_writer = "not supported in InterfaceGenerateContext"
+ cpp_writer = validator_writer
+
+ for type in ad_hoc_type_list:
+ generator = type.get_code_generator()
+ if generator:
+ generator.generate_type_builder(ad_hoc_type_writer, InterfaceGenerateContext)
+
+ return type_binding
+
+ @staticmethod
+ def process_types(type_map):
+ output = Generator.type_builder_fragments
+
+ class GenerateContext:
+ validator_writer = Writer(Generator.validator_impl_list, "")
+ cpp_writer = Writer(Generator.type_builder_impl_list, "")
+
+ def generate_all_domains_code(out, type_data_callback):
+ writer = Writer(out, "")
+ for domain_data in type_map.domains():
+ domain_fixes = DomainNameFixes.get_fixed_data(domain_data.name())
+
+ namespace_declared = []
+
+ def namespace_lazy_generator():
+ if not namespace_declared:
+ writer.newline("namespace ")
+ writer.append(domain_data.name())
+ writer.append(" {\n")
+ # What is a better way to change value from outer scope?
+ namespace_declared.append(True)
+ return writer
+
+ for type_data in domain_data.types():
+ type_data_callback(type_data, namespace_lazy_generator)
+
+ if namespace_declared:
+ writer.append("} // ")
+ writer.append(domain_data.name())
+ writer.append("\n\n")
+
+ def create_type_builder_caller(generate_pass_id):
+ def call_type_builder(type_data, writer_getter):
+ code_generator = type_data.get_binding().get_code_generator()
+ if code_generator and generate_pass_id == code_generator.get_generate_pass_id():
+ writer = writer_getter()
+
+ code_generator.generate_type_builder(writer, GenerateContext)
+ return call_type_builder
+
+ generate_all_domains_code(output, create_type_builder_caller(TypeBuilderPass.MAIN))
+
+ Generator.type_builder_forwards.append("// Forward declarations.\n")
+
+ def generate_forward_callback(type_data, writer_getter):
+ if type_data in global_forward_listener.type_data_set:
+ binding = type_data.get_binding()
+ binding.get_code_generator().generate_forward_declaration(writer_getter())
+ generate_all_domains_code(Generator.type_builder_forwards, generate_forward_callback)
+
+ Generator.type_builder_forwards.append("// End of forward declarations.\n\n")
+
+ Generator.type_builder_forwards.append("// Typedefs.\n")
+
+ generate_all_domains_code(Generator.type_builder_forwards, create_type_builder_caller(TypeBuilderPass.TYPEDEF))
+
+ Generator.type_builder_forwards.append("// End of typedefs.\n\n")
+
+
+def flatten_list(input):
+ res = []
+
+ def fill_recursive(l):
+ for item in l:
+ if isinstance(item, list):
+ fill_recursive(item)
+ else:
+ res.append(item)
+ fill_recursive(input)
+ return res
+
+
+# A writer that only updates file if it actually changed to better support incremental build.
+class SmartOutput:
+ def __init__(self, file_name):
+ self.file_name_ = file_name
+ self.output_ = ""
+
+ def write(self, text):
+ self.output_ += text
+
+ def close(self):
+ text_changed = True
+
+ try:
+ read_file = open(self.file_name_, "r")
+ old_text = read_file.read()
+ read_file.close()
+ text_changed = old_text != self.output_
+ except:
+ # Ignore, just overwrite by default
+ pass
+
+ if text_changed:
+ out_file = open(self.file_name_, "w")
+ out_file.write(self.output_)
+ out_file.close()
+
+
+def output_file(file_name):
+ # For now, disable the incremental build optimisation in all cases.
+ if False:
+ return SmartOutput(file_name)
+ else:
+ return open(file_name, "w")
+
+
+Generator.go()
+
+backend_h_file = output_file(output_header_dirname + "/InspectorBackendDispatcher.h")
+backend_cpp_file = output_file(output_cpp_dirname + "/InspectorBackendDispatcher.cpp")
+
+frontend_h_file = output_file(output_header_dirname + "/InspectorFrontend.h")
+frontend_cpp_file = output_file(output_cpp_dirname + "/InspectorFrontend.cpp")
+
+typebuilder_h_file = output_file(output_header_dirname + "/InspectorTypeBuilder.h")
+typebuilder_cpp_file = output_file(output_cpp_dirname + "/InspectorTypeBuilder.cpp")
+
+
+backend_h_file.write(Templates.backend_h.substitute(None,
+ virtualSetters="\n".join(Generator.backend_virtual_setters_list),
+ agentInterfaces="".join(flatten_list(Generator.backend_agent_interface_list)),
+ methodNamesEnumContent="\n".join(Generator.method_name_enum_list)))
+
+backend_cpp_file.write(Templates.backend_cpp.substitute(None,
+ constructorInit="\n".join(Generator.backend_constructor_init_list),
+ setters="\n".join(Generator.backend_setters_list),
+ fieldDeclarations="\n".join(Generator.backend_field_list),
+ methodNameDeclarations="\n".join(Generator.backend_method_name_declaration_list),
+ methods="\n".join(Generator.backend_method_implementation_list),
+ methodDeclarations="\n".join(Generator.backend_method_declaration_list),
+ messageHandlers="\n".join(Generator.method_handler_list)))
+
+frontend_h_file.write(Templates.frontend_h.substitute(None,
+ fieldDeclarations="".join(Generator.frontend_class_field_lines),
+ domainClassList="".join(Generator.frontend_domain_class_lines)))
+
+frontend_cpp_file.write(Templates.frontend_cpp.substitute(None,
+ constructorInit="".join(Generator.frontend_constructor_init_list),
+ methods="\n".join(Generator.frontend_method_list)))
+
+typebuilder_h_file.write(Templates.typebuilder_h.substitute(None,
+ typeBuilders="".join(flatten_list(Generator.type_builder_fragments)),
+ forwards="".join(Generator.type_builder_forwards),
+ validatorIfdefName=VALIDATOR_IFDEF_NAME))
+
+typebuilder_cpp_file.write(Templates.typebuilder_cpp.substitute(None,
+ enumConstantValues=EnumConstants.get_enum_constant_code(),
+ implCode="".join(flatten_list(Generator.type_builder_impl_list)),
+ validatorCode="".join(flatten_list(Generator.validator_impl_list)),
+ validatorIfdefName=VALIDATOR_IFDEF_NAME))
+
+backend_h_file.close()
+backend_cpp_file.close()
+
+frontend_h_file.close()
+frontend_cpp_file.close()
+
+typebuilder_h_file.close()
+typebuilder_cpp_file.close()
diff --git a/Source/core/inspector/CodeGeneratorInspectorStrings.py b/Source/core/inspector/CodeGeneratorInspectorStrings.py
new file mode 100644
index 0000000..6c3fe05
--- /dev/null
+++ b/Source/core/inspector/CodeGeneratorInspectorStrings.py
@@ -0,0 +1,929 @@
+# Copyright (c) 2013 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER OR 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.
+
+# THis file contains string resources for CodeGeneratorInspector.
+# Its syntax is a Python syntax subset, suitable for manual parsing.
+
+frontend_domain_class = (
+""" class $domainClassName {
+ public:
+ $domainClassName(InspectorFrontendChannel* inspectorFrontendChannel) : m_inspectorFrontendChannel(inspectorFrontendChannel) { }
+${frontendDomainMethodDeclarations} void setInspectorFrontendChannel(InspectorFrontendChannel* inspectorFrontendChannel) { m_inspectorFrontendChannel = inspectorFrontendChannel; }
+ InspectorFrontendChannel* getInspectorFrontendChannel() { return m_inspectorFrontendChannel; }
+ private:
+ InspectorFrontendChannel* m_inspectorFrontendChannel;
+ };
+
+ $domainClassName* $domainFieldName() { return &m_$domainFieldName; }
+
+""")
+
+backend_method = (
+"""void InspectorBackendDispatcherImpl::${domainName}_$methodName(long callId, InspectorObject*$requestMessageObject)
+{
+ RefPtr<InspectorArray> protocolErrors = InspectorArray::create();
+
+ if (!$agentField)
+ protocolErrors->pushString("${domainName} handler is not available.");
+$methodOutCode
+$methodInCode
+ RefPtr<InspectorObject> result = InspectorObject::create();
+ ErrorString error;
+ if (!protocolErrors->length()) {
+ $agentField->$methodName(&error$agentCallParams);
+
+${responseCook}
+ }
+ sendResponse(callId, result, commandNames[$commandNameIndex], protocolErrors, error);
+}
+""")
+
+frontend_method = ("""void InspectorFrontend::$domainName::$eventName($parameters)
+{
+ RefPtr<InspectorObject> jsonMessage = InspectorObject::create();
+ jsonMessage->setString("method", "$domainName.$eventName");
+$code if (m_inspectorFrontendChannel)
+ m_inspectorFrontendChannel->sendMessageToFrontend(jsonMessage->toJSONString());
+}
+""")
+
+callback_method = (
+"""InspectorBackendDispatcher::$agentName::$callbackName::$callbackName(PassRefPtr<InspectorBackendDispatcherImpl> backendImpl, int id) : CallbackBase(backendImpl, id) {}
+
+void InspectorBackendDispatcher::$agentName::$callbackName::sendSuccess($parameters)
+{
+ RefPtr<InspectorObject> jsonMessage = InspectorObject::create();
+$code sendIfActive(jsonMessage, ErrorString());
+}
+""")
+
+frontend_h = (
+"""#ifndef InspectorFrontend_h
+#define InspectorFrontend_h
+
+#include "InspectorTypeBuilder.h"
+#include "core/inspector/InspectorValues.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InspectorFrontendChannel;
+
+typedef String ErrorString;
+
+class InspectorFrontend {
+public:
+ InspectorFrontend(InspectorFrontendChannel*);
+
+
+$domainClassList
+private:
+${fieldDeclarations}};
+
+} // namespace WebCore
+#endif // !defined(InspectorFrontend_h)
+""")
+
+backend_h = (
+"""#ifndef InspectorBackendDispatcher_h
+#define InspectorBackendDispatcher_h
+
+#include "InspectorTypeBuilder.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InspectorAgent;
+class InspectorObject;
+class InspectorArray;
+class InspectorFrontendChannel;
+
+typedef String ErrorString;
+
+class InspectorBackendDispatcherImpl;
+
+class InspectorBackendDispatcher: public RefCounted<InspectorBackendDispatcher> {
+public:
+ static PassRefPtr<InspectorBackendDispatcher> create(InspectorFrontendChannel* inspectorFrontendChannel);
+ virtual ~InspectorBackendDispatcher() { }
+
+ class CallbackBase: public RefCounted<CallbackBase> {
+ public:
+ CallbackBase(PassRefPtr<InspectorBackendDispatcherImpl> backendImpl, int id);
+ virtual ~CallbackBase();
+ void sendFailure(const ErrorString&);
+ bool isActive();
+
+ protected:
+ void sendIfActive(PassRefPtr<InspectorObject> partialMessage, const ErrorString& invocationError);
+
+ private:
+ void disable() { m_alreadySent = true; }
+
+ RefPtr<InspectorBackendDispatcherImpl> m_backendImpl;
+ int m_id;
+ bool m_alreadySent;
+
+ friend class InspectorBackendDispatcherImpl;
+ };
+
+$agentInterfaces
+$virtualSetters
+
+ virtual void clearFrontend() = 0;
+
+ enum CommonErrorCode {
+ ParseError = 0,
+ InvalidRequest,
+ MethodNotFound,
+ InvalidParams,
+ InternalError,
+ ServerError,
+ LastEntry,
+ };
+
+ void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage) const;
+ virtual void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage, PassRefPtr<InspectorArray> data) const = 0;
+ virtual void dispatch(const String& message) = 0;
+ static bool getCommandName(const String& message, String* result);
+
+ enum MethodNames {
+$methodNamesEnumContent
+
+ kMethodNamesEnumSize
+ };
+
+ static const char* commandNames[];
+};
+
+} // namespace WebCore
+#endif // !defined(InspectorBackendDispatcher_h)
+
+
+""")
+
+backend_cpp = (
+"""
+
+#include "config.h"
+#include "InspectorBackendDispatcher.h"
+
+
+#include "core/inspector/InspectorAgent.h"
+#include "core/inspector/InspectorFrontendChannel.h"
+#include "core/inspector/InspectorValues.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+const char* InspectorBackendDispatcher::commandNames[] = {
+$methodNameDeclarations
+};
+
+
+class InspectorBackendDispatcherImpl : public InspectorBackendDispatcher {
+public:
+ InspectorBackendDispatcherImpl(InspectorFrontendChannel* inspectorFrontendChannel)
+ : m_inspectorFrontendChannel(inspectorFrontendChannel)
+$constructorInit
+ { }
+
+ virtual void clearFrontend() { m_inspectorFrontendChannel = 0; }
+ virtual void dispatch(const String& message);
+ virtual void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage, PassRefPtr<InspectorArray> data) const;
+ using InspectorBackendDispatcher::reportProtocolError;
+
+ void sendResponse(long callId, PassRefPtr<InspectorObject> result, const ErrorString& invocationError);
+ bool isActive() { return m_inspectorFrontendChannel; }
+
+$setters
+private:
+$methodDeclarations
+
+ InspectorFrontendChannel* m_inspectorFrontendChannel;
+$fieldDeclarations
+
+ template<typename R, typename V, typename V0>
+ static R getPropertyValueImpl(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors, V0 initial_value, bool (*as_method)(InspectorValue*, V*), const char* type_name);
+
+ static int getInt(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
+ static double getDouble(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
+ static String getString(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
+ static bool getBoolean(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
+ static PassRefPtr<InspectorObject> getObject(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
+ static PassRefPtr<InspectorArray> getArray(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors);
+
+ void sendResponse(long callId, PassRefPtr<InspectorObject> result, const char* commandName, PassRefPtr<InspectorArray> protocolErrors, ErrorString invocationError);
+
+};
+
+$methods
+
+PassRefPtr<InspectorBackendDispatcher> InspectorBackendDispatcher::create(InspectorFrontendChannel* inspectorFrontendChannel)
+{
+ return adoptRef(new InspectorBackendDispatcherImpl(inspectorFrontendChannel));
+}
+
+
+void InspectorBackendDispatcherImpl::dispatch(const String& message)
+{
+ RefPtr<InspectorBackendDispatcher> protect = this;
+ typedef void (InspectorBackendDispatcherImpl::*CallHandler)(long callId, InspectorObject* messageObject);
+ typedef HashMap<String, CallHandler> DispatchMap;
+ DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, );
+ long callId = 0;
+
+ if (dispatchMap.isEmpty()) {
+ static CallHandler handlers[] = {
+$messageHandlers
+ };
+ size_t length = WTF_ARRAY_LENGTH(commandNames);
+ for (size_t i = 0; i < length; ++i)
+ dispatchMap.add(commandNames[i], handlers[i]);
+ }
+
+ RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message);
+ if (!parsedMessage) {
+ reportProtocolError(0, ParseError, "Message must be in JSON format");
+ return;
+ }
+
+ RefPtr<InspectorObject> messageObject = parsedMessage->asObject();
+ if (!messageObject) {
+ reportProtocolError(0, InvalidRequest, "Message must be a JSONified object");
+ return;
+ }
+
+ RefPtr<InspectorValue> callIdValue = messageObject->get("id");
+ if (!callIdValue) {
+ reportProtocolError(0, InvalidRequest, "'id' property was not found");
+ return;
+ }
+
+ if (!callIdValue->asNumber(&callId)) {
+ reportProtocolError(0, InvalidRequest, "The type of 'id' property must be number");
+ return;
+ }
+
+ RefPtr<InspectorValue> methodValue = messageObject->get("method");
+ if (!methodValue) {
+ reportProtocolError(&callId, InvalidRequest, "'method' property wasn't found");
+ return;
+ }
+
+ String method;
+ if (!methodValue->asString(&method)) {
+ reportProtocolError(&callId, InvalidRequest, "The type of 'method' property must be string");
+ return;
+ }
+
+ HashMap<String, CallHandler>::iterator it = dispatchMap.find(method);
+ if (it == dispatchMap.end()) {
+ reportProtocolError(&callId, MethodNotFound, "'" + method + "' wasn't found");
+ return;
+ }
+
+ ((*this).*it->value)(callId, messageObject.get());
+}
+
+void InspectorBackendDispatcherImpl::sendResponse(long callId, PassRefPtr<InspectorObject> result, const char* commandName, PassRefPtr<InspectorArray> protocolErrors, ErrorString invocationError)
+{
+ if (protocolErrors->length()) {
+ String errorMessage = String::format("Some arguments of method '%s' can't be processed", commandName);
+ reportProtocolError(&callId, InvalidParams, errorMessage, protocolErrors);
+ return;
+ }
+ sendResponse(callId, result, invocationError);
+}
+
+void InspectorBackendDispatcherImpl::sendResponse(long callId, PassRefPtr<InspectorObject> result, const ErrorString& invocationError)
+{
+ if (invocationError.length()) {
+ reportProtocolError(&callId, ServerError, invocationError);
+ return;
+ }
+
+ RefPtr<InspectorObject> responseMessage = InspectorObject::create();
+ responseMessage->setObject("result", result);
+ responseMessage->setNumber("id", callId);
+ if (m_inspectorFrontendChannel)
+ m_inspectorFrontendChannel->sendMessageToFrontend(responseMessage->toJSONString());
+}
+
+void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode code, const String& errorMessage) const
+{
+ reportProtocolError(callId, code, errorMessage, 0);
+}
+
+void InspectorBackendDispatcherImpl::reportProtocolError(const long* const callId, CommonErrorCode code, const String& errorMessage, PassRefPtr<InspectorArray> data) const
+{
+ DEFINE_STATIC_LOCAL(Vector<int>,s_commonErrors,);
+ if (!s_commonErrors.size()) {
+ s_commonErrors.insert(ParseError, -32700);
+ s_commonErrors.insert(InvalidRequest, -32600);
+ s_commonErrors.insert(MethodNotFound, -32601);
+ s_commonErrors.insert(InvalidParams, -32602);
+ s_commonErrors.insert(InternalError, -32603);
+ s_commonErrors.insert(ServerError, -32000);
+ }
+ ASSERT(code >=0);
+ ASSERT((unsigned)code < s_commonErrors.size());
+ ASSERT(s_commonErrors[code]);
+ RefPtr<InspectorObject> error = InspectorObject::create();
+ error->setNumber("code", s_commonErrors[code]);
+ error->setString("message", errorMessage);
+ ASSERT(error);
+ if (data)
+ error->setArray("data", data);
+ RefPtr<InspectorObject> message = InspectorObject::create();
+ message->setObject("error", error);
+ if (callId)
+ message->setNumber("id", *callId);
+ else
+ message->setValue("id", InspectorValue::null());
+ if (m_inspectorFrontendChannel)
+ m_inspectorFrontendChannel->sendMessageToFrontend(message->toJSONString());
+}
+
+template<typename R, typename V, typename V0>
+R InspectorBackendDispatcherImpl::getPropertyValueImpl(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors, V0 initial_value, bool (*as_method)(InspectorValue*, V*), const char* type_name)
+{
+ ASSERT(protocolErrors);
+
+ if (valueFound)
+ *valueFound = false;
+
+ V value = initial_value;
+
+ if (!object) {
+ if (!valueFound) {
+ // Required parameter in missing params container.
+ protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type '%s'.", name.utf8().data(), type_name));
+ }
+ return value;
+ }
+
+ InspectorObject::const_iterator end = object->end();
+ InspectorObject::const_iterator valueIterator = object->find(name);
+
+ if (valueIterator == end) {
+ if (!valueFound)
+ protocolErrors->pushString(String::format("Parameter '%s' with type '%s' was not found.", name.utf8().data(), type_name));
+ return value;
+ }
+
+ if (!as_method(valueIterator->value.get(), &value))
+ protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be '%s'.", name.utf8().data(), type_name));
+ else
+ if (valueFound)
+ *valueFound = true;
+ return value;
+}
+
+struct AsMethodBridges {
+ static bool asInt(InspectorValue* value, int* output) { return value->asNumber(output); }
+ static bool asDouble(InspectorValue* value, double* output) { return value->asNumber(output); }
+ static bool asString(InspectorValue* value, String* output) { return value->asString(output); }
+ static bool asBoolean(InspectorValue* value, bool* output) { return value->asBoolean(output); }
+ static bool asObject(InspectorValue* value, RefPtr<InspectorObject>* output) { return value->asObject(output); }
+ static bool asArray(InspectorValue* value, RefPtr<InspectorArray>* output) { return value->asArray(output); }
+};
+
+int InspectorBackendDispatcherImpl::getInt(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
+{
+ return getPropertyValueImpl<int, int, int>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asInt, "Number");
+}
+
+double InspectorBackendDispatcherImpl::getDouble(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
+{
+ return getPropertyValueImpl<double, double, double>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asDouble, "Number");
+}
+
+String InspectorBackendDispatcherImpl::getString(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
+{
+ return getPropertyValueImpl<String, String, String>(object, name, valueFound, protocolErrors, "", AsMethodBridges::asString, "String");
+}
+
+bool InspectorBackendDispatcherImpl::getBoolean(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
+{
+ return getPropertyValueImpl<bool, bool, bool>(object, name, valueFound, protocolErrors, false, AsMethodBridges::asBoolean, "Boolean");
+}
+
+PassRefPtr<InspectorObject> InspectorBackendDispatcherImpl::getObject(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
+{
+ return getPropertyValueImpl<PassRefPtr<InspectorObject>, RefPtr<InspectorObject>, InspectorObject*>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asObject, "Object");
+}
+
+PassRefPtr<InspectorArray> InspectorBackendDispatcherImpl::getArray(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
+{
+ return getPropertyValueImpl<PassRefPtr<InspectorArray>, RefPtr<InspectorArray>, InspectorArray*>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asArray, "Array");
+}
+
+bool InspectorBackendDispatcher::getCommandName(const String& message, String* result)
+{
+ RefPtr<InspectorValue> value = InspectorValue::parseJSON(message);
+ if (!value)
+ return false;
+
+ RefPtr<InspectorObject> object = value->asObject();
+ if (!object)
+ return false;
+
+ if (!object->getString("method", result))
+ return false;
+
+ return true;
+}
+
+InspectorBackendDispatcher::CallbackBase::CallbackBase(PassRefPtr<InspectorBackendDispatcherImpl> backendImpl, int id)
+ : m_backendImpl(backendImpl), m_id(id), m_alreadySent(false) {}
+
+InspectorBackendDispatcher::CallbackBase::~CallbackBase() {}
+
+void InspectorBackendDispatcher::CallbackBase::sendFailure(const ErrorString& error)
+{
+ ASSERT(error.length());
+ sendIfActive(0, error);
+}
+
+bool InspectorBackendDispatcher::CallbackBase::isActive()
+{
+ return !m_alreadySent && m_backendImpl->isActive();
+}
+
+void InspectorBackendDispatcher::CallbackBase::sendIfActive(PassRefPtr<InspectorObject> partialMessage, const ErrorString& invocationError)
+{
+ if (m_alreadySent)
+ return;
+ m_backendImpl->sendResponse(m_id, partialMessage, invocationError);
+ m_alreadySent = true;
+}
+
+COMPILE_ASSERT(static_cast<int>(InspectorBackendDispatcher::kMethodNamesEnumSize) == WTF_ARRAY_LENGTH(InspectorBackendDispatcher::commandNames), command_name_array_problem);
+
+} // namespace WebCore
+
+""")
+
+frontend_cpp = (
+"""
+
+#include "config.h"
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorFrontendChannel.h"
+#include "core/inspector/InspectorValues.h"
+
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+InspectorFrontend::InspectorFrontend(InspectorFrontendChannel* inspectorFrontendChannel)
+ : $constructorInit{
+}
+
+$methods
+
+} // namespace WebCore
+
+""")
+
+typebuilder_h = (
+"""
+#ifndef InspectorTypeBuilder_h
+#define InspectorTypeBuilder_h
+
+#include "core/inspector/InspectorValues.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+namespace TypeBuilder {
+
+template<typename T>
+class OptOutput {
+public:
+ OptOutput() : m_assigned(false) { }
+
+ void operator=(T value)
+ {
+ m_value = value;
+ m_assigned = true;
+ }
+
+ bool isAssigned() { return m_assigned; }
+
+ T getValue()
+ {
+ ASSERT(isAssigned());
+ return m_value;
+ }
+
+private:
+ T m_value;
+ bool m_assigned;
+
+ WTF_MAKE_NONCOPYABLE(OptOutput);
+};
+
+
+// A small transient wrapper around int type, that can be used as a funciton parameter type
+// cleverly disallowing C++ implicit casts from float or double.
+class ExactlyInt {
+public:
+ template<typename T>
+ ExactlyInt(T t) : m_value(cast_to_int<T>(t)) {}
+
+ ExactlyInt() {}
+
+ operator int() { return m_value; }
+private:
+ int m_value;
+
+ template<typename T>
+ static int cast_to_int(T) { return T::default_case_cast_is_not_supported(); }
+};
+
+template<>
+inline int ExactlyInt::cast_to_int<int>(int i) { return i; }
+
+template<>
+inline int ExactlyInt::cast_to_int<unsigned int>(unsigned int i) { return i; }
+
+class RuntimeCastHelper {
+public:
+#if $validatorIfdefName
+ template<InspectorValue::Type TYPE>
+ static void assertType(InspectorValue* value)
+ {
+ ASSERT(value->type() == TYPE);
+ }
+ static void assertAny(InspectorValue*);
+ static void assertInt(InspectorValue* value);
+#endif
+};
+
+
+// This class provides "Traits" type for the input type T. It is programmed using C++ template specialization
+// technique. By default it simply takes "ItemTraits" type from T, but it doesn't work with the base types.
+template<typename T>
+struct ArrayItemHelper {
+ typedef typename T::ItemTraits Traits;
+};
+
+template<typename T>
+class Array : public InspectorArrayBase {
+private:
+ Array() { }
+
+ InspectorArray* openAccessors() {
+ COMPILE_ASSERT(sizeof(InspectorArray) == sizeof(Array<T>), cannot_cast);
+ return static_cast<InspectorArray*>(static_cast<InspectorArrayBase*>(this));
+ }
+
+public:
+ void addItem(PassRefPtr<T> value)
+ {
+ ArrayItemHelper<T>::Traits::pushRefPtr(this->openAccessors(), value);
+ }
+
+ void addItem(T value)
+ {
+ ArrayItemHelper<T>::Traits::pushRaw(this->openAccessors(), value);
+ }
+
+ static PassRefPtr<Array<T> > create()
+ {
+ return adoptRef(new Array<T>());
+ }
+
+ static PassRefPtr<Array<T> > runtimeCast(PassRefPtr<InspectorValue> value)
+ {
+ RefPtr<InspectorArray> array;
+ bool castRes = value->asArray(&array);
+ ASSERT_UNUSED(castRes, castRes);
+#if $validatorIfdefName
+ assertCorrectValue(array.get());
+#endif // $validatorIfdefName
+ COMPILE_ASSERT(sizeof(Array<T>) == sizeof(InspectorArray), type_cast_problem);
+ return static_cast<Array<T>*>(static_cast<InspectorArrayBase*>(array.get()));
+ }
+
+#if $validatorIfdefName
+ static void assertCorrectValue(InspectorValue* value)
+ {
+ RefPtr<InspectorArray> array;
+ bool castRes = value->asArray(&array);
+ ASSERT_UNUSED(castRes, castRes);
+ for (unsigned i = 0; i < array->length(); i++)
+ ArrayItemHelper<T>::Traits::template assertCorrectValue<T>(array->get(i).get());
+ }
+
+#endif // $validatorIfdefName
+};
+
+struct StructItemTraits {
+ static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorValue> value)
+ {
+ array->pushValue(value);
+ }
+
+#if $validatorIfdefName
+ template<typename T>
+ static void assertCorrectValue(InspectorValue* value) {
+ T::assertCorrectValue(value);
+ }
+#endif // $validatorIfdefName
+};
+
+template<>
+struct ArrayItemHelper<String> {
+ struct Traits {
+ static void pushRaw(InspectorArray* array, const String& value)
+ {
+ array->pushString(value);
+ }
+
+#if $validatorIfdefName
+ template<typename T>
+ static void assertCorrectValue(InspectorValue* value) {
+ RuntimeCastHelper::assertType<InspectorValue::TypeString>(value);
+ }
+#endif // $validatorIfdefName
+ };
+};
+
+template<>
+struct ArrayItemHelper<int> {
+ struct Traits {
+ static void pushRaw(InspectorArray* array, int value)
+ {
+ array->pushInt(value);
+ }
+
+#if $validatorIfdefName
+ template<typename T>
+ static void assertCorrectValue(InspectorValue* value) {
+ RuntimeCastHelper::assertInt(value);
+ }
+#endif // $validatorIfdefName
+ };
+};
+
+template<>
+struct ArrayItemHelper<double> {
+ struct Traits {
+ static void pushRaw(InspectorArray* array, double value)
+ {
+ array->pushNumber(value);
+ }
+
+#if $validatorIfdefName
+ template<typename T>
+ static void assertCorrectValue(InspectorValue* value) {
+ RuntimeCastHelper::assertType<InspectorValue::TypeNumber>(value);
+ }
+#endif // $validatorIfdefName
+ };
+};
+
+template<>
+struct ArrayItemHelper<bool> {
+ struct Traits {
+ static void pushRaw(InspectorArray* array, bool value)
+ {
+ array->pushBoolean(value);
+ }
+
+#if $validatorIfdefName
+ template<typename T>
+ static void assertCorrectValue(InspectorValue* value) {
+ RuntimeCastHelper::assertType<InspectorValue::TypeBoolean>(value);
+ }
+#endif // $validatorIfdefName
+ };
+};
+
+template<>
+struct ArrayItemHelper<InspectorValue> {
+ struct Traits {
+ static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorValue> value)
+ {
+ array->pushValue(value);
+ }
+
+#if $validatorIfdefName
+ template<typename T>
+ static void assertCorrectValue(InspectorValue* value) {
+ RuntimeCastHelper::assertAny(value);
+ }
+#endif // $validatorIfdefName
+ };
+};
+
+template<>
+struct ArrayItemHelper<InspectorObject> {
+ struct Traits {
+ static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorValue> value)
+ {
+ array->pushValue(value);
+ }
+
+#if $validatorIfdefName
+ template<typename T>
+ static void assertCorrectValue(InspectorValue* value) {
+ RuntimeCastHelper::assertType<InspectorValue::TypeObject>(value);
+ }
+#endif // $validatorIfdefName
+ };
+};
+
+template<>
+struct ArrayItemHelper<InspectorArray> {
+ struct Traits {
+ static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorArray> value)
+ {
+ array->pushArray(value);
+ }
+
+#if $validatorIfdefName
+ template<typename T>
+ static void assertCorrectValue(InspectorValue* value) {
+ RuntimeCastHelper::assertType<InspectorValue::TypeArray>(value);
+ }
+#endif // $validatorIfdefName
+ };
+};
+
+template<typename T>
+struct ArrayItemHelper<TypeBuilder::Array<T> > {
+ struct Traits {
+ static void pushRefPtr(InspectorArray* array, PassRefPtr<TypeBuilder::Array<T> > value)
+ {
+ array->pushValue(value);
+ }
+
+#if $validatorIfdefName
+ template<typename S>
+ static void assertCorrectValue(InspectorValue* value) {
+ S::assertCorrectValue(value);
+ }
+#endif // $validatorIfdefName
+ };
+};
+
+${forwards}
+
+String getEnumConstantValue(int code);
+
+${typeBuilders}
+} // namespace TypeBuilder
+
+
+} // namespace WebCore
+
+#endif // !defined(InspectorTypeBuilder_h)
+
+""")
+
+typebuilder_cpp = (
+"""
+
+#include "config.h"
+
+#include "InspectorTypeBuilder.h"
+
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+namespace TypeBuilder {
+
+const char* const enum_constant_values[] = {
+$enumConstantValues};
+
+String getEnumConstantValue(int code) {
+ return enum_constant_values[code];
+}
+
+} // namespace TypeBuilder
+
+$implCode
+
+#if $validatorIfdefName
+
+void TypeBuilder::RuntimeCastHelper::assertAny(InspectorValue*)
+{
+ // No-op.
+}
+
+
+void TypeBuilder::RuntimeCastHelper::assertInt(InspectorValue* value)
+{
+ double v;
+ bool castRes = value->asNumber(&v);
+ ASSERT_UNUSED(castRes, castRes);
+ ASSERT(static_cast<double>(static_cast<int>(v)) == v);
+}
+
+$validatorCode
+
+#endif // $validatorIfdefName
+
+} // namespace WebCore
+
+""")
+
+param_container_access_code = """
+ RefPtr<InspectorObject> paramsContainer = requestMessageObject->getObject("params");
+ InspectorObject* paramsContainerPtr = paramsContainer.get();
+ InspectorArray* protocolErrorsPtr = protocolErrors.get();
+"""
+
+class_binding_builder_part_1 = (
+""" AllFieldsSet = %s
+ };
+
+ template<int STATE>
+ class Builder {
+ private:
+ RefPtr<InspectorObject> m_result;
+
+ template<int STEP> Builder<STATE | STEP>& castState()
+ {
+ return *reinterpret_cast<Builder<STATE | STEP>*>(this);
+ }
+
+ Builder(PassRefPtr</*%s*/InspectorObject> ptr)
+ {
+ COMPILE_ASSERT(STATE == NoFieldsSet, builder_created_in_non_init_state);
+ m_result = ptr;
+ }
+ friend class %s;
+ public:
+""")
+
+class_binding_builder_part_2 = ("""
+ Builder<STATE | %s>& set%s(%s value)
+ {
+ COMPILE_ASSERT(!(STATE & %s), property_%s_already_set);
+ m_result->set%s("%s", %s);
+ return castState<%s>();
+ }
+""")
+
+class_binding_builder_part_3 = ("""
+ operator RefPtr<%s>& ()
+ {
+ COMPILE_ASSERT(STATE == AllFieldsSet, result_is_not_ready);
+ COMPILE_ASSERT(sizeof(%s) == sizeof(InspectorObject), cannot_cast);
+ return *reinterpret_cast<RefPtr<%s>*>(&m_result);
+ }
+
+ PassRefPtr<%s> release()
+ {
+ return RefPtr<%s>(*this).release();
+ }
+ };
+
+""")
+
+class_binding_builder_part_4 = (
+""" static Builder<NoFieldsSet> create()
+ {
+ return Builder<NoFieldsSet>(InspectorObject::create());
+ }
+""")
diff --git a/Source/core/inspector/ConsoleAPITypes.h b/Source/core/inspector/ConsoleAPITypes.h
new file mode 100644
index 0000000..11f65ec
--- /dev/null
+++ b/Source/core/inspector/ConsoleAPITypes.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 Google 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 ConsoleAPITypes_h
+#define ConsoleAPITypes_h
+
+namespace WebCore {
+
+enum MessageType {
+ LogMessageType,
+ DirMessageType,
+ DirXMLMessageType,
+ TableMessageType,
+ TraceMessageType,
+ StartGroupMessageType,
+ StartGroupCollapsedMessageType,
+ EndGroupMessageType,
+ ClearMessageType,
+ AssertMessageType,
+ TimingMessageType,
+ ProfileMessageType,
+ ProfileEndMessageType
+};
+
+} // namespace WebCore
+
+#endif // ConsoleAPITypes_h
diff --git a/Source/core/inspector/ConsoleMessage.cpp b/Source/core/inspector/ConsoleMessage.cpp
new file mode 100644
index 0000000..d1f71b9
--- /dev/null
+++ b/Source/core/inspector/ConsoleMessage.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ * Copyright (C) 2009, 2010 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/ConsoleMessage.h"
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptCallStackFactory.h"
+#include "bindings/v8/ScriptValue.h"
+#include "core/inspector/IdentifiersFactory.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/ScriptArguments.h"
+#include "core/inspector/ScriptCallFrame.h"
+#include "core/inspector/ScriptCallStack.h"
+#include "core/page/Console.h"
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+ConsoleMessage::ConsoleMessage(bool canGenerateCallStack, MessageSource source, MessageType type, MessageLevel level, const String& message)
+ : m_source(source)
+ , m_type(type)
+ , m_level(level)
+ , m_message(message)
+ , m_url()
+ , m_line(0)
+ , m_repeatCount(1)
+ , m_requestId(IdentifiersFactory::requestId(0))
+{
+ autogenerateMetadata(canGenerateCallStack);
+}
+
+ConsoleMessage::ConsoleMessage(bool canGenerateCallStack, MessageSource source, MessageType type, MessageLevel level, const String& message, const String& url, unsigned line, ScriptState* state, unsigned long requestIdentifier)
+ : m_source(source)
+ , m_type(type)
+ , m_level(level)
+ , m_message(message)
+ , m_url(url)
+ , m_line(line)
+ , m_repeatCount(1)
+ , m_requestId(IdentifiersFactory::requestId(requestIdentifier))
+{
+ autogenerateMetadata(canGenerateCallStack, state);
+}
+
+ConsoleMessage::ConsoleMessage(bool, MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier)
+ : m_source(source)
+ , m_type(type)
+ , m_level(level)
+ , m_message(message)
+ , m_arguments(0)
+ , m_line(0)
+ , m_repeatCount(1)
+ , m_requestId(IdentifiersFactory::requestId(requestIdentifier))
+{
+ if (callStack && callStack->size()) {
+ const ScriptCallFrame& frame = callStack->at(0);
+ m_url = frame.sourceURL();
+ m_line = frame.lineNumber();
+ }
+ m_callStack = callStack;
+}
+
+ConsoleMessage::ConsoleMessage(bool canGenerateCallStack, MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptArguments> arguments, ScriptState* state, unsigned long requestIdentifier)
+ : m_source(source)
+ , m_type(type)
+ , m_level(level)
+ , m_message(message)
+ , m_arguments(arguments)
+ , m_url()
+ , m_line(0)
+ , m_repeatCount(1)
+ , m_requestId(IdentifiersFactory::requestId(requestIdentifier))
+{
+ autogenerateMetadata(canGenerateCallStack, state);
+}
+
+ConsoleMessage::~ConsoleMessage()
+{
+}
+
+void ConsoleMessage::autogenerateMetadata(bool canGenerateCallStack, ScriptState* state)
+{
+ if (m_type == EndGroupMessageType)
+ return;
+
+ if (state)
+ m_callStack = createScriptCallStackForConsole(state);
+ else if (canGenerateCallStack)
+ m_callStack = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
+ else
+ return;
+
+ if (m_callStack && m_callStack->size()) {
+ const ScriptCallFrame& frame = m_callStack->at(0);
+ m_url = frame.sourceURL();
+ m_line = frame.lineNumber();
+ return;
+ }
+
+ m_callStack.clear();
+}
+
+static TypeBuilder::Console::ConsoleMessage::Source::Enum messageSourceValue(MessageSource source)
+{
+ switch (source) {
+ case XMLMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Xml;
+ case JSMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Javascript;
+ case NetworkMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Network;
+ case ConsoleAPIMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Console_api;
+ case StorageMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Storage;
+ case AppCacheMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Appcache;
+ case RenderingMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Rendering;
+ case CSSMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Css;
+ case SecurityMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Security;
+ case OtherMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Other;
+ case DeprecationMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Deprecation;
+ }
+ return TypeBuilder::Console::ConsoleMessage::Source::Other;
+}
+
+static TypeBuilder::Console::ConsoleMessage::Type::Enum messageTypeValue(MessageType type)
+{
+ switch (type) {
+ case LogMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Log;
+ case ClearMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Clear;
+ case DirMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Dir;
+ case DirXMLMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Dirxml;
+ case TableMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Table;
+ case TraceMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Trace;
+ case StartGroupMessageType: return TypeBuilder::Console::ConsoleMessage::Type::StartGroup;
+ case StartGroupCollapsedMessageType: return TypeBuilder::Console::ConsoleMessage::Type::StartGroupCollapsed;
+ case EndGroupMessageType: return TypeBuilder::Console::ConsoleMessage::Type::EndGroup;
+ case AssertMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Assert;
+ case TimingMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Timing;
+ case ProfileMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Profile;
+ case ProfileEndMessageType: return TypeBuilder::Console::ConsoleMessage::Type::ProfileEnd;
+ }
+ return TypeBuilder::Console::ConsoleMessage::Type::Log;
+}
+
+static TypeBuilder::Console::ConsoleMessage::Level::Enum messageLevelValue(MessageLevel level)
+{
+ switch (level) {
+ case DebugMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Debug;
+ case LogMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Log;
+ case WarningMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Warning;
+ case ErrorMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Error;
+ }
+ return TypeBuilder::Console::ConsoleMessage::Level::Log;
+}
+
+void ConsoleMessage::addToFrontend(InspectorFrontend::Console* frontend, InjectedScriptManager* injectedScriptManager, bool generatePreview)
+{
+ RefPtr<TypeBuilder::Console::ConsoleMessage> jsonObj = TypeBuilder::Console::ConsoleMessage::create()
+ .setSource(messageSourceValue(m_source))
+ .setLevel(messageLevelValue(m_level))
+ .setText(m_message);
+ // FIXME: only send out type for ConsoleAPI source messages.
+ jsonObj->setType(messageTypeValue(m_type));
+ jsonObj->setLine(static_cast<int>(m_line));
+ jsonObj->setUrl(m_url);
+ jsonObj->setRepeatCount(static_cast<int>(m_repeatCount));
+ if (m_source == NetworkMessageSource && !m_requestId.isEmpty())
+ jsonObj->setNetworkRequestId(m_requestId);
+ if (m_arguments && m_arguments->argumentCount()) {
+ InjectedScript injectedScript = injectedScriptManager->injectedScriptFor(m_arguments->globalState());
+ if (!injectedScript.hasNoValue()) {
+ RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::RemoteObject> > jsonArgs = TypeBuilder::Array<TypeBuilder::Runtime::RemoteObject>::create();
+ if (m_type == TableMessageType && generatePreview && m_arguments->argumentCount()) {
+ ScriptValue table = m_arguments->argumentAt(0);
+ ScriptValue columns = m_arguments->argumentCount() > 1 ? m_arguments->argumentAt(1) : ScriptValue();
+ RefPtr<TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapTable(table, columns);
+ if (!inspectorValue) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ jsonArgs->addItem(inspectorValue);
+ } else {
+ for (unsigned i = 0; i < m_arguments->argumentCount(); ++i) {
+ RefPtr<TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapObject(m_arguments->argumentAt(i), "console", generatePreview);
+ if (!inspectorValue) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ jsonArgs->addItem(inspectorValue);
+ }
+ }
+ jsonObj->setParameters(jsonArgs);
+ }
+ }
+ if (m_callStack)
+ jsonObj->setStackTrace(m_callStack->buildInspectorArray());
+ frontend->messageAdded(jsonObj);
+}
+
+void ConsoleMessage::updateRepeatCountInConsole(InspectorFrontend::Console* frontend)
+{
+ frontend->messageRepeatCountUpdated(m_repeatCount);
+}
+
+bool ConsoleMessage::isEqual(ConsoleMessage* msg) const
+{
+ if (m_arguments) {
+ if (!m_arguments->isEqual(msg->m_arguments.get()))
+ return false;
+ // Never treat objects as equal - their properties might change over time.
+ for (size_t i = 0; i < m_arguments->argumentCount(); ++i) {
+ if (m_arguments->argumentAt(i).isObject())
+ return false;
+ }
+ } else if (msg->m_arguments)
+ return false;
+
+ if (m_callStack) {
+ if (!m_callStack->isEqual(msg->m_callStack.get()))
+ return false;
+ } else if (msg->m_callStack)
+ return false;
+
+ return msg->m_source == m_source
+ && msg->m_type == m_type
+ && msg->m_level == m_level
+ && msg->m_message == m_message
+ && msg->m_line == m_line
+ && msg->m_url == m_url
+ && msg->m_requestId == m_requestId;
+}
+
+void ConsoleMessage::windowCleared(DOMWindow* window)
+{
+ if (!m_arguments)
+ return;
+ if (domWindowFromScriptState(m_arguments->globalState()) != window)
+ return;
+ if (!m_message)
+ m_message = "<message collected>";
+ m_arguments.clear();
+}
+
+unsigned ConsoleMessage::argumentCount()
+{
+ if (m_arguments)
+ return m_arguments->argumentCount();
+ return 0;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/ConsoleMessage.h b/Source/core/inspector/ConsoleMessage.h
new file mode 100644
index 0000000..1594df0
--- /dev/null
+++ b/Source/core/inspector/ConsoleMessage.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ * Copyright (C) 2009, 2010 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 ConsoleMessage_h
+#define ConsoleMessage_h
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/ConsoleAPITypes.h"
+#include "core/page/ConsoleTypes.h"
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class DOMWindow;
+class InjectedScriptManager;
+class InspectorFrontend;
+class InspectorObject;
+class ScriptArguments;
+class ScriptCallFrame;
+class ScriptCallStack;
+class ScriptValue;
+
+class ConsoleMessage {
+ WTF_MAKE_NONCOPYABLE(ConsoleMessage); WTF_MAKE_FAST_ALLOCATED;
+public:
+ ConsoleMessage(bool canGenerateCallStack, MessageSource, MessageType, MessageLevel, const String& message);
+ ConsoleMessage(bool canGenerateCallStack, MessageSource, MessageType, MessageLevel, const String& message, const String& url, unsigned line, ScriptState*, unsigned long requestIdentifier);
+ ConsoleMessage(bool canGenerateCallStack, MessageSource, MessageType, MessageLevel, const String& message, PassRefPtr<ScriptCallStack>, unsigned long requestIdentifier);
+ ConsoleMessage(bool canGenerateCallStack, MessageSource, MessageType, MessageLevel, const String& message, PassRefPtr<ScriptArguments>, ScriptState*, unsigned long requestIdentifier);
+ ~ConsoleMessage();
+
+ void addToFrontend(InspectorFrontend::Console*, InjectedScriptManager*, bool generatePreview);
+ void updateRepeatCountInConsole(InspectorFrontend::Console*);
+ void incrementCount() { ++m_repeatCount; }
+ bool isEqual(ConsoleMessage* msg) const;
+
+ MessageSource source() const { return m_source; }
+ const String& message() const { return m_message; }
+ MessageType type() const { return m_type; }
+
+ void windowCleared(DOMWindow*);
+
+ unsigned argumentCount();
+
+private:
+ void autogenerateMetadata(bool canGenerateCallStack, ScriptState* = 0);
+
+ MessageSource m_source;
+ MessageType m_type;
+ MessageLevel m_level;
+ String m_message;
+ RefPtr<ScriptArguments> m_arguments;
+ RefPtr<ScriptCallStack> m_callStack;
+ String m_url;
+ unsigned m_line;
+ unsigned m_repeatCount;
+ String m_requestId;
+};
+
+} // namespace WebCore
+
+#endif // ConsoleMessage_h
diff --git a/Source/core/inspector/ContentSearchUtils.cpp b/Source/core/inspector/ContentSearchUtils.cpp
new file mode 100644
index 0000000..e294336
--- /dev/null
+++ b/Source/core/inspector/ContentSearchUtils.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2011 Google 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 GOOGLE 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 GOOGLE 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 "core/inspector/ContentSearchUtils.h"
+
+#include "core/inspector/InspectorValues.h"
+#include "core/platform/text/RegularExpression.h"
+#include <wtf/StdLibExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+namespace ContentSearchUtils {
+
+namespace {
+// This should be kept the same as the one in front-end/utilities.js
+static const char regexSpecialCharacters[] = "[](){}+-*.,?\\^$|";
+}
+
+static String createSearchRegexSource(const String& text)
+{
+ String result;
+ const UChar* characters = text.characters();
+ String specials(regexSpecialCharacters);
+
+ for (unsigned i = 0; i < text.length(); i++) {
+ if (specials.find(characters[i]) != notFound)
+ result.append("\\");
+ result.append(characters[i]);
+ }
+
+ return result;
+}
+
+static inline size_t sizetExtractor(const size_t* value)
+{
+ return *value;
+}
+
+TextPosition textPositionFromOffset(size_t offset, const Vector<size_t>& lineEndings)
+{
+ const size_t* foundLineEnding = approximateBinarySearch<size_t, size_t>(lineEndings, lineEndings.size(), offset, sizetExtractor);
+ size_t lineIndex = foundLineEnding - &lineEndings.at(0);
+ if (offset > *foundLineEnding)
+ ++lineIndex;
+ size_t lineStartOffset = lineIndex > 0 ? lineEndings.at(lineIndex - 1) + 1 : 0;
+ size_t column = offset - lineStartOffset;
+ return TextPosition(OrdinalNumber::fromZeroBasedInt(lineIndex), OrdinalNumber::fromZeroBasedInt(column));
+}
+
+static Vector<pair<int, String> > getRegularExpressionMatchesByLines(const RegularExpression* regex, const String& text)
+{
+ Vector<pair<int, String> > result;
+ if (text.isEmpty())
+ return result;
+
+ OwnPtr<Vector<size_t> > endings(lineEndings(text));
+ size_t size = endings->size();
+ unsigned start = 0;
+ for (size_t lineNumber = 0; lineNumber < size; ++lineNumber) {
+ size_t lineEnd = endings->at(lineNumber);
+ String line = text.substring(start, lineEnd - start);
+ if (line.endsWith('\r'))
+ line = line.left(line.length() - 1);
+
+ int matchLength;
+ if (regex->match(line, 0, &matchLength) != -1)
+ result.append(pair<int, String>(lineNumber, line));
+
+ start = lineEnd + 1;
+ }
+ return result;
+}
+
+PassOwnPtr<Vector<size_t> > lineEndings(const String& text)
+{
+ OwnPtr<Vector<size_t> > result(adoptPtr(new Vector<size_t>()));
+
+ unsigned start = 0;
+ while (start < text.length()) {
+ size_t lineEnd = text.find('\n', start);
+ if (lineEnd == notFound)
+ break;
+
+ result->append(lineEnd);
+ start = lineEnd + 1;
+ }
+ result->append(text.length());
+
+ return result.release();
+}
+
+static PassRefPtr<TypeBuilder::Page::SearchMatch> buildObjectForSearchMatch(int lineNumber, const String& lineContent)
+{
+ return TypeBuilder::Page::SearchMatch::create()
+ .setLineNumber(lineNumber)
+ .setLineContent(lineContent)
+ .release();
+}
+
+PassOwnPtr<RegularExpression> createSearchRegex(const String& query, bool caseSensitive, bool isRegex)
+{
+ String regexSource = isRegex ? query : createSearchRegexSource(query);
+ return adoptPtr(new RegularExpression(regexSource, caseSensitive ? TextCaseSensitive : TextCaseInsensitive));
+}
+
+int countRegularExpressionMatches(const RegularExpression* regex, const String& content)
+{
+ if (content.isEmpty())
+ return 0;
+
+ int result = 0;
+ int position;
+ unsigned start = 0;
+ int matchLength;
+ while ((position = regex->match(content, start, &matchLength)) != -1) {
+ if (start >= content.length())
+ break;
+ if (matchLength > 0)
+ ++result;
+ start = position + 1;
+ }
+ return result;
+}
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > result = TypeBuilder::Array<TypeBuilder::Page::SearchMatch>::create();
+
+ OwnPtr<RegularExpression> regex = ContentSearchUtils::createSearchRegex(query, caseSensitive, isRegex);
+ Vector<pair<int, String> > matches = getRegularExpressionMatchesByLines(regex.get(), text);
+
+ for (Vector<pair<int, String> >::const_iterator it = matches.begin(); it != matches.end(); ++it)
+ result->addItem(buildObjectForSearchMatch(it->first, it->second));
+
+ return result;
+}
+
+static String findMagicComment(const String& content, const String& name)
+{
+ ASSERT(name.find("=") == notFound);
+ String pattern = "//@[\040\t]" + createSearchRegexSource(name) + "=[\040\t]*[^\\s\'\"]*[\040\t]*$";
+ RegularExpression regex(pattern, TextCaseSensitive, MultilineEnabled);
+
+ int matchLength;
+ int offset = regex.match(content, 0, &matchLength);
+ if (offset == -1)
+ return String();
+
+ String match = content.substring(offset, matchLength);
+ size_t separator = match.find("=");
+ ASSERT(separator != notFound);
+
+ return match.substring(separator + 1).stripWhiteSpace();
+}
+
+String findSourceURL(const String& content)
+{
+ return findMagicComment(content, "sourceURL");
+}
+
+String findSourceMapURL(const String& content)
+{
+ return findMagicComment(content, "sourceMappingURL");
+}
+
+} // namespace ContentSearchUtils
+} // namespace WebCore
+
diff --git a/Source/core/inspector/ContentSearchUtils.h b/Source/core/inspector/ContentSearchUtils.h
new file mode 100644
index 0000000..f7259de
--- /dev/null
+++ b/Source/core/inspector/ContentSearchUtils.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 Google 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 GOOGLE 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 GOOGLE 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 ContentSearchUtils_h
+#define ContentSearchUtils_h
+
+
+#include "InspectorTypeBuilder.h"
+#include <wtf/Vector.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/TextPosition.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InspectorArray;
+class RegularExpression;
+
+namespace ContentSearchUtils {
+
+PassOwnPtr<RegularExpression> createSearchRegex(const String& query, bool caseSensitive, bool isRegex);
+int countRegularExpressionMatches(const RegularExpression*, const String&);
+PassRefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> > searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex);
+TextPosition textPositionFromOffset(size_t offset, const Vector<size_t>& lineEndings);
+PassOwnPtr<Vector<size_t> > lineEndings(const String&);
+
+String findSourceURL(const String& content);
+String findSourceMapURL(const String& content);
+
+} // namespace ContentSearchUtils
+} // namespace WebCore
+
+
+#endif // !defined(ContentSearchUtils_h)
diff --git a/Source/core/inspector/DOMEditor.cpp b/Source/core/inspector/DOMEditor.cpp
new file mode 100644
index 0000000..095e4b2
--- /dev/null
+++ b/Source/core/inspector/DOMEditor.cpp
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/DOMEditor.h"
+
+#include "core/dom/Document.h"
+#include "core/dom/Element.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/Node.h"
+#include "core/dom/Text.h"
+#include "core/inspector/DOMPatchSupport.h"
+#include "core/inspector/InspectorHistory.h"
+
+#include "core/editing/markup.h"
+
+#include <wtf/RefPtr.h>
+
+using namespace std;
+
+namespace WebCore {
+
+class DOMEditor::RemoveChildAction : public InspectorHistory::Action {
+ WTF_MAKE_NONCOPYABLE(RemoveChildAction);
+public:
+ RemoveChildAction(Node* parentNode, Node* node)
+ : InspectorHistory::Action("RemoveChild")
+ , m_parentNode(parentNode)
+ , m_node(node)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ m_anchorNode = m_node->nextSibling();
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ return m_parentNode->removeChild(m_node.get(), ec);
+ }
+
+private:
+ RefPtr<Node> m_parentNode;
+ RefPtr<Node> m_node;
+ RefPtr<Node> m_anchorNode;
+};
+
+class DOMEditor::InsertBeforeAction : public InspectorHistory::Action {
+ WTF_MAKE_NONCOPYABLE(InsertBeforeAction);
+public:
+ InsertBeforeAction(Node* parentNode, PassRefPtr<Node> node, Node* anchorNode)
+ : InspectorHistory::Action("InsertBefore")
+ , m_parentNode(parentNode)
+ , m_node(node)
+ , m_anchorNode(anchorNode)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ if (m_node->parentNode()) {
+ m_removeChildAction = adoptPtr(new RemoveChildAction(m_node->parentNode(), m_node.get()));
+ if (!m_removeChildAction->perform(ec))
+ return false;
+ }
+ return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ if (!m_parentNode->removeChild(m_node.get(), ec))
+ return false;
+ if (m_removeChildAction)
+ return m_removeChildAction->undo(ec);
+ return true;
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ if (m_removeChildAction && !m_removeChildAction->redo(ec))
+ return false;
+ return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
+ }
+
+private:
+ RefPtr<Node> m_parentNode;
+ RefPtr<Node> m_node;
+ RefPtr<Node> m_anchorNode;
+ OwnPtr<RemoveChildAction> m_removeChildAction;
+};
+
+class DOMEditor::RemoveAttributeAction : public InspectorHistory::Action {
+ WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
+public:
+ RemoveAttributeAction(Element* element, const String& name)
+ : InspectorHistory::Action("RemoveAttribute")
+ , m_element(element)
+ , m_name(name)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ m_value = m_element->getAttribute(m_name);
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ m_element->setAttribute(m_name, m_value, ec);
+ return true;
+ }
+
+ virtual bool redo(ExceptionCode&)
+ {
+ m_element->removeAttribute(m_name);
+ return true;
+ }
+
+private:
+ RefPtr<Element> m_element;
+ String m_name;
+ String m_value;
+};
+
+class DOMEditor::SetAttributeAction : public InspectorHistory::Action {
+ WTF_MAKE_NONCOPYABLE(SetAttributeAction);
+public:
+ SetAttributeAction(Element* element, const String& name, const String& value)
+ : InspectorHistory::Action("SetAttribute")
+ , m_element(element)
+ , m_name(name)
+ , m_value(value)
+ , m_hadAttribute(false)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ m_hadAttribute = m_element->hasAttribute(m_name);
+ if (m_hadAttribute)
+ m_oldValue = m_element->getAttribute(m_name);
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ if (m_hadAttribute)
+ m_element->setAttribute(m_name, m_oldValue, ec);
+ else
+ m_element->removeAttribute(m_name);
+ return true;
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ m_element->setAttribute(m_name, m_value, ec);
+ return true;
+ }
+
+private:
+ RefPtr<Element> m_element;
+ String m_name;
+ String m_value;
+ bool m_hadAttribute;
+ String m_oldValue;
+};
+
+class DOMEditor::SetOuterHTMLAction : public InspectorHistory::Action {
+ WTF_MAKE_NONCOPYABLE(SetOuterHTMLAction);
+public:
+ SetOuterHTMLAction(Node* node, const String& html)
+ : InspectorHistory::Action("SetOuterHTML")
+ , m_node(node)
+ , m_nextSibling(node->nextSibling())
+ , m_html(html)
+ , m_newNode(0)
+ , m_history(adoptPtr(new InspectorHistory()))
+ , m_domEditor(adoptPtr(new DOMEditor(m_history.get())))
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ m_oldHTML = createMarkup(m_node.get());
+ DOMPatchSupport domPatchSupport(m_domEditor.get(), m_node->ownerDocument());
+ m_newNode = domPatchSupport.patchNode(m_node.get(), m_html, ec);
+ return !ec;
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ return m_history->undo(ec);
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ return m_history->redo(ec);
+ }
+
+ Node* newNode()
+ {
+ return m_newNode;
+ }
+
+private:
+ RefPtr<Node> m_node;
+ RefPtr<Node> m_nextSibling;
+ String m_html;
+ String m_oldHTML;
+ Node* m_newNode;
+ OwnPtr<InspectorHistory> m_history;
+ OwnPtr<DOMEditor> m_domEditor;
+};
+
+class DOMEditor::ReplaceWholeTextAction : public InspectorHistory::Action {
+ WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
+public:
+ ReplaceWholeTextAction(Text* textNode, const String& text)
+ : InspectorHistory::Action("ReplaceWholeText")
+ , m_textNode(textNode)
+ , m_text(text)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ m_oldText = m_textNode->wholeText();
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ m_textNode->replaceWholeText(m_oldText, ec);
+ return true;
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ m_textNode->replaceWholeText(m_text, ec);
+ return true;
+ }
+
+private:
+ RefPtr<Text> m_textNode;
+ String m_text;
+ String m_oldText;
+};
+
+class DOMEditor::ReplaceChildNodeAction : public InspectorHistory::Action {
+ WTF_MAKE_NONCOPYABLE(ReplaceChildNodeAction);
+public:
+ ReplaceChildNodeAction(Node* parentNode, PassRefPtr<Node> newNode, Node* oldNode)
+ : InspectorHistory::Action("ReplaceChildNode")
+ , m_parentNode(parentNode)
+ , m_newNode(newNode)
+ , m_oldNode(oldNode)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ return m_parentNode->replaceChild(m_oldNode, m_newNode.get(), ec);
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ return m_parentNode->replaceChild(m_newNode, m_oldNode.get(), ec);
+ }
+
+private:
+ RefPtr<Node> m_parentNode;
+ RefPtr<Node> m_newNode;
+ RefPtr<Node> m_oldNode;
+};
+
+class DOMEditor::SetNodeValueAction : public InspectorHistory::Action {
+ WTF_MAKE_NONCOPYABLE(SetNodeValueAction);
+public:
+ SetNodeValueAction(Node* node, const String& value)
+ : InspectorHistory::Action("SetNodeValue")
+ , m_node(node)
+ , m_value(value)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ m_oldValue = m_node->nodeValue();
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ m_node->setNodeValue(m_oldValue, ec);
+ return !ec;
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ m_node->setNodeValue(m_value, ec);
+ return !ec;
+ }
+
+private:
+ RefPtr<Node> m_node;
+ String m_value;
+ String m_oldValue;
+};
+
+DOMEditor::DOMEditor(InspectorHistory* history) : m_history(history) { }
+
+DOMEditor::~DOMEditor() { }
+
+bool DOMEditor::insertBefore(Node* parentNode, PassRefPtr<Node> node, Node* anchorNode, ExceptionCode& ec)
+{
+ return m_history->perform(adoptPtr(new InsertBeforeAction(parentNode, node, anchorNode)), ec);
+}
+
+bool DOMEditor::removeChild(Node* parentNode, Node* node, ExceptionCode& ec)
+{
+ return m_history->perform(adoptPtr(new RemoveChildAction(parentNode, node)), ec);
+}
+
+bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ExceptionCode& ec)
+{
+ return m_history->perform(adoptPtr(new SetAttributeAction(element, name, value)), ec);
+}
+
+bool DOMEditor::removeAttribute(Element* element, const String& name, ExceptionCode& ec)
+{
+ return m_history->perform(adoptPtr(new RemoveAttributeAction(element, name)), ec);
+}
+
+bool DOMEditor::setOuterHTML(Node* node, const String& html, Node** newNode, ExceptionCode& ec)
+{
+ OwnPtr<SetOuterHTMLAction> action = adoptPtr(new SetOuterHTMLAction(node, html));
+ SetOuterHTMLAction* rawAction = action.get();
+ bool result = m_history->perform(action.release(), ec);
+ if (result)
+ *newNode = rawAction->newNode();
+ return result;
+}
+
+bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ExceptionCode& ec)
+{
+ return m_history->perform(adoptPtr(new ReplaceWholeTextAction(textNode, text)), ec);
+}
+
+bool DOMEditor::replaceChild(Node* parentNode, PassRefPtr<Node> newNode, Node* oldNode, ExceptionCode& ec)
+{
+ return m_history->perform(adoptPtr(new ReplaceChildNodeAction(parentNode, newNode, oldNode)), ec);
+}
+
+bool DOMEditor::setNodeValue(Node* node, const String& value, ExceptionCode& ec)
+{
+ return m_history->perform(adoptPtr(new SetNodeValueAction(node, value)), ec);
+}
+
+static void populateErrorString(const ExceptionCode& ec, ErrorString* errorString)
+{
+ if (ec) {
+ ExceptionCodeDescription description(ec);
+ *errorString = description.name;
+ }
+}
+
+bool DOMEditor::insertBefore(Node* parentNode, PassRefPtr<Node> node, Node* anchorNode, ErrorString* errorString)
+{
+ ExceptionCode ec = 0;
+ bool result = insertBefore(parentNode, node, anchorNode, ec);
+ populateErrorString(ec, errorString);
+ return result;
+}
+
+bool DOMEditor::removeChild(Node* parentNode, Node* node, ErrorString* errorString)
+{
+ ExceptionCode ec = 0;
+ bool result = removeChild(parentNode, node, ec);
+ populateErrorString(ec, errorString);
+ return result;
+}
+
+bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ErrorString* errorString)
+{
+ ExceptionCode ec = 0;
+ bool result = setAttribute(element, name, value, ec);
+ populateErrorString(ec, errorString);
+ return result;
+}
+
+bool DOMEditor::removeAttribute(Element* element, const String& name, ErrorString* errorString)
+{
+ ExceptionCode ec = 0;
+ bool result = removeAttribute(element, name, ec);
+ populateErrorString(ec, errorString);
+ return result;
+}
+
+bool DOMEditor::setOuterHTML(Node* node, const String& html, Node** newNode, ErrorString* errorString)
+{
+ ExceptionCode ec = 0;
+ bool result = setOuterHTML(node, html, newNode, ec);
+ populateErrorString(ec, errorString);
+ return result;
+}
+
+bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ErrorString* errorString)
+{
+ ExceptionCode ec = 0;
+ bool result = replaceWholeText(textNode, text, ec);
+ populateErrorString(ec, errorString);
+ return result;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/DOMEditor.h b/Source/core/inspector/DOMEditor.h
new file mode 100644
index 0000000..7691588
--- /dev/null
+++ b/Source/core/inspector/DOMEditor.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 DOMEditor_h
+#define DOMEditor_h
+
+#include "core/dom/ExceptionCode.h"
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Element;
+class InspectorHistory;
+class Node;
+class Text;
+
+
+typedef String ErrorString;
+
+class DOMEditor {
+ WTF_MAKE_NONCOPYABLE(DOMEditor); WTF_MAKE_FAST_ALLOCATED;
+public:
+ explicit DOMEditor(InspectorHistory*);
+ ~DOMEditor();
+
+ bool insertBefore(Node* parentNode, PassRefPtr<Node>, Node* anchorNode, ExceptionCode&);
+ bool removeChild(Node* parentNode, Node*, ExceptionCode&);
+ bool setAttribute(Element*, const String& name, const String& value, ExceptionCode&);
+ bool removeAttribute(Element*, const String& name, ExceptionCode&);
+ bool setOuterHTML(Node*, const String& html, Node** newNode, ExceptionCode&);
+ bool replaceWholeText(Text*, const String& text, ExceptionCode&);
+ bool replaceChild(Node* parentNode, PassRefPtr<Node> newNode, Node* oldNode, ExceptionCode&);
+ bool setNodeValue(Node* parentNode, const String& value, ExceptionCode&);
+
+ bool insertBefore(Node* parentNode, PassRefPtr<Node>, Node* anchorNode, ErrorString*);
+ bool removeChild(Node* parentNode, Node*, ErrorString*);
+ bool setAttribute(Element*, const String& name, const String& value, ErrorString*);
+ bool removeAttribute(Element*, const String& name, ErrorString*);
+ bool setOuterHTML(Node*, const String& html, Node** newNode, ErrorString*);
+ bool replaceWholeText(Text*, const String& text, ErrorString*);
+
+private:
+ class DOMAction;
+ class RemoveChildAction;
+ class InsertBeforeAction;
+ class RemoveAttributeAction;
+ class SetAttributeAction;
+ class SetOuterHTMLAction;
+ class ReplaceWholeTextAction;
+ class ReplaceChildNodeAction;
+ class SetNodeValueAction;
+
+ InspectorHistory* m_history;
+};
+
+
+} // namespace WebCore
+
+#endif // !defined(DOMEditor_h)
diff --git a/Source/core/inspector/DOMPatchSupport.cpp b/Source/core/inspector/DOMPatchSupport.cpp
new file mode 100644
index 0000000..12dc1b0
--- /dev/null
+++ b/Source/core/inspector/DOMPatchSupport.cpp
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/DOMPatchSupport.h"
+
+#include "HTMLNames.h"
+#include "core/dom/Attribute.h"
+#include "core/dom/ContextFeatures.h"
+#include "core/dom/Document.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/dom/Node.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLElement.h"
+#include "core/html/HTMLHeadElement.h"
+#include "core/html/parser/HTMLDocumentParser.h"
+#include "core/inspector/DOMEditor.h"
+#include "core/inspector/InspectorHistory.h"
+#include "core/xml/parser/XMLDocumentParser.h"
+
+#include <wtf/Deque.h>
+#include <wtf/HashTraits.h>
+#include <wtf/RefPtr.h>
+#include <wtf/SHA1.h>
+#include <wtf/text/Base64.h>
+#include <wtf/text/CString.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using HTMLNames::bodyTag;
+using HTMLNames::headTag;
+using HTMLNames::htmlTag;
+
+struct DOMPatchSupport::Digest {
+ explicit Digest(Node* node) : m_node(node) { }
+
+ String m_sha1;
+ String m_attrsSHA1;
+ Node* m_node;
+ Vector<OwnPtr<Digest> > m_children;
+};
+
+void DOMPatchSupport::patchDocument(Document* document, const String& markup)
+{
+ InspectorHistory history;
+ DOMEditor domEditor(&history);
+ DOMPatchSupport patchSupport(&domEditor, document);
+ patchSupport.patchDocument(markup);
+}
+
+DOMPatchSupport::DOMPatchSupport(DOMEditor* domEditor, Document* document)
+ : m_domEditor(domEditor)
+ , m_document(document)
+{
+}
+
+DOMPatchSupport::~DOMPatchSupport() { }
+
+void DOMPatchSupport::patchDocument(const String& markup)
+{
+ RefPtr<Document> newDocument;
+ if (m_document->isHTMLDocument())
+ newDocument = HTMLDocument::create(0, KURL());
+ else if (m_document->isXHTMLDocument())
+ newDocument = HTMLDocument::createXHTML(0, KURL());
+#if ENABLE(SVG)
+ else if (m_document->isSVGDocument())
+ newDocument = Document::create(0, KURL());
+#endif
+
+ ASSERT(newDocument);
+ newDocument->setContextFeatures(m_document->contextFeatures());
+ RefPtr<DocumentParser> parser;
+ if (m_document->isHTMLDocument())
+ parser = HTMLDocumentParser::create(static_cast<HTMLDocument*>(newDocument.get()), false);
+ else
+ parser = XMLDocumentParser::create(newDocument.get(), 0);
+ parser->insert(markup); // Use insert() so that the parser will not yield.
+ parser->finish();
+ parser->detach();
+
+ OwnPtr<Digest> oldInfo = createDigest(m_document->documentElement(), 0);
+ OwnPtr<Digest> newInfo = createDigest(newDocument->documentElement(), &m_unusedNodesMap);
+
+ if (!innerPatchNode(oldInfo.get(), newInfo.get(), IGNORE_EXCEPTION)) {
+ // Fall back to rewrite.
+ m_document->write(markup);
+ m_document->close();
+ }
+}
+
+Node* DOMPatchSupport::patchNode(Node* node, const String& markup, ExceptionCode& ec)
+{
+ // Don't parse <html> as a fragment.
+ if (node->isDocumentNode() || (node->parentNode() && node->parentNode()->isDocumentNode())) {
+ patchDocument(markup);
+ return 0;
+ }
+
+ Node* previousSibling = node->previousSibling();
+ // FIXME: This code should use one of createFragment* in markup.h
+ RefPtr<DocumentFragment> fragment = DocumentFragment::create(m_document);
+ if (m_document->isHTMLDocument())
+ fragment->parseHTML(markup, node->parentElement() ? node->parentElement() : m_document->documentElement());
+ else
+ fragment->parseXML(markup, node->parentElement() ? node->parentElement() : m_document->documentElement());
+
+ // Compose the old list.
+ ContainerNode* parentNode = node->parentNode();
+ Vector<OwnPtr<Digest> > oldList;
+ for (Node* child = parentNode->firstChild(); child; child = child->nextSibling())
+ oldList.append(createDigest(child, 0));
+
+ // Compose the new list.
+ String markupCopy = markup;
+ markupCopy.makeLower();
+ Vector<OwnPtr<Digest> > newList;
+ for (Node* child = parentNode->firstChild(); child != node; child = child->nextSibling())
+ newList.append(createDigest(child, 0));
+ for (Node* child = fragment->firstChild(); child; child = child->nextSibling()) {
+ if (child->hasTagName(headTag) && !child->firstChild() && markupCopy.find("</head>") == notFound)
+ continue; // HTML5 parser inserts empty <head> tag whenever it parses <body>
+ if (child->hasTagName(bodyTag) && !child->firstChild() && markupCopy.find("</body>") == notFound)
+ continue; // HTML5 parser inserts empty <body> tag whenever it parses </head>
+ newList.append(createDigest(child, &m_unusedNodesMap));
+ }
+ for (Node* child = node->nextSibling(); child; child = child->nextSibling())
+ newList.append(createDigest(child, 0));
+
+ if (!innerPatchChildren(parentNode, oldList, newList, ec)) {
+ // Fall back to total replace.
+ ec = 0;
+ if (!m_domEditor->replaceChild(parentNode, fragment.release(), node, ec))
+ return 0;
+ }
+ return previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
+}
+
+bool DOMPatchSupport::innerPatchNode(Digest* oldDigest, Digest* newDigest, ExceptionCode& ec)
+{
+ if (oldDigest->m_sha1 == newDigest->m_sha1)
+ return true;
+
+ Node* oldNode = oldDigest->m_node;
+ Node* newNode = newDigest->m_node;
+
+ if (newNode->nodeType() != oldNode->nodeType() || newNode->nodeName() != oldNode->nodeName())
+ return m_domEditor->replaceChild(oldNode->parentNode(), newNode, oldNode, ec);
+
+ if (oldNode->nodeValue() != newNode->nodeValue()) {
+ if (!m_domEditor->setNodeValue(oldNode, newNode->nodeValue(), ec))
+ return false;
+ }
+
+ if (oldNode->nodeType() != Node::ELEMENT_NODE)
+ return true;
+
+ // Patch attributes
+ Element* oldElement = toElement(oldNode);
+ Element* newElement = toElement(newNode);
+ if (oldDigest->m_attrsSHA1 != newDigest->m_attrsSHA1) {
+ // FIXME: Create a function in Element for removing all properties. Take in account whether did/willModifyAttribute are important.
+ if (oldElement->hasAttributesWithoutUpdate()) {
+ while (oldElement->attributeCount()) {
+ const Attribute* attribute = oldElement->attributeItem(0);
+ if (!m_domEditor->removeAttribute(oldElement, attribute->localName(), ec))
+ return false;
+ }
+ }
+
+ // FIXME: Create a function in Element for copying properties. cloneDataFromElement() is close but not enough for this case.
+ if (newElement->hasAttributesWithoutUpdate()) {
+ size_t numAttrs = newElement->attributeCount();
+ for (size_t i = 0; i < numAttrs; ++i) {
+ const Attribute* attribute = newElement->attributeItem(i);
+ if (!m_domEditor->setAttribute(oldElement, attribute->name().localName(), attribute->value(), ec))
+ return false;
+ }
+ }
+ }
+
+ bool result = innerPatchChildren(oldElement, oldDigest->m_children, newDigest->m_children, ec);
+ m_unusedNodesMap.remove(newDigest->m_sha1);
+ return result;
+}
+
+pair<DOMPatchSupport::ResultMap, DOMPatchSupport::ResultMap>
+DOMPatchSupport::diff(const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList)
+{
+ ResultMap newMap(newList.size());
+ ResultMap oldMap(oldList.size());
+
+ for (size_t i = 0; i < oldMap.size(); ++i) {
+ oldMap[i].first = 0;
+ oldMap[i].second = 0;
+ }
+
+ for (size_t i = 0; i < newMap.size(); ++i) {
+ newMap[i].first = 0;
+ newMap[i].second = 0;
+ }
+
+ // Trim head and tail.
+ for (size_t i = 0; i < oldList.size() && i < newList.size() && oldList[i]->m_sha1 == newList[i]->m_sha1; ++i) {
+ oldMap[i].first = oldList[i].get();
+ oldMap[i].second = i;
+ newMap[i].first = newList[i].get();
+ newMap[i].second = i;
+ }
+ for (size_t i = 0; i < oldList.size() && i < newList.size() && oldList[oldList.size() - i - 1]->m_sha1 == newList[newList.size() - i - 1]->m_sha1; ++i) {
+ size_t oldIndex = oldList.size() - i - 1;
+ size_t newIndex = newList.size() - i - 1;
+ oldMap[oldIndex].first = oldList[oldIndex].get();
+ oldMap[oldIndex].second = newIndex;
+ newMap[newIndex].first = newList[newIndex].get();
+ newMap[newIndex].second = oldIndex;
+ }
+
+ typedef HashMap<String, Vector<size_t> > DiffTable;
+ DiffTable newTable;
+ DiffTable oldTable;
+
+ for (size_t i = 0; i < newList.size(); ++i) {
+ DiffTable::iterator it = newTable.add(newList[i]->m_sha1, Vector<size_t>()).iterator;
+ it->value.append(i);
+ }
+
+ for (size_t i = 0; i < oldList.size(); ++i) {
+ DiffTable::iterator it = oldTable.add(oldList[i]->m_sha1, Vector<size_t>()).iterator;
+ it->value.append(i);
+ }
+
+ for (DiffTable::iterator newIt = newTable.begin(); newIt != newTable.end(); ++newIt) {
+ if (newIt->value.size() != 1)
+ continue;
+
+ DiffTable::iterator oldIt = oldTable.find(newIt->key);
+ if (oldIt == oldTable.end() || oldIt->value.size() != 1)
+ continue;
+
+ newMap[newIt->value[0]] = make_pair(newList[newIt->value[0]].get(), oldIt->value[0]);
+ oldMap[oldIt->value[0]] = make_pair(oldList[oldIt->value[0]].get(), newIt->value[0]);
+ }
+
+ for (size_t i = 0; newList.size() > 0 && i < newList.size() - 1; ++i) {
+ if (!newMap[i].first || newMap[i + 1].first)
+ continue;
+
+ size_t j = newMap[i].second + 1;
+ if (j < oldMap.size() && !oldMap[j].first && newList[i + 1]->m_sha1 == oldList[j]->m_sha1) {
+ newMap[i + 1] = make_pair(newList[i + 1].get(), j);
+ oldMap[j] = make_pair(oldList[j].get(), i + 1);
+ }
+ }
+
+ for (size_t i = newList.size() - 1; newList.size() > 0 && i > 0; --i) {
+ if (!newMap[i].first || newMap[i - 1].first || newMap[i].second <= 0)
+ continue;
+
+ size_t j = newMap[i].second - 1;
+ if (!oldMap[j].first && newList[i - 1]->m_sha1 == oldList[j]->m_sha1) {
+ newMap[i - 1] = make_pair(newList[i - 1].get(), j);
+ oldMap[j] = make_pair(oldList[j].get(), i - 1);
+ }
+ }
+
+#ifdef DEBUG_DOM_PATCH_SUPPORT
+ dumpMap(oldMap, "OLD");
+ dumpMap(newMap, "NEW");
+#endif
+
+ return make_pair(oldMap, newMap);
+}
+
+bool DOMPatchSupport::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionCode& ec)
+{
+ pair<ResultMap, ResultMap> resultMaps = diff(oldList, newList);
+ ResultMap& oldMap = resultMaps.first;
+ ResultMap& newMap = resultMaps.second;
+
+ Digest* oldHead = 0;
+ Digest* oldBody = 0;
+
+ // 1. First strip everything except for the nodes that retain. Collect pending merges.
+ HashMap<Digest*, Digest*> merges;
+ HashSet<size_t, WTF::IntHash<size_t>, WTF::UnsignedWithZeroKeyHashTraits<size_t> > usedNewOrdinals;
+ for (size_t i = 0; i < oldList.size(); ++i) {
+ if (oldMap[i].first) {
+ if (!usedNewOrdinals.contains(oldMap[i].second)) {
+ usedNewOrdinals.add(oldMap[i].second);
+ continue;
+ }
+ oldMap[i].first = 0;
+ oldMap[i].second = 0;
+ }
+
+ // Always match <head> and <body> tags with each other - we can't remove them from the DOM
+ // upon patching.
+ if (oldList[i]->m_node->hasTagName(headTag)) {
+ oldHead = oldList[i].get();
+ continue;
+ }
+ if (oldList[i]->m_node->hasTagName(bodyTag)) {
+ oldBody = oldList[i].get();
+ continue;
+ }
+
+ // Check if this change is between stable nodes. If it is, consider it as "modified".
+ if (!m_unusedNodesMap.contains(oldList[i]->m_sha1) && (!i || oldMap[i - 1].first) && (i == oldMap.size() - 1 || oldMap[i + 1].first)) {
+ size_t anchorCandidate = i ? oldMap[i - 1].second + 1 : 0;
+ size_t anchorAfter = i == oldMap.size() - 1 ? anchorCandidate + 1 : oldMap[i + 1].second;
+ if (anchorAfter - anchorCandidate == 1 && anchorCandidate < newList.size())
+ merges.set(newList[anchorCandidate].get(), oldList[i].get());
+ else {
+ if (!removeChildAndMoveToNew(oldList[i].get(), ec))
+ return false;
+ }
+ } else {
+ if (!removeChildAndMoveToNew(oldList[i].get(), ec))
+ return false;
+ }
+ }
+
+ // Mark retained nodes as used, do not reuse node more than once.
+ HashSet<size_t, WTF::IntHash<size_t>, WTF::UnsignedWithZeroKeyHashTraits<size_t> > usedOldOrdinals;
+ for (size_t i = 0; i < newList.size(); ++i) {
+ if (!newMap[i].first)
+ continue;
+ size_t oldOrdinal = newMap[i].second;
+ if (usedOldOrdinals.contains(oldOrdinal)) {
+ // Do not map node more than once
+ newMap[i].first = 0;
+ newMap[i].second = 0;
+ continue;
+ }
+ usedOldOrdinals.add(oldOrdinal);
+ markNodeAsUsed(newMap[i].first);
+ }
+
+ // Mark <head> and <body> nodes for merge.
+ if (oldHead || oldBody) {
+ for (size_t i = 0; i < newList.size(); ++i) {
+ if (oldHead && newList[i]->m_node->hasTagName(headTag))
+ merges.set(newList[i].get(), oldHead);
+ if (oldBody && newList[i]->m_node->hasTagName(bodyTag))
+ merges.set(newList[i].get(), oldBody);
+ }
+ }
+
+ // 2. Patch nodes marked for merge.
+ for (HashMap<Digest*, Digest*>::iterator it = merges.begin(); it != merges.end(); ++it) {
+ if (!innerPatchNode(it->value, it->key, ec))
+ return false;
+ }
+
+ // 3. Insert missing nodes.
+ for (size_t i = 0; i < newMap.size(); ++i) {
+ if (newMap[i].first || merges.contains(newList[i].get()))
+ continue;
+ if (!insertBeforeAndMarkAsUsed(parentNode, newList[i].get(), parentNode->childNode(i), ec))
+ return false;
+ }
+
+ // 4. Then put all nodes that retained into their slots (sort by new index).
+ for (size_t i = 0; i < oldMap.size(); ++i) {
+ if (!oldMap[i].first)
+ continue;
+ RefPtr<Node> node = oldMap[i].first->m_node;
+ Node* anchorNode = parentNode->childNode(oldMap[i].second);
+ if (node.get() == anchorNode)
+ continue;
+ if (node->hasTagName(bodyTag) || node->hasTagName(headTag))
+ continue; // Never move head or body, move the rest of the nodes around them.
+
+ if (!m_domEditor->insertBefore(parentNode, node.release(), anchorNode, ec))
+ return false;
+ }
+ return true;
+}
+
+static void addStringToSHA1(SHA1& sha1, const String& string)
+{
+ CString cString = string.utf8();
+ sha1.addBytes(reinterpret_cast<const uint8_t*>(cString.data()), cString.length());
+}
+
+PassOwnPtr<DOMPatchSupport::Digest> DOMPatchSupport::createDigest(Node* node, UnusedNodesMap* unusedNodesMap)
+{
+ Digest* digest = new Digest(node);
+
+ SHA1 sha1;
+
+ Node::NodeType nodeType = node->nodeType();
+ sha1.addBytes(reinterpret_cast<const uint8_t*>(&nodeType), sizeof(nodeType));
+ addStringToSHA1(sha1, node->nodeName());
+ addStringToSHA1(sha1, node->nodeValue());
+
+ if (node->nodeType() == Node::ELEMENT_NODE) {
+ Node* child = node->firstChild();
+ while (child) {
+ OwnPtr<Digest> childInfo = createDigest(child, unusedNodesMap);
+ addStringToSHA1(sha1, childInfo->m_sha1);
+ child = child->nextSibling();
+ digest->m_children.append(childInfo.release());
+ }
+ Element* element = toElement(node);
+
+ if (element->hasAttributesWithoutUpdate()) {
+ size_t numAttrs = element->attributeCount();
+ SHA1 attrsSHA1;
+ for (size_t i = 0; i < numAttrs; ++i) {
+ const Attribute* attribute = element->attributeItem(i);
+ addStringToSHA1(attrsSHA1, attribute->name().toString());
+ addStringToSHA1(attrsSHA1, attribute->value());
+ }
+ Vector<uint8_t, 20> attrsHash;
+ attrsSHA1.computeHash(attrsHash);
+ digest->m_attrsSHA1 = base64Encode(reinterpret_cast<const char*>(attrsHash.data()), 10);
+ addStringToSHA1(sha1, digest->m_attrsSHA1);
+ }
+ }
+
+ Vector<uint8_t, 20> hash;
+ sha1.computeHash(hash);
+ digest->m_sha1 = base64Encode(reinterpret_cast<const char*>(hash.data()), 10);
+ if (unusedNodesMap)
+ unusedNodesMap->add(digest->m_sha1, digest);
+ return adoptPtr(digest);
+}
+
+bool DOMPatchSupport::insertBeforeAndMarkAsUsed(ContainerNode* parentNode, Digest* digest, Node* anchor, ExceptionCode& ec)
+{
+ bool result = m_domEditor->insertBefore(parentNode, digest->m_node, anchor, ec);
+ markNodeAsUsed(digest);
+ return result;
+}
+
+bool DOMPatchSupport::removeChildAndMoveToNew(Digest* oldDigest, ExceptionCode& ec)
+{
+ RefPtr<Node> oldNode = oldDigest->m_node;
+ if (!m_domEditor->removeChild(oldNode->parentNode(), oldNode.get(), ec))
+ return false;
+
+ // Diff works within levels. In order not to lose the node identity when user
+ // prepends his HTML with "<div>" (i.e. all nodes are shifted to the next nested level),
+ // prior to dropping the original node on the floor, check whether new DOM has a digest
+ // with matching sha1. If it does, replace it with the original DOM chunk. Chances are
+ // high that it will get merged back into the original DOM during the further patching.
+ UnusedNodesMap::iterator it = m_unusedNodesMap.find(oldDigest->m_sha1);
+ if (it != m_unusedNodesMap.end()) {
+ Digest* newDigest = it->value;
+ Node* newNode = newDigest->m_node;
+ if (!m_domEditor->replaceChild(newNode->parentNode(), oldNode, newNode, ec))
+ return false;
+ newDigest->m_node = oldNode.get();
+ markNodeAsUsed(newDigest);
+ return true;
+ }
+
+ for (size_t i = 0; i < oldDigest->m_children.size(); ++i) {
+ if (!removeChildAndMoveToNew(oldDigest->m_children[i].get(), ec))
+ return false;
+ }
+ return true;
+}
+
+void DOMPatchSupport::markNodeAsUsed(Digest* digest)
+{
+ Deque<Digest*> queue;
+ queue.append(digest);
+ while (!queue.isEmpty()) {
+ Digest* first = queue.takeFirst();
+ m_unusedNodesMap.remove(first->m_sha1);
+ for (size_t i = 0; i < first->m_children.size(); ++i)
+ queue.append(first->m_children[i].get());
+ }
+}
+
+#ifdef DEBUG_DOM_PATCH_SUPPORT
+static String nodeName(Node* node)
+{
+ if (node->document()->isXHTMLDocument())
+ return node->nodeName();
+ return node->nodeName().lower();
+}
+
+void DOMPatchSupport::dumpMap(const ResultMap& map, const String& name)
+{
+ fprintf(stderr, "\n\n");
+ for (size_t i = 0; i < map.size(); ++i)
+ fprintf(stderr, "%s[%lu]: %s (%p) - [%lu]\n", name.utf8().data(), i, map[i].first ? nodeName(map[i].first->m_node).utf8().data() : "", map[i].first, map[i].second);
+}
+#endif
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/DOMPatchSupport.h b/Source/core/inspector/DOMPatchSupport.h
new file mode 100644
index 0000000..7e53a3e
--- /dev/null
+++ b/Source/core/inspector/DOMPatchSupport.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 DOMPatchSupport_h
+#define DOMPatchSupport_h
+
+#include "core/dom/ExceptionCode.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ContainerNode;
+class DOMEditor;
+class Document;
+class Node;
+
+
+class DOMPatchSupport {
+ WTF_MAKE_NONCOPYABLE(DOMPatchSupport);
+public:
+ static void patchDocument(Document*, const String& markup);
+
+ DOMPatchSupport(DOMEditor*, Document*);
+ virtual ~DOMPatchSupport();
+
+ void patchDocument(const String& markup);
+ Node* patchNode(Node*, const String& markup, ExceptionCode&);
+
+private:
+ struct Digest;
+ typedef Vector<pair<Digest*, size_t> > ResultMap;
+ typedef HashMap<String, Digest*> UnusedNodesMap;
+
+ bool innerPatchNode(Digest* oldNode, Digest* newNode, ExceptionCode&);
+ std::pair<ResultMap, ResultMap> diff(const Vector<OwnPtr<Digest> >& oldChildren, const Vector<OwnPtr<Digest> >& newChildren);
+ bool innerPatchChildren(ContainerNode*, const Vector<OwnPtr<Digest> >& oldChildren, const Vector<OwnPtr<Digest> >& newChildren, ExceptionCode&);
+ PassOwnPtr<Digest> createDigest(Node*, UnusedNodesMap*);
+ bool insertBeforeAndMarkAsUsed(ContainerNode*, Digest*, Node* anchor, ExceptionCode&);
+ bool removeChildAndMoveToNew(Digest*, ExceptionCode&);
+ void markNodeAsUsed(Digest*);
+#ifdef DEBUG_DOM_PATCH_SUPPORT
+ void dumpMap(const ResultMap&, const String& name);
+#endif
+
+ DOMEditor* m_domEditor;
+ Document* m_document;
+
+ UnusedNodesMap m_unusedNodesMap;
+};
+
+
+} // namespace WebCore
+
+#endif // !defined(DOMPatchSupport_h)
diff --git a/Source/core/inspector/HeapGraphSerializer.cpp b/Source/core/inspector/HeapGraphSerializer.cpp
new file mode 100644
index 0000000..41d1824
--- /dev/null
+++ b/Source/core/inspector/HeapGraphSerializer.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/HeapGraphSerializer.h"
+
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include <wtf/MemoryInstrumentationHashMap.h>
+#include <wtf/MemoryInstrumentationVector.h>
+#include <wtf/MemoryObjectInfo.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+HeapGraphSerializer::HeapGraphSerializer(Client* client)
+ : m_client(client)
+ , m_strings(Strings::create())
+ , m_edges(Edges::create())
+ , m_nodeEdgesCount(0)
+ , m_nodes(Nodes::create())
+ , m_baseToRealNodeIdMap(BaseToRealNodeIdMap::create())
+ , m_typeStrings(InspectorObject::create())
+ , m_leafCount(0)
+{
+ ASSERT(m_client);
+ m_strings->addItem(String()); // An empty string with 0 index.
+
+ memset(m_edgeTypes, 0, sizeof(m_edgeTypes));
+
+ m_edgeTypes[WTF::PointerMember] = registerTypeString("weak");
+ m_edgeTypes[WTF::RetainingPointer] = registerTypeString("property");
+
+ // FIXME: It is used as a magic constant for 'object' node type.
+ registerTypeString("object");
+
+ m_unknownClassNameId = registerString("unknown");
+}
+
+HeapGraphSerializer::~HeapGraphSerializer()
+{
+}
+
+void HeapGraphSerializer::pushUpdateIfNeeded()
+{
+ static const size_t chunkSize = 10000;
+ static const size_t averageEdgesPerNode = 5;
+
+ if (m_strings->length() <= chunkSize
+ && m_nodes->length() <= chunkSize * s_nodeFieldsCount
+ && m_edges->length() <= chunkSize * averageEdgesPerNode * s_edgeFieldsCount
+ && m_baseToRealNodeIdMap->length() <= chunkSize * s_idMapEntryFieldCount)
+ return;
+
+ pushUpdate();
+}
+
+void HeapGraphSerializer::pushUpdate()
+{
+ typedef TypeBuilder::Memory::HeapSnapshotChunk HeapSnapshotChunk;
+
+ RefPtr<HeapSnapshotChunk> chunk = HeapSnapshotChunk::create()
+ .setStrings(m_strings.release())
+ .setNodes(m_nodes.release())
+ .setEdges(m_edges.release())
+ .setBaseToRealNodeId(m_baseToRealNodeIdMap.release());
+
+ m_client->addNativeSnapshotChunk(chunk.release());
+
+ m_strings = Strings::create();
+ m_edges = Edges::create();
+ m_nodes = Nodes::create();
+ m_baseToRealNodeIdMap = BaseToRealNodeIdMap::create();
+}
+
+void HeapGraphSerializer::reportNode(const WTF::MemoryObjectInfo& info)
+{
+ ASSERT(info.reportedPointer());
+ reportNodeImpl(info, m_nodeEdgesCount);
+ m_nodeEdgesCount = 0;
+ if (info.isRoot())
+ m_roots.append(info.reportedPointer());
+ pushUpdateIfNeeded();
+}
+
+int HeapGraphSerializer::reportNodeImpl(const WTF::MemoryObjectInfo& info, int edgesCount)
+{
+ int nodeId = toNodeId(info.reportedPointer());
+ int classNameId = info.classNameId();
+ m_nodes->addItem(classNameId ? classNameId : m_unknownClassNameId);
+ m_nodes->addItem(info.nameId());
+ m_nodes->addItem(nodeId);
+ m_nodes->addItem(info.objectSize());
+ m_nodes->addItem(edgesCount);
+
+ return nodeId;
+}
+
+void HeapGraphSerializer::reportEdge(const void* to, const char* name, WTF::MemberType memberType)
+{
+ ASSERT(to);
+ reportEdgeImpl(toNodeId(to), name, m_edgeTypes[memberType]);
+ pushUpdateIfNeeded();
+}
+
+void HeapGraphSerializer::reportEdgeImpl(const int toNodeId, const char* name, int memberType)
+{
+ ASSERT(memberType >= 0);
+ ASSERT(memberType < WTF::LastMemberTypeEntry);
+
+ m_edges->addItem(memberType);
+ m_edges->addItem(registerString(name));
+ m_edges->addItem(toNodeId);
+
+ ++m_nodeEdgesCount;
+}
+
+void HeapGraphSerializer::reportLeaf(const WTF::MemoryObjectInfo& info, const char* edgeName)
+{
+ int nodeId = reportNodeImpl(info, 0);
+ reportEdgeImpl(nodeId, edgeName, m_edgeTypes[WTF::RetainingPointer]);
+ pushUpdateIfNeeded();
+}
+
+void HeapGraphSerializer::reportBaseAddress(const void* base, const void* real)
+{
+ m_baseToRealNodeIdMap->addItem(toNodeId(base));
+ m_baseToRealNodeIdMap->addItem(toNodeId(real));
+}
+
+PassRefPtr<InspectorObject> HeapGraphSerializer::finish()
+{
+ addRootNode();
+ pushUpdate();
+ String metaString =
+ "{"
+ "\"node_fields\":["
+ "\"type\","
+ "\"name\","
+ "\"id\","
+ "\"self_size\","
+ "\"edge_count\""
+ "],"
+ "\"node_types\":["
+ "[]," // FIXME: It is a fallback for Heap Snapshot parser. In case of Native Heap Snapshot it is a plain string id.
+ "\"string\","
+ "\"number\","
+ "\"number\","
+ "\"number\""
+ "],"
+ "\"edge_fields\":["
+ "\"type\","
+ "\"name_or_index\","
+ "\"to_node\""
+ "],"
+ "\"edge_types\":["
+ "[],"
+ "\"string_or_number\","
+ "\"node\""
+ "]"
+ "}";
+
+ RefPtr<InspectorValue> metaValue = InspectorValue::parseJSON(metaString);
+ RefPtr<InspectorObject> meta;
+ metaValue->asObject(&meta);
+ ASSERT(meta);
+ meta->setObject("type_strings", m_typeStrings);
+ return meta.release();
+}
+
+void HeapGraphSerializer::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Inspector);
+ info.ignoreMember(m_stringToIndex);
+ info.ignoreMember(m_strings);
+ info.ignoreMember(m_edges);
+ info.ignoreMember(m_nodes);
+ info.ignoreMember(m_baseToRealNodeIdMap);
+ info.ignoreMember(m_roots);
+}
+
+int HeapGraphSerializer::registerString(const char* string)
+{
+ if (!string)
+ return 0;
+ int length = strlen(string);
+ if (length > 256)
+ length = 256;
+ StringMap::AddResult result = m_stringToIndex.add(String(string, length), m_stringToIndex.size() + 1);
+ if (result.isNewEntry)
+ m_strings->addItem(string);
+ return result.iterator->value;
+}
+
+int HeapGraphSerializer::registerTypeString(const char* string)
+{
+ int stringId = registerString(string);
+ m_typeStrings->setNumber(string, stringId);
+ return stringId;
+}
+
+int HeapGraphSerializer::toNodeId(const void* to)
+{
+ if (!to)
+ return s_firstNodeId + m_address2NodeIdMap.size() + m_leafCount++;
+
+ Address2NodeId::AddResult result = m_address2NodeIdMap.add(to, s_firstNodeId + m_leafCount + m_address2NodeIdMap.size());
+ return result.iterator->value;
+}
+
+void HeapGraphSerializer::addRootNode()
+{
+ for (size_t i = 0; i < m_roots.size(); i++)
+ reportEdgeImpl(toNodeId(m_roots[i]), 0, m_edgeTypes[WTF::PointerMember]);
+
+ m_nodes->addItem(registerString("Root"));
+ m_nodes->addItem(0);
+ m_nodes->addItem(s_firstNodeId + m_address2NodeIdMap.size() + m_leafCount);
+ m_nodes->addItem(0);
+ m_nodes->addItem(m_roots.size());
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/HeapGraphSerializer.h b/Source/core/inspector/HeapGraphSerializer.h
new file mode 100644
index 0000000..6669805
--- /dev/null
+++ b/Source/core/inspector/HeapGraphSerializer.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 HeapGraphSerializer_h
+#define HeapGraphSerializer_h
+
+
+#include "InspectorFrontend.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/MemoryInstrumentation.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class HeapGraphSerializer {
+ WTF_MAKE_NONCOPYABLE(HeapGraphSerializer);
+public:
+
+ class Client {
+ public:
+ virtual ~Client() { }
+ virtual void addNativeSnapshotChunk(PassRefPtr<TypeBuilder::Memory::HeapSnapshotChunk>) = 0;
+ };
+
+ explicit HeapGraphSerializer(Client*);
+ ~HeapGraphSerializer();
+ void reportNode(const WTF::MemoryObjectInfo&);
+ void reportEdge(const void*, const char*, WTF::MemberType);
+ void reportLeaf(const WTF::MemoryObjectInfo&, const char*);
+ void reportBaseAddress(const void*, const void*);
+ int registerString(const char*);
+
+ PassRefPtr<InspectorObject> finish();
+
+ void reportMemoryUsage(MemoryObjectInfo*) const;
+
+private:
+ void pushUpdateIfNeeded();
+ void pushUpdate();
+
+ int toNodeId(const void*);
+
+ void addRootNode();
+ int registerTypeString(const char*);
+
+ void reportEdgeImpl(const int toNodeId, const char* name, int memberType);
+ int reportNodeImpl(const WTF::MemoryObjectInfo&, int edgesCount);
+
+ Client* m_client;
+
+ typedef HashMap<String, int> StringMap;
+ StringMap m_stringToIndex;
+ typedef TypeBuilder::Array<String> Strings;
+ RefPtr<Strings> m_strings;
+
+ typedef TypeBuilder::Array<int> Edges;
+ RefPtr<Edges> m_edges;
+ int m_nodeEdgesCount;
+ static const size_t s_edgeFieldsCount = 3;
+
+ typedef TypeBuilder::Array<int> Nodes;
+ RefPtr<Nodes> m_nodes;
+ static const size_t s_nodeFieldsCount = 5;
+
+ typedef TypeBuilder::Array<int> BaseToRealNodeIdMap;
+ RefPtr<BaseToRealNodeIdMap> m_baseToRealNodeIdMap;
+ static const size_t s_idMapEntryFieldCount = 2;
+
+ typedef HashMap<const void*, int> Address2NodeId;
+ Address2NodeId m_address2NodeIdMap;
+
+ Vector<const void*> m_roots;
+ RefPtr<InspectorObject> m_typeStrings;
+
+ size_t m_edgeTypes[WTF::LastMemberTypeEntry];
+ int m_unknownClassNameId;
+ int m_leafCount;
+
+ static const int s_firstNodeId = 1;
+};
+
+} // namespace WebCore
+
+#endif // !defined(HeapGraphSerializer_h)
diff --git a/Source/core/inspector/IdentifiersFactory.cpp b/Source/core/inspector/IdentifiersFactory.cpp
new file mode 100644
index 0000000..f0c2b18
--- /dev/null
+++ b/Source/core/inspector/IdentifiersFactory.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 Google 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 COMPUTER, INC. ``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 COMPUTER, INC. OR
+ * 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 "core/inspector/IdentifiersFactory.h"
+
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+namespace {
+static long s_lastUsedIdentifier = 0;
+}
+
+// static
+long IdentifiersFactory::s_processId;
+
+// static
+String IdentifiersFactory::createIdentifier()
+{
+ return addProcessIdPrefixTo(String::number(++s_lastUsedIdentifier));
+}
+
+// static
+String IdentifiersFactory::requestId(unsigned long identifier)
+{
+ if (identifier)
+ return addProcessIdPrefixTo(String::number(identifier));
+ return String();
+}
+
+// static
+String IdentifiersFactory::addProcessIdPrefixTo(const String& id)
+{
+ StringBuilder builder;
+ builder.appendNumber(s_processId);
+ builder.append('.');
+ builder.append(id);
+ return builder.toString();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/IdentifiersFactory.h b/Source/core/inspector/IdentifiersFactory.h
new file mode 100644
index 0000000..6ec416c
--- /dev/null
+++ b/Source/core/inspector/IdentifiersFactory.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 Google 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 COMPUTER, INC. ``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 COMPUTER, INC. OR
+ * 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 IdentifiersFactory_h
+#define IdentifiersFactory_h
+
+#include <wtf/text/WTFString.h>
+
+
+namespace WebCore {
+
+class IdentifiersFactory {
+public:
+ static void setProcessId(long processId) { s_processId = processId; }
+ static String createIdentifier();
+ static String requestId(unsigned long identifier);
+private:
+ static String addProcessIdPrefixTo(const String& id);
+
+ static long s_processId;
+};
+
+} // namespace WebCore
+
+
+#endif // IdentifiersFactory_h
diff --git a/Source/core/inspector/InjectedScript.cpp b/Source/core/inspector/InjectedScript.cpp
new file mode 100644
index 0000000..9b993d8
--- /dev/null
+++ b/Source/core/inspector/InjectedScript.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InjectedScript.h"
+
+#include "bindings/v8/ScriptFunctionCall.h"
+#include "bindings/v8/SerializedScriptValue.h"
+#include "core/dom/Node.h"
+#include "core/inspector/InjectedScriptHost.h"
+#include "core/inspector/InjectedScriptModule.h"
+#include "core/inspector/InspectorValues.h"
+#include <wtf/text/WTFString.h>
+
+using WebCore::TypeBuilder::Array;
+using WebCore::TypeBuilder::Debugger::CallFrame;
+using WebCore::TypeBuilder::Runtime::PropertyDescriptor;
+using WebCore::TypeBuilder::Runtime::InternalPropertyDescriptor;
+using WebCore::TypeBuilder::Debugger::FunctionDetails;
+using WebCore::TypeBuilder::Runtime::RemoteObject;
+
+namespace WebCore {
+
+InjectedScript::InjectedScript()
+ : InjectedScriptBase("InjectedScript")
+{
+}
+
+InjectedScript::InjectedScript(ScriptObject injectedScriptObject, InspectedStateAccessCheck accessCheck)
+ : InjectedScriptBase("InjectedScript", injectedScriptObject, accessCheck)
+{
+}
+
+void InjectedScript::evaluate(ErrorString* errorString, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "evaluate");
+ function.appendArgument(expression);
+ function.appendArgument(objectGroup);
+ function.appendArgument(includeCommandLineAPI);
+ function.appendArgument(returnByValue);
+ function.appendArgument(generatePreview);
+ makeEvalCall(errorString, function, result, wasThrown);
+}
+
+void InjectedScript::callFunctionOn(ErrorString* errorString, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "callFunctionOn");
+ function.appendArgument(objectId);
+ function.appendArgument(expression);
+ function.appendArgument(arguments);
+ function.appendArgument(returnByValue);
+ function.appendArgument(generatePreview);
+ makeEvalCall(errorString, function, result, wasThrown);
+}
+
+void InjectedScript::evaluateOnCallFrame(ErrorString* errorString, const ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "evaluateOnCallFrame");
+ function.appendArgument(callFrames);
+ function.appendArgument(callFrameId);
+ function.appendArgument(expression);
+ function.appendArgument(objectGroup);
+ function.appendArgument(includeCommandLineAPI);
+ function.appendArgument(returnByValue);
+ function.appendArgument(generatePreview);
+ makeEvalCall(errorString, function, result, wasThrown);
+}
+
+void InjectedScript::restartFrame(ErrorString* errorString, const ScriptValue& callFrames, const String& callFrameId, RefPtr<InspectorObject>* result)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "restartFrame");
+ function.appendArgument(callFrames);
+ function.appendArgument(callFrameId);
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (resultValue) {
+ if (resultValue->type() == InspectorValue::TypeString) {
+ resultValue->asString(errorString);
+ return;
+ }
+ if (resultValue->type() == InspectorValue::TypeObject) {
+ *result = resultValue->asObject();
+ return;
+ }
+ }
+ *errorString = "Internal error";
+}
+
+void InjectedScript::setVariableValue(ErrorString* errorString, const ScriptValue& callFrames, const String* callFrameIdOpt, const String* functionObjectIdOpt, int scopeNumber, const String& variableName, const String& newValueStr)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "setVariableValue");
+ if (callFrameIdOpt) {
+ function.appendArgument(callFrames);
+ function.appendArgument(*callFrameIdOpt);
+ } else {
+ function.appendArgument(false);
+ function.appendArgument(false);
+ }
+ if (functionObjectIdOpt)
+ function.appendArgument(*functionObjectIdOpt);
+ else
+ function.appendArgument(false);
+ function.appendArgument(scopeNumber);
+ function.appendArgument(variableName);
+ function.appendArgument(newValueStr);
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (!resultValue) {
+ *errorString = "Internal error";
+ return;
+ }
+ if (resultValue->type() == InspectorValue::TypeString) {
+ resultValue->asString(errorString);
+ return;
+ }
+ // Normal return.
+}
+
+void InjectedScript::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<FunctionDetails>* result)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "getFunctionDetails");
+ function.appendArgument(functionId);
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (!resultValue || resultValue->type() != InspectorValue::TypeObject) {
+ if (!resultValue->asString(errorString))
+ *errorString = "Internal error";
+ return;
+ }
+ *result = FunctionDetails::runtimeCast(resultValue);
+}
+
+void InjectedScript::getProperties(ErrorString* errorString, const String& objectId, bool ownProperties, RefPtr<Array<PropertyDescriptor> >* properties)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "getProperties");
+ function.appendArgument(objectId);
+ function.appendArgument(ownProperties);
+
+ RefPtr<InspectorValue> result;
+ makeCall(function, &result);
+ if (!result || result->type() != InspectorValue::TypeArray) {
+ *errorString = "Internal error";
+ return;
+ }
+ *properties = Array<PropertyDescriptor>::runtimeCast(result);
+}
+
+void InjectedScript::getInternalProperties(ErrorString* errorString, const String& objectId, RefPtr<Array<InternalPropertyDescriptor> >* properties)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "getInternalProperties");
+ function.appendArgument(objectId);
+
+ RefPtr<InspectorValue> result;
+ makeCall(function, &result);
+ if (!result || result->type() != InspectorValue::TypeArray) {
+ *errorString = "Internal error";
+ return;
+ }
+ RefPtr<Array<InternalPropertyDescriptor> > array = Array<InternalPropertyDescriptor>::runtimeCast(result);
+ if (array->length() > 0)
+ *properties = array;
+}
+
+Node* InjectedScript::nodeForObjectId(const String& objectId)
+{
+ if (hasNoValue() || !canAccessInspectedWindow())
+ return 0;
+
+ ScriptFunctionCall function(injectedScriptObject(), "nodeForObjectId");
+ function.appendArgument(objectId);
+
+ bool hadException = false;
+ ScriptValue resultValue = callFunctionWithEvalEnabled(function, hadException);
+ ASSERT(!hadException);
+
+ return InjectedScriptHost::scriptValueAsNode(resultValue);
+}
+
+void InjectedScript::releaseObject(const String& objectId)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "releaseObject");
+ function.appendArgument(objectId);
+ RefPtr<InspectorValue> result;
+ makeCall(function, &result);
+}
+
+PassRefPtr<Array<CallFrame> > InjectedScript::wrapCallFrames(const ScriptValue& callFrames)
+{
+ ASSERT(!hasNoValue());
+ ScriptFunctionCall function(injectedScriptObject(), "wrapCallFrames");
+ function.appendArgument(callFrames);
+ bool hadException = false;
+ ScriptValue callFramesValue = callFunctionWithEvalEnabled(function, hadException);
+ ASSERT(!hadException);
+ RefPtr<InspectorValue> result = callFramesValue.toInspectorValue(scriptState());
+ if (result->type() == InspectorValue::TypeArray)
+ return Array<CallFrame>::runtimeCast(result);
+ return Array<CallFrame>::create();
+}
+
+PassRefPtr<TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapObject(const ScriptValue& value, const String& groupName, bool generatePreview) const
+{
+ ASSERT(!hasNoValue());
+ ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapObject");
+ wrapFunction.appendArgument(value);
+ wrapFunction.appendArgument(groupName);
+ wrapFunction.appendArgument(canAccessInspectedWindow());
+ wrapFunction.appendArgument(generatePreview);
+ bool hadException = false;
+ ScriptValue r = callFunctionWithEvalEnabled(wrapFunction, hadException);
+ if (hadException)
+ return 0;
+ RefPtr<InspectorObject> rawResult = r.toInspectorValue(scriptState())->asObject();
+ return TypeBuilder::Runtime::RemoteObject::runtimeCast(rawResult);
+}
+
+PassRefPtr<TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapTable(const ScriptValue& table, const ScriptValue& columns) const
+{
+ ASSERT(!hasNoValue());
+ ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapTable");
+ wrapFunction.appendArgument(canAccessInspectedWindow());
+ wrapFunction.appendArgument(table);
+ if (columns.hasNoValue())
+ wrapFunction.appendArgument(false);
+ else
+ wrapFunction.appendArgument(columns);
+ bool hadException = false;
+ ScriptValue r = callFunctionWithEvalEnabled(wrapFunction, hadException);
+ if (hadException)
+ return 0;
+ RefPtr<InspectorObject> rawResult = r.toInspectorValue(scriptState())->asObject();
+ return TypeBuilder::Runtime::RemoteObject::runtimeCast(rawResult);
+}
+
+PassRefPtr<TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapNode(Node* node, const String& groupName)
+{
+ return wrapObject(nodeAsScriptValue(node), groupName);
+}
+
+ScriptValue InjectedScript::findObjectById(const String& objectId) const
+{
+ ASSERT(!hasNoValue());
+ ScriptFunctionCall function(injectedScriptObject(), "findObjectById");
+ function.appendArgument(objectId);
+
+ bool hadException = false;
+ ScriptValue resultValue = callFunctionWithEvalEnabled(function, hadException);
+ ASSERT(!hadException);
+ return resultValue;
+}
+
+void InjectedScript::inspectNode(Node* node)
+{
+ ASSERT(!hasNoValue());
+ ScriptFunctionCall function(injectedScriptObject(), "inspectNode");
+ function.appendArgument(nodeAsScriptValue(node));
+ RefPtr<InspectorValue> result;
+ makeCall(function, &result);
+}
+
+void InjectedScript::releaseObjectGroup(const String& objectGroup)
+{
+ ASSERT(!hasNoValue());
+ ScriptFunctionCall releaseFunction(injectedScriptObject(), "releaseObjectGroup");
+ releaseFunction.appendArgument(objectGroup);
+ bool hadException = false;
+ callFunctionWithEvalEnabled(releaseFunction, hadException);
+ ASSERT(!hadException);
+}
+
+ScriptValue InjectedScript::nodeAsScriptValue(Node* node)
+{
+ return InjectedScriptHost::nodeAsScriptValue(scriptState(), node);
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InjectedScript.h b/Source/core/inspector/InjectedScript.h
new file mode 100644
index 0000000..e3bbcc8
--- /dev/null
+++ b/Source/core/inspector/InjectedScript.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InjectedScript_h
+#define InjectedScript_h
+
+#include "InspectorTypeBuilder.h"
+#include "bindings/v8/ScriptObject.h"
+#include "core/inspector/InjectedScriptBase.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/ScriptArguments.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class InjectedScriptModule;
+class Node;
+class SerializedScriptValue;
+
+
+class InjectedScript : public InjectedScriptBase {
+public:
+ InjectedScript();
+ ~InjectedScript() { }
+
+ void evaluate(ErrorString*,
+ const String& expression,
+ const String& objectGroup,
+ bool includeCommandLineAPI,
+ bool returnByValue,
+ bool generatePreview,
+ RefPtr<TypeBuilder::Runtime::RemoteObject>* result,
+ TypeBuilder::OptOutput<bool>* wasThrown);
+ void callFunctionOn(ErrorString*,
+ const String& objectId,
+ const String& expression,
+ const String& arguments,
+ bool returnByValue,
+ bool generatePreview,
+ RefPtr<TypeBuilder::Runtime::RemoteObject>* result,
+ TypeBuilder::OptOutput<bool>* wasThrown);
+ void evaluateOnCallFrame(ErrorString*,
+ const ScriptValue& callFrames,
+ const String& callFrameId,
+ const String& expression,
+ const String& objectGroup,
+ bool includeCommandLineAPI,
+ bool returnByValue,
+ bool generatePreview,
+ RefPtr<TypeBuilder::Runtime::RemoteObject>* result,
+ TypeBuilder::OptOutput<bool>* wasThrown);
+ void restartFrame(ErrorString*, const ScriptValue& callFrames, const String& callFrameId, RefPtr<InspectorObject>* result);
+ void setVariableValue(ErrorString*, const ScriptValue& callFrames, const String* callFrameIdOpt, const String* functionObjectIdOpt, int scopeNumber, const String& variableName, const String& newValueStr);
+ void getFunctionDetails(ErrorString*, const String& functionId, RefPtr<TypeBuilder::Debugger::FunctionDetails>* result);
+ void getProperties(ErrorString*, const String& objectId, bool ownProperties, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::PropertyDescriptor> >* result);
+ void getInternalProperties(ErrorString*, const String& objectId, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::InternalPropertyDescriptor> >* result);
+ Node* nodeForObjectId(const String& objectId);
+ void releaseObject(const String& objectId);
+
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame> > wrapCallFrames(const ScriptValue&);
+
+ PassRefPtr<TypeBuilder::Runtime::RemoteObject> wrapObject(const ScriptValue&, const String& groupName, bool generatePreview = false) const;
+ PassRefPtr<TypeBuilder::Runtime::RemoteObject> wrapTable(const ScriptValue& table, const ScriptValue& columns) const;
+ PassRefPtr<TypeBuilder::Runtime::RemoteObject> wrapNode(Node*, const String& groupName);
+ ScriptValue findObjectById(const String& objectId) const;
+
+ void inspectNode(Node*);
+ void releaseObjectGroup(const String&);
+
+private:
+ friend class InjectedScriptModule;
+ friend InjectedScript InjectedScriptManager::injectedScriptFor(ScriptState*);
+ InjectedScript(ScriptObject, InspectedStateAccessCheck);
+
+ ScriptValue nodeAsScriptValue(Node*);
+};
+
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/inspector/InjectedScriptBase.cpp b/Source/core/inspector/InjectedScriptBase.cpp
new file mode 100644
index 0000000..6da87cb
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptBase.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InjectedScriptBase.h"
+
+#include "bindings/v8/ScriptFunctionCall.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/InspectorValues.h"
+#include <wtf/text/WTFString.h>
+
+using WebCore::TypeBuilder::Runtime::RemoteObject;
+
+namespace WebCore {
+
+InjectedScriptBase::InjectedScriptBase(const String& name)
+ : m_name(name)
+ , m_inspectedStateAccessCheck(0)
+{
+}
+
+InjectedScriptBase::InjectedScriptBase(const String& name, ScriptObject injectedScriptObject, InspectedStateAccessCheck accessCheck)
+ : m_name(name)
+ , m_injectedScriptObject(injectedScriptObject)
+ , m_inspectedStateAccessCheck(accessCheck)
+{
+}
+
+void InjectedScriptBase::initialize(ScriptObject injectedScriptObject, InspectedStateAccessCheck accessCheck)
+{
+ m_injectedScriptObject = injectedScriptObject;
+ m_inspectedStateAccessCheck = accessCheck;
+}
+
+bool InjectedScriptBase::canAccessInspectedWindow() const
+{
+ return m_inspectedStateAccessCheck(m_injectedScriptObject.scriptState());
+}
+
+const ScriptObject& InjectedScriptBase::injectedScriptObject() const
+{
+ return m_injectedScriptObject;
+}
+
+ScriptValue InjectedScriptBase::callFunctionWithEvalEnabled(ScriptFunctionCall& function, bool& hadException) const
+{
+ ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromScriptState(m_injectedScriptObject.scriptState());
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willCallFunction(scriptExecutionContext, name(), 1);
+
+ ScriptState* scriptState = m_injectedScriptObject.scriptState();
+ bool evalIsDisabled = false;
+ if (scriptState) {
+ evalIsDisabled = !evalEnabled(scriptState);
+ // Temporarily enable allow evals for inspector.
+ if (evalIsDisabled)
+ setEvalEnabled(scriptState, true);
+ }
+
+ ScriptValue resultValue = function.call(hadException);
+
+ if (evalIsDisabled)
+ setEvalEnabled(scriptState, false);
+
+ InspectorInstrumentation::didCallFunction(cookie);
+ return resultValue;
+}
+
+void InjectedScriptBase::makeCall(ScriptFunctionCall& function, RefPtr<InspectorValue>* result)
+{
+ if (hasNoValue() || !canAccessInspectedWindow()) {
+ *result = InspectorValue::null();
+ return;
+ }
+
+ bool hadException = false;
+ ScriptValue resultValue = callFunctionWithEvalEnabled(function, hadException);
+
+ ASSERT(!hadException);
+ if (!hadException) {
+ *result = resultValue.toInspectorValue(m_injectedScriptObject.scriptState());
+ if (!*result)
+ *result = InspectorString::create(String::format("Object has too long reference chain(must not be longer than %d)", InspectorValue::maxDepth));
+ } else
+ *result = InspectorString::create("Exception while making a call.");
+}
+
+void InjectedScriptBase::makeEvalCall(ErrorString* errorString, ScriptFunctionCall& function, RefPtr<TypeBuilder::Runtime::RemoteObject>* objectResult, TypeBuilder::OptOutput<bool>* wasThrown)
+{
+ RefPtr<InspectorValue> result;
+ makeCall(function, &result);
+ if (!result) {
+ *errorString = "Internal error: result value is empty";
+ return;
+ }
+ if (result->type() == InspectorValue::TypeString) {
+ result->asString(errorString);
+ ASSERT(errorString->length());
+ return;
+ }
+ RefPtr<InspectorObject> resultPair = result->asObject();
+ if (!resultPair) {
+ *errorString = "Internal error: result is not an Object";
+ return;
+ }
+ RefPtr<InspectorObject> resultObj = resultPair->getObject("result");
+ bool wasThrownVal = false;
+ if (!resultObj || !resultPair->getBoolean("wasThrown", &wasThrownVal)) {
+ *errorString = "Internal error: result is not a pair of value and wasThrown flag";
+ return;
+ }
+ *objectResult = TypeBuilder::Runtime::RemoteObject::runtimeCast(resultObj);
+ *wasThrown = wasThrownVal;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InjectedScriptBase.h b/Source/core/inspector/InjectedScriptBase.h
new file mode 100644
index 0000000..17b8ca3
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptBase.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InjectedScriptBase_h
+#define InjectedScriptBase_h
+
+#include "InspectorTypeBuilder.h"
+#include "bindings/v8/ScriptObject.h"
+#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class InspectorValue;
+class ScriptFunctionCall;
+
+typedef String ErrorString;
+
+
+class InjectedScriptBase {
+public:
+ virtual ~InjectedScriptBase() { }
+
+ const String& name() const { return m_name; }
+ bool hasNoValue() const { return m_injectedScriptObject.hasNoValue(); }
+ ScriptState* scriptState() const { return m_injectedScriptObject.scriptState(); }
+
+protected:
+ typedef bool (*InspectedStateAccessCheck)(ScriptState*);
+ InjectedScriptBase(const String& name);
+ InjectedScriptBase(const String& name, ScriptObject, InspectedStateAccessCheck);
+
+ void initialize(ScriptObject, InspectedStateAccessCheck);
+ bool canAccessInspectedWindow() const;
+ const ScriptObject& injectedScriptObject() const;
+ ScriptValue callFunctionWithEvalEnabled(ScriptFunctionCall&, bool& hadException) const;
+ void makeCall(ScriptFunctionCall&, RefPtr<InspectorValue>* result);
+ void makeEvalCall(ErrorString*, ScriptFunctionCall&, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown);
+
+private:
+ String m_name;
+ ScriptObject m_injectedScriptObject;
+ InspectedStateAccessCheck m_inspectedStateAccessCheck;
+};
+
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/inspector/InjectedScriptCanvasModule.cpp b/Source/core/inspector/InjectedScriptCanvasModule.cpp
new file mode 100644
index 0000000..825f0aa
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptCanvasModule.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InjectedScriptCanvasModule.h"
+
+#include "InjectedScriptCanvasModuleSource.h"
+#include "bindings/v8/ScriptFunctionCall.h"
+#include "bindings/v8/ScriptObject.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptManager.h"
+
+using WebCore::TypeBuilder::Array;
+using WebCore::TypeBuilder::Canvas::ResourceId;
+using WebCore::TypeBuilder::Canvas::ResourceInfo;
+using WebCore::TypeBuilder::Canvas::ResourceState;
+using WebCore::TypeBuilder::Canvas::TraceLog;
+using WebCore::TypeBuilder::Canvas::TraceLogId;
+
+namespace WebCore {
+
+InjectedScriptCanvasModule::InjectedScriptCanvasModule()
+ : InjectedScriptModule("InjectedScriptCanvasModule")
+{
+}
+
+InjectedScriptCanvasModule InjectedScriptCanvasModule::moduleForState(InjectedScriptManager* injectedScriptManager, ScriptState* scriptState)
+{
+ InjectedScriptCanvasModule result;
+ result.ensureInjected(injectedScriptManager, scriptState);
+ return result;
+}
+
+String InjectedScriptCanvasModule::source() const
+{
+ return String(reinterpret_cast<const char*>(InjectedScriptCanvasModuleSource_js), sizeof(InjectedScriptCanvasModuleSource_js));
+}
+
+ScriptObject InjectedScriptCanvasModule::wrapCanvas2DContext(const ScriptObject& context)
+{
+ return callWrapContextFunction("wrapCanvas2DContext", context);
+}
+
+ScriptObject InjectedScriptCanvasModule::wrapWebGLContext(const ScriptObject& glContext)
+{
+ return callWrapContextFunction("wrapWebGLContext", glContext);
+}
+
+ScriptObject InjectedScriptCanvasModule::callWrapContextFunction(const String& functionName, const ScriptObject& context)
+{
+ ScriptFunctionCall function(injectedScriptObject(), functionName);
+ function.appendArgument(context);
+ bool hadException = false;
+ ScriptValue resultValue = callFunctionWithEvalEnabled(function, hadException);
+ if (hadException || resultValue.hasNoValue() || !resultValue.isObject()) {
+ ASSERT_NOT_REACHED();
+ return ScriptObject();
+ }
+ return ScriptObject(context.scriptState(), resultValue);
+}
+
+void InjectedScriptCanvasModule::markFrameEnd()
+{
+ ScriptFunctionCall function(injectedScriptObject(), "markFrameEnd");
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ ASSERT(resultValue);
+}
+
+void InjectedScriptCanvasModule::captureFrame(ErrorString* errorString, TraceLogId* traceLogId)
+{
+ callStartCapturingFunction("captureFrame", errorString, traceLogId);
+}
+
+void InjectedScriptCanvasModule::startCapturing(ErrorString* errorString, TraceLogId* traceLogId)
+{
+ callStartCapturingFunction("startCapturing", errorString, traceLogId);
+}
+
+void InjectedScriptCanvasModule::callStartCapturingFunction(const String& functionName, ErrorString* errorString, TraceLogId* traceLogId)
+{
+ ScriptFunctionCall function(injectedScriptObject(), functionName);
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (!resultValue || resultValue->type() != InspectorValue::TypeString || !resultValue->asString(traceLogId))
+ *errorString = "Internal error: " + functionName;
+}
+
+void InjectedScriptCanvasModule::stopCapturing(ErrorString* errorString, const TraceLogId& traceLogId)
+{
+ callVoidFunctionWithTraceLogIdArgument("stopCapturing", errorString, traceLogId);
+}
+
+void InjectedScriptCanvasModule::dropTraceLog(ErrorString* errorString, const TraceLogId& traceLogId)
+{
+ callVoidFunctionWithTraceLogIdArgument("dropTraceLog", errorString, traceLogId);
+}
+
+void InjectedScriptCanvasModule::callVoidFunctionWithTraceLogIdArgument(const String& functionName, ErrorString* errorString, const TraceLogId& traceLogId)
+{
+ ScriptFunctionCall function(injectedScriptObject(), functionName);
+ function.appendArgument(traceLogId);
+ bool hadException = false;
+ callFunctionWithEvalEnabled(function, hadException);
+ ASSERT(!hadException);
+ if (hadException)
+ *errorString = "Internal error: " + functionName;
+}
+
+void InjectedScriptCanvasModule::traceLog(ErrorString* errorString, const TraceLogId& traceLogId, const int* startOffset, const int* maxLength, RefPtr<TraceLog>* traceLog)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "traceLog");
+ function.appendArgument(traceLogId);
+ if (startOffset)
+ function.appendArgument(*startOffset);
+ if (maxLength)
+ function.appendArgument(*maxLength);
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (!resultValue || resultValue->type() != InspectorValue::TypeObject) {
+ if (!resultValue->asString(errorString))
+ *errorString = "Internal error: traceLog";
+ return;
+ }
+ *traceLog = TraceLog::runtimeCast(resultValue);
+}
+
+void InjectedScriptCanvasModule::replayTraceLog(ErrorString* errorString, const TraceLogId& traceLogId, int stepNo, RefPtr<ResourceState>* result)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "replayTraceLog");
+ function.appendArgument(traceLogId);
+ function.appendArgument(stepNo);
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (!resultValue || resultValue->type() != InspectorValue::TypeObject) {
+ if (!resultValue->asString(errorString))
+ *errorString = "Internal error: replayTraceLog";
+ return;
+ }
+ *result = ResourceState::runtimeCast(resultValue);
+}
+
+void InjectedScriptCanvasModule::resourceInfo(ErrorString* errorString, const ResourceId& resourceId, RefPtr<ResourceInfo>* result)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "resourceInfo");
+ function.appendArgument(resourceId);
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (!resultValue || resultValue->type() != InspectorValue::TypeObject) {
+ if (!resultValue->asString(errorString))
+ *errorString = "Internal error: resourceInfo";
+ return;
+ }
+ *result = ResourceInfo::runtimeCast(resultValue);
+}
+
+void InjectedScriptCanvasModule::resourceState(ErrorString* errorString, const TraceLogId& traceLogId, const ResourceId& resourceId, RefPtr<ResourceState>* result)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "resourceState");
+ function.appendArgument(traceLogId);
+ function.appendArgument(resourceId);
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (!resultValue || resultValue->type() != InspectorValue::TypeObject) {
+ if (!resultValue->asString(errorString))
+ *errorString = "Internal error: resourceState";
+ return;
+ }
+ *result = ResourceState::runtimeCast(resultValue);
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InjectedScriptCanvasModule.h b/Source/core/inspector/InjectedScriptCanvasModule.h
new file mode 100644
index 0000000..8999373
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptCanvasModule.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InjectedScriptCanvasModule_h
+#define InjectedScriptCanvasModule_h
+
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/InjectedScriptModule.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InjectedScriptManager;
+class ScriptObject;
+
+
+class InjectedScriptCanvasModule : public InjectedScriptModule {
+public:
+ InjectedScriptCanvasModule();
+
+ virtual String source() const;
+
+ static InjectedScriptCanvasModule moduleForState(InjectedScriptManager*, ScriptState*);
+
+ ScriptObject wrapCanvas2DContext(const ScriptObject&);
+ ScriptObject wrapWebGLContext(const ScriptObject&);
+ void markFrameEnd();
+
+ void captureFrame(ErrorString*, TypeBuilder::Canvas::TraceLogId*);
+ void startCapturing(ErrorString*, TypeBuilder::Canvas::TraceLogId*);
+ void stopCapturing(ErrorString*, const TypeBuilder::Canvas::TraceLogId&);
+ void dropTraceLog(ErrorString*, const TypeBuilder::Canvas::TraceLogId&);
+ void traceLog(ErrorString*, const String&, const int*, const int*, RefPtr<TypeBuilder::Canvas::TraceLog>*);
+ void replayTraceLog(ErrorString*, const TypeBuilder::Canvas::TraceLogId&, int, RefPtr<TypeBuilder::Canvas::ResourceState>*);
+ void resourceInfo(ErrorString*, const TypeBuilder::Canvas::ResourceId&, RefPtr<TypeBuilder::Canvas::ResourceInfo>*);
+ void resourceState(ErrorString*, const TypeBuilder::Canvas::TraceLogId&, const TypeBuilder::Canvas::ResourceId&, RefPtr<TypeBuilder::Canvas::ResourceState>*);
+
+private:
+ ScriptObject callWrapContextFunction(const String&, const ScriptObject&);
+ void callStartCapturingFunction(const String&, ErrorString*, String*);
+ void callVoidFunctionWithTraceLogIdArgument(const String&, ErrorString*, const String&);
+};
+
+
+} // namespace WebCore
+
+#endif // !defined(InjectedScriptCanvasModule_h)
diff --git a/Source/core/inspector/InjectedScriptCanvasModuleSource.js b/Source/core/inspector/InjectedScriptCanvasModuleSource.js
new file mode 100644
index 0000000..115ad75
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptCanvasModuleSource.js
@@ -0,0 +1,3273 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+/**
+ * @param {InjectedScriptHost} InjectedScriptHost
+ * @param {Window} inspectedWindow
+ * @param {number} injectedScriptId
+ */
+(function (InjectedScriptHost, inspectedWindow, injectedScriptId) {
+
+var TypeUtils = {
+ /**
+ * http://www.khronos.org/registry/typedarray/specs/latest/#7
+ * @const
+ * @type {!Array.<function(new:ArrayBufferView, ArrayBufferView)>}
+ */
+ _typedArrayClasses: (function(typeNames) {
+ var result = [];
+ for (var i = 0, n = typeNames.length; i < n; ++i) {
+ if (inspectedWindow[typeNames[i]])
+ result.push(inspectedWindow[typeNames[i]]);
+ }
+ return result;
+ })(["Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array"]),
+
+ /**
+ * @const
+ * @type {!Array.<string>}
+ */
+ _supportedPropertyPrefixes: ["webkit"],
+
+ /**
+ * @param {*} array
+ * @return {function(new:ArrayBufferView, ArrayBufferView)|null}
+ */
+ typedArrayClass: function(array)
+ {
+ var classes = TypeUtils._typedArrayClasses;
+ for (var i = 0, n = classes.length; i < n; ++i) {
+ if (array instanceof classes[i])
+ return classes[i];
+ }
+ return null;
+ },
+
+ /**
+ * @param {*} obj
+ * @return {*}
+ */
+ clone: function(obj)
+ {
+ if (!obj)
+ return obj;
+
+ var type = typeof obj;
+ if (type !== "object" && type !== "function")
+ return obj;
+
+ // Handle Array and ArrayBuffer instances.
+ if (typeof obj.slice === "function") {
+ console.assert(obj instanceof Array || obj instanceof ArrayBuffer);
+ return obj.slice(0);
+ }
+
+ var typedArrayClass = TypeUtils.typedArrayClass(obj);
+ if (typedArrayClass)
+ return new typedArrayClass(/** @type {ArrayBufferView} */ (obj));
+
+ if (obj instanceof HTMLImageElement) {
+ var img = /** @type {HTMLImageElement} */ (obj);
+ // Special case for Images with Blob URIs: cloneNode will fail if the Blob URI has already been revoked.
+ // FIXME: Maybe this is a bug in WebKit core?
+ if (/^blob:/.test(img.src))
+ return TypeUtils.cloneIntoCanvas(img);
+ return img.cloneNode(true);
+ }
+
+ if (obj instanceof HTMLCanvasElement)
+ return TypeUtils.cloneIntoCanvas(obj);
+
+ if (obj instanceof HTMLVideoElement)
+ return TypeUtils.cloneIntoCanvas(obj, obj.videoWidth, obj.videoHeight);
+
+ if (obj instanceof ImageData) {
+ var context = TypeUtils._dummyCanvas2dContext();
+ // FIXME: suppress type checks due to outdated builtin externs for createImageData.
+ var result = (/** @type {?} */ (context)).createImageData(obj);
+ for (var i = 0, n = obj.data.length; i < n; ++i)
+ result.data[i] = obj.data[i];
+ return result;
+ }
+
+ console.error("ASSERT_NOT_REACHED: failed to clone object: ", obj);
+ return obj;
+ },
+
+ /**
+ * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} obj
+ * @param {number=} width
+ * @param {number=} height
+ * @return {HTMLCanvasElement}
+ */
+ cloneIntoCanvas: function(obj, width, height)
+ {
+ var canvas = /** @type {HTMLCanvasElement} */ (inspectedWindow.document.createElement("canvas"));
+ canvas.width = width || +obj.width;
+ canvas.height = height || +obj.height;
+ var context = /** @type {CanvasRenderingContext2D} */ (Resource.wrappedObject(canvas.getContext("2d")));
+ context.drawImage(obj, 0, 0);
+ return canvas;
+ },
+
+ /**
+ * @param {Object=} obj
+ * @return {Object}
+ */
+ cloneObject: function(obj)
+ {
+ if (!obj)
+ return null;
+ var result = {};
+ for (var key in obj)
+ result[key] = obj[key];
+ return result;
+ },
+
+ /**
+ * @param {!Array.<string>} names
+ * @return {!Object.<string, boolean>}
+ */
+ createPrefixedPropertyNamesSet: function(names)
+ {
+ var result = Object.create(null);
+ for (var i = 0, name; name = names[i]; ++i) {
+ result[name] = true;
+ var suffix = name.substr(0, 1).toUpperCase() + name.substr(1);
+ for (var j = 0, prefix; prefix = TypeUtils._supportedPropertyPrefixes[j]; ++j)
+ result[prefix + suffix] = true;
+ }
+ return result;
+ },
+
+ /**
+ * @return {CanvasRenderingContext2D}
+ */
+ _dummyCanvas2dContext: function()
+ {
+ var context = TypeUtils._dummyCanvas2dContextInstance;
+ if (!context) {
+ var canvas = /** @type {HTMLCanvasElement} */ (inspectedWindow.document.createElement("canvas"));
+ context = /** @type {CanvasRenderingContext2D} */ (Resource.wrappedObject(canvas.getContext("2d")));
+ TypeUtils._dummyCanvas2dContextInstance = context;
+ }
+ return context;
+ }
+}
+
+/**
+ * @interface
+ */
+function StackTrace()
+{
+}
+
+StackTrace.prototype = {
+ /**
+ * @param {number} index
+ * @return {{sourceURL: string, lineNumber: number, columnNumber: number}|undefined}
+ */
+ callFrame: function(index)
+ {
+ }
+}
+
+/**
+ * @param {number=} stackTraceLimit
+ * @param {Function=} topMostFunctionToIgnore
+ * @return {StackTrace}
+ */
+StackTrace.create = function(stackTraceLimit, topMostFunctionToIgnore)
+{
+ if (typeof Error.captureStackTrace === "function")
+ return new StackTraceV8(stackTraceLimit, topMostFunctionToIgnore || arguments.callee);
+ // FIXME: Support JSC, and maybe other browsers.
+ return null;
+}
+
+/**
+ * @constructor
+ * @implements {StackTrace}
+ * @param {number=} stackTraceLimit
+ * @param {Function=} topMostFunctionToIgnore
+ * @see http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
+ */
+function StackTraceV8(stackTraceLimit, topMostFunctionToIgnore)
+{
+ StackTrace.call(this);
+
+ var oldPrepareStackTrace = Error.prepareStackTrace;
+ var oldStackTraceLimit = Error.stackTraceLimit;
+ if (typeof stackTraceLimit === "number")
+ Error.stackTraceLimit = stackTraceLimit;
+
+ /**
+ * @param {Object} error
+ * @param {Array.<CallSite>} structuredStackTrace
+ * @return {Array.<{sourceURL: string, lineNumber: number, columnNumber: number}>}
+ */
+ Error.prepareStackTrace = function(error, structuredStackTrace)
+ {
+ return structuredStackTrace.map(function(callSite) {
+ return {
+ sourceURL: callSite.getFileName(),
+ lineNumber: callSite.getLineNumber(),
+ columnNumber: callSite.getColumnNumber()
+ };
+ });
+ }
+
+ var holder = /** @type {{stack: Array.<{sourceURL: string, lineNumber: number, columnNumber: number}>}} */ ({});
+ Error.captureStackTrace(holder, topMostFunctionToIgnore || arguments.callee);
+ this._stackTrace = holder.stack;
+
+ Error.stackTraceLimit = oldStackTraceLimit;
+ Error.prepareStackTrace = oldPrepareStackTrace;
+}
+
+StackTraceV8.prototype = {
+ /**
+ * @override
+ * @param {number} index
+ * @return {{sourceURL: string, lineNumber: number, columnNumber: number}|undefined}
+ */
+ callFrame: function(index)
+ {
+ return this._stackTrace[index];
+ },
+
+ __proto__: StackTrace.prototype
+}
+
+/**
+ * @constructor
+ */
+function Cache()
+{
+ this.reset();
+}
+
+Cache.prototype = {
+ /**
+ * @return {number}
+ */
+ size: function()
+ {
+ return this._size;
+ },
+
+ reset: function()
+ {
+ /** @type {!Object.<number, Object>} */
+ this._items = Object.create(null);
+ /** @type {number} */
+ this._size = 0;
+ },
+
+ /**
+ * @param {number} key
+ * @return {boolean}
+ */
+ has: function(key)
+ {
+ return key in this._items;
+ },
+
+ /**
+ * @param {number} key
+ * @return {Object}
+ */
+ get: function(key)
+ {
+ return this._items[key];
+ },
+
+ /**
+ * @param {number} key
+ * @param {Object} item
+ */
+ put: function(key, item)
+ {
+ if (!this.has(key))
+ ++this._size;
+ this._items[key] = item;
+ }
+}
+
+/**
+ * @constructor
+ * @param {Resource|Object} thisObject
+ * @param {string} functionName
+ * @param {Array|Arguments} args
+ * @param {Resource|*=} result
+ * @param {StackTrace=} stackTrace
+ */
+function Call(thisObject, functionName, args, result, stackTrace)
+{
+ this._thisObject = thisObject;
+ this._functionName = functionName;
+ this._args = Array.prototype.slice.call(args, 0);
+ this._result = result;
+ this._stackTrace = stackTrace || null;
+
+ if (!this._functionName)
+ console.assert(this._args.length === 2 && typeof this._args[0] === "string");
+}
+
+Call.prototype = {
+ /**
+ * @return {Resource}
+ */
+ resource: function()
+ {
+ return Resource.forObject(this._thisObject);
+ },
+
+ /**
+ * @return {string}
+ */
+ functionName: function()
+ {
+ return this._functionName;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isPropertySetter: function()
+ {
+ return !this._functionName;
+ },
+
+ /**
+ * @return {!Array}
+ */
+ args: function()
+ {
+ return this._args;
+ },
+
+ /**
+ * @return {*}
+ */
+ result: function()
+ {
+ return this._result;
+ },
+
+ /**
+ * @return {StackTrace}
+ */
+ stackTrace: function()
+ {
+ return this._stackTrace;
+ },
+
+ /**
+ * @param {StackTrace} stackTrace
+ */
+ setStackTrace: function(stackTrace)
+ {
+ this._stackTrace = stackTrace;
+ },
+
+ /**
+ * @param {*} result
+ */
+ setResult: function(result)
+ {
+ this._result = result;
+ },
+
+ /**
+ * @param {string} name
+ * @param {Object} attachment
+ */
+ setAttachment: function(name, attachment)
+ {
+ if (attachment) {
+ /** @type {Object.<string, Object>} */
+ this._attachments = this._attachments || Object.create(null);
+ this._attachments[name] = attachment;
+ } else if (this._attachments)
+ delete this._attachments[name];
+ },
+
+ /**
+ * @param {string} name
+ * @return {Object}
+ */
+ attachment: function(name)
+ {
+ return this._attachments && this._attachments[name];
+ },
+
+ freeze: function()
+ {
+ if (this._freezed)
+ return;
+ this._freezed = true;
+ for (var i = 0, n = this._args.length; i < n; ++i) {
+ // FIXME: freeze the Resources also!
+ if (!Resource.forObject(this._args[i]))
+ this._args[i] = TypeUtils.clone(this._args[i]);
+ }
+ },
+
+ /**
+ * @param {!Cache} cache
+ * @return {!ReplayableCall}
+ */
+ toReplayable: function(cache)
+ {
+ this.freeze();
+ var thisObject = /** @type {ReplayableResource} */ (Resource.toReplayable(this._thisObject, cache));
+ var result = Resource.toReplayable(this._result, cache);
+ var args = this._args.map(function(obj) {
+ return Resource.toReplayable(obj, cache);
+ });
+ var attachments = TypeUtils.cloneObject(this._attachments);
+ return new ReplayableCall(thisObject, this._functionName, args, result, this._stackTrace, attachments);
+ },
+
+ /**
+ * @param {!ReplayableCall} replayableCall
+ * @param {!Cache} cache
+ * @return {!Call}
+ */
+ replay: function(replayableCall, cache)
+ {
+ var replayObject = ReplayableResource.replay(replayableCall.replayableResource(), cache);
+ var replayArgs = replayableCall.args().map(function(obj) {
+ return ReplayableResource.replay(obj, cache);
+ });
+ var replayResult = undefined;
+
+ if (replayableCall.isPropertySetter())
+ replayObject[replayArgs[0]] = replayArgs[1];
+ else {
+ var replayFunction = replayObject[replayableCall.functionName()];
+ console.assert(typeof replayFunction === "function", "Expected a function to replay");
+ replayResult = replayFunction.apply(replayObject, replayArgs);
+ if (replayableCall.result() instanceof ReplayableResource) {
+ var resource = replayableCall.result().replay(cache);
+ if (!resource.wrappedObject())
+ resource.setWrappedObject(replayResult);
+ }
+ }
+
+ this._thisObject = replayObject;
+ this._functionName = replayableCall.functionName();
+ this._args = replayArgs;
+ this._result = replayResult;
+ this._stackTrace = replayableCall.stackTrace();
+ this._freezed = true;
+ var attachments = replayableCall.attachments();
+ if (attachments)
+ this._attachments = TypeUtils.cloneObject(attachments);
+ return this;
+ }
+}
+
+/**
+ * @constructor
+ * @param {ReplayableResource} thisObject
+ * @param {string} functionName
+ * @param {Array.<ReplayableResource|*>} args
+ * @param {ReplayableResource|*} result
+ * @param {StackTrace} stackTrace
+ * @param {Object.<string, Object>} attachments
+ */
+function ReplayableCall(thisObject, functionName, args, result, stackTrace, attachments)
+{
+ this._thisObject = thisObject;
+ this._functionName = functionName;
+ this._args = args;
+ this._result = result;
+ this._stackTrace = stackTrace;
+ if (attachments)
+ this._attachments = attachments;
+}
+
+ReplayableCall.prototype = {
+ /**
+ * @return {ReplayableResource}
+ */
+ replayableResource: function()
+ {
+ return this._thisObject;
+ },
+
+ /**
+ * @return {string}
+ */
+ functionName: function()
+ {
+ return this._functionName;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isPropertySetter: function()
+ {
+ return !this._functionName;
+ },
+
+ /**
+ * @return {Array.<ReplayableResource|*>}
+ */
+ args: function()
+ {
+ return this._args;
+ },
+
+ /**
+ * @return {ReplayableResource|*}
+ */
+ result: function()
+ {
+ return this._result;
+ },
+
+ /**
+ * @return {StackTrace}
+ */
+ stackTrace: function()
+ {
+ return this._stackTrace;
+ },
+
+ /**
+ * @return {Object.<string, Object>}
+ */
+ attachments: function()
+ {
+ return this._attachments;
+ },
+
+ /**
+ * @param {string} name
+ * @return {Object}
+ */
+ attachment: function(name)
+ {
+ return this._attachments && this._attachments[name];
+ },
+
+ /**
+ * @param {Cache} cache
+ * @return {!Call}
+ */
+ replay: function(cache)
+ {
+ var call = /** @type {!Call} */ (Object.create(Call.prototype));
+ return call.replay(this, cache);
+ }
+}
+
+/**
+ * @constructor
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function Resource(wrappedObject, name)
+{
+ /** @type {number} */
+ this._id = ++Resource._uniqueId;
+ /** @type {string} */
+ this._name = name || "Resource";
+ /** @type {number} */
+ this._kindId = Resource._uniqueKindIds[this._name] = (Resource._uniqueKindIds[this._name] || 0) + 1;
+ /** @type {ResourceTrackingManager} */
+ this._resourceManager = null;
+ /** @type {!Array.<Call>} */
+ this._calls = [];
+ /**
+ * This is to prevent GC from collecting associated resources.
+ * Otherwise, for example in WebGL, subsequent calls to gl.getParameter()
+ * may return a recently created instance that is no longer bound to a
+ * Resource object (thus, no history to replay it later).
+ *
+ * @type {!Object.<string, Resource>}
+ */
+ this._boundResources = Object.create(null);
+ this.setWrappedObject(wrappedObject);
+}
+
+/**
+ * @type {number}
+ */
+Resource._uniqueId = 0;
+
+/**
+ * @type {!Object.<string, number>}
+ */
+Resource._uniqueKindIds = {};
+
+/**
+ * @param {*} obj
+ * @return {Resource}
+ */
+Resource.forObject = function(obj)
+{
+ if (!obj)
+ return null;
+ if (obj instanceof Resource)
+ return obj;
+ if (typeof obj === "object")
+ return obj["__resourceObject"];
+ return null;
+}
+
+/**
+ * @param {Resource|*} obj
+ * @return {*}
+ */
+Resource.wrappedObject = function(obj)
+{
+ var resource = Resource.forObject(obj);
+ return resource ? resource.wrappedObject() : obj;
+}
+
+/**
+ * @param {Resource|*} obj
+ * @param {!Cache} cache
+ * @return {ReplayableResource|*}
+ */
+Resource.toReplayable = function(obj, cache)
+{
+ var resource = Resource.forObject(obj);
+ return resource ? resource.toReplayable(cache) : obj;
+}
+
+Resource.prototype = {
+ /**
+ * @return {number}
+ */
+ id: function()
+ {
+ return this._id;
+ },
+
+ /**
+ * @return {Object}
+ */
+ wrappedObject: function()
+ {
+ return this._wrappedObject;
+ },
+
+ /**
+ * @param {!Object} value
+ */
+ setWrappedObject: function(value)
+ {
+ console.assert(value, "wrappedObject should not be NULL");
+ console.assert(!(value instanceof Resource), "Binding a Resource object to another Resource object?");
+ this._wrappedObject = value;
+ this._bindObjectToResource(value);
+ },
+
+ /**
+ * @return {Object}
+ */
+ proxyObject: function()
+ {
+ if (!this._proxyObject)
+ this._proxyObject = this._wrapObject();
+ return this._proxyObject;
+ },
+
+ /**
+ * @return {ResourceTrackingManager}
+ */
+ manager: function()
+ {
+ return this._resourceManager;
+ },
+
+ /**
+ * @param {ResourceTrackingManager} value
+ */
+ setManager: function(value)
+ {
+ this._resourceManager = value;
+ },
+
+ /**
+ * @return {!Array.<Call>}
+ */
+ calls: function()
+ {
+ return this._calls;
+ },
+
+ /**
+ * @return {ContextResource}
+ */
+ contextResource: function()
+ {
+ if (this instanceof ContextResource)
+ return /** @type {ContextResource} */ (this);
+
+ if (this._calculatingContextResource)
+ return null;
+
+ this._calculatingContextResource = true;
+ var result = null;
+ for (var i = 0, n = this._calls.length; i < n; ++i) {
+ result = this._calls[i].resource().contextResource();
+ if (result)
+ break;
+ }
+ delete this._calculatingContextResource;
+ console.assert(result, "Failed to find context resource for " + this._name + "@" + this._kindId);
+ return result;
+ },
+
+ /**
+ * @return {string}
+ */
+ toDataURL: function()
+ {
+ return "";
+ },
+
+ /**
+ * @param {!Cache} cache
+ * @return {!ReplayableResource}
+ */
+ toReplayable: function(cache)
+ {
+ var result = /** @type {ReplayableResource} */ (cache.get(this._id));
+ if (result)
+ return result;
+ var data = {
+ id: this._id,
+ name: this._name,
+ kindId: this._kindId
+ };
+ result = new ReplayableResource(this, data);
+ cache.put(this._id, result); // Put into the cache early to avoid loops.
+ data.calls = this._calls.map(function(call) {
+ return call.toReplayable(cache);
+ });
+ this._populateReplayableData(data, cache);
+ var contextResource = this.contextResource();
+ if (contextResource !== this)
+ data.contextResource = Resource.toReplayable(contextResource, cache);
+ return result;
+ },
+
+ /**
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _populateReplayableData: function(data, cache)
+ {
+ // Do nothing. Should be overridden by subclasses.
+ },
+
+ /**
+ * @param {!Object} data
+ * @param {!Cache} cache
+ * @return {!Resource}
+ */
+ replay: function(data, cache)
+ {
+ var resource = /** @type {Resource} */ (cache.get(data.id));
+ if (resource)
+ return resource;
+ this._id = data.id;
+ this._name = data.name;
+ this._kindId = data.kindId;
+ this._resourceManager = null;
+ this._calls = [];
+ this._boundResources = Object.create(null);
+ this._wrappedObject = null;
+ cache.put(data.id, this); // Put into the cache early to avoid loops.
+ this._doReplayCalls(data, cache);
+ console.assert(this._wrappedObject, "Resource should be reconstructed!");
+ return this;
+ },
+
+ /**
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _doReplayCalls: function(data, cache)
+ {
+ for (var i = 0, n = data.calls.length; i < n; ++i)
+ this._calls.push(data.calls[i].replay(cache));
+ },
+
+ /**
+ * @param {!Call} call
+ */
+ pushCall: function(call)
+ {
+ call.freeze();
+ this._calls.push(call);
+ },
+
+ /**
+ * @param {!Object} object
+ */
+ _bindObjectToResource: function(object)
+ {
+ Object.defineProperty(object, "__resourceObject", {
+ value: this,
+ writable: false,
+ enumerable: false,
+ configurable: true
+ });
+ },
+
+ /**
+ * @param {string} key
+ * @param {*} obj
+ */
+ _registerBoundResource: function(key, obj)
+ {
+ var resource = Resource.forObject(obj);
+ if (resource)
+ this._boundResources[key] = resource;
+ else
+ delete this._boundResources[key];
+ },
+
+ /**
+ * @return {Object}
+ */
+ _wrapObject: function()
+ {
+ var wrappedObject = this.wrappedObject();
+ if (!wrappedObject)
+ return null;
+ var proxy = Object.create(wrappedObject.__proto__); // In order to emulate "instanceof".
+
+ var self = this;
+ var customWrapFunctions = this._customWrapFunctions();
+ function processProperty(property)
+ {
+ if (typeof wrappedObject[property] === "function") {
+ var customWrapFunction = customWrapFunctions[property];
+ if (customWrapFunction)
+ proxy[property] = self._wrapCustomFunction(self, wrappedObject, wrappedObject[property], property, customWrapFunction);
+ else
+ proxy[property] = self._wrapFunction(self, wrappedObject, wrappedObject[property], property);
+ } else if (/^[A-Z0-9_]+$/.test(property) && typeof wrappedObject[property] === "number") {
+ // Fast access to enums and constants.
+ proxy[property] = wrappedObject[property];
+ } else {
+ Object.defineProperty(proxy, property, {
+ get: function()
+ {
+ var obj = wrappedObject[property];
+ var resource = Resource.forObject(obj);
+ return resource ? resource : obj;
+ },
+ set: self._wrapPropertySetter(self, wrappedObject, property),
+ enumerable: true
+ });
+ }
+ }
+
+ var isEmpty = true;
+ for (var property in wrappedObject) {
+ isEmpty = false;
+ processProperty(property);
+ }
+ if (isEmpty)
+ return wrappedObject; // Nothing to proxy.
+
+ this._bindObjectToResource(proxy);
+ return proxy;
+ },
+
+ /**
+ * @param {!Resource} resource
+ * @param {!Object} originalObject
+ * @param {!Function} originalFunction
+ * @param {string} functionName
+ * @param {!Function} customWrapFunction
+ * @return {!Function}
+ */
+ _wrapCustomFunction: function(resource, originalObject, originalFunction, functionName, customWrapFunction)
+ {
+ return function()
+ {
+ var manager = resource.manager();
+ var isCapturing = manager && manager.capturing();
+ if (isCapturing)
+ manager.captureArguments(resource, arguments);
+ var wrapFunction = new Resource.WrapFunction(originalObject, originalFunction, functionName, arguments);
+ customWrapFunction.apply(wrapFunction, arguments);
+ if (isCapturing) {
+ var call = wrapFunction.call();
+ call.setStackTrace(StackTrace.create(1, arguments.callee));
+ manager.captureCall(call);
+ }
+ return wrapFunction.result();
+ };
+ },
+
+ /**
+ * @param {!Resource} resource
+ * @param {!Object} originalObject
+ * @param {!Function} originalFunction
+ * @param {string} functionName
+ * @return {!Function}
+ */
+ _wrapFunction: function(resource, originalObject, originalFunction, functionName)
+ {
+ return function()
+ {
+ var manager = resource.manager();
+ if (!manager || !manager.capturing())
+ return originalFunction.apply(originalObject, arguments);
+ manager.captureArguments(resource, arguments);
+ var result = originalFunction.apply(originalObject, arguments);
+ var stackTrace = StackTrace.create(1, arguments.callee);
+ var call = new Call(resource, functionName, arguments, result, stackTrace);
+ manager.captureCall(call);
+ return result;
+ };
+ },
+
+ /**
+ * @param {!Resource} resource
+ * @param {!Object} originalObject
+ * @param {string} propertyName
+ * @return {function(*)}
+ */
+ _wrapPropertySetter: function(resource, originalObject, propertyName)
+ {
+ return function(value)
+ {
+ resource._registerBoundResource(propertyName, value);
+ var manager = resource.manager();
+ if (!manager || !manager.capturing()) {
+ originalObject[propertyName] = Resource.wrappedObject(value);
+ return;
+ }
+ var args = [propertyName, value];
+ manager.captureArguments(resource, args);
+ originalObject[propertyName] = Resource.wrappedObject(value);
+ var stackTrace = StackTrace.create(1, arguments.callee);
+ var call = new Call(resource, "", args, undefined, stackTrace);
+ manager.captureCall(call);
+ };
+ },
+
+ /**
+ * @return {!Object.<string, Function>}
+ */
+ _customWrapFunctions: function()
+ {
+ return Object.create(null); // May be overridden by subclasses.
+ }
+}
+
+/**
+ * @constructor
+ * @param {Object} originalObject
+ * @param {Function} originalFunction
+ * @param {string} functionName
+ * @param {Array|Arguments} args
+ */
+Resource.WrapFunction = function(originalObject, originalFunction, functionName, args)
+{
+ this._originalObject = originalObject;
+ this._originalFunction = originalFunction;
+ this._functionName = functionName;
+ this._args = args;
+ this._resource = Resource.forObject(originalObject);
+ console.assert(this._resource, "Expected a wrapped call on a Resource object.");
+}
+
+Resource.WrapFunction.prototype = {
+ /**
+ * @return {*}
+ */
+ result: function()
+ {
+ if (!this._executed) {
+ this._executed = true;
+ this._result = this._originalFunction.apply(this._originalObject, this._args);
+ }
+ return this._result;
+ },
+
+ /**
+ * @return {!Call}
+ */
+ call: function()
+ {
+ if (!this._call)
+ this._call = new Call(this._resource, this._functionName, this._args, this.result());
+ return this._call;
+ },
+
+ /**
+ * @param {*} result
+ */
+ overrideResult: function(result)
+ {
+ var call = this.call();
+ call.setResult(result);
+ this._result = result;
+ }
+}
+
+/**
+ * @param {function(new:Resource, !Object, string)} resourceConstructor
+ * @param {string} resourceName
+ * @return {function(this:Resource.WrapFunction)}
+ */
+Resource.WrapFunction.resourceFactoryMethod = function(resourceConstructor, resourceName)
+{
+ /** @this Resource.WrapFunction */
+ return function()
+ {
+ var wrappedObject = /** @type {Object} */ (this.result());
+ if (!wrappedObject)
+ return;
+ var resource = new resourceConstructor(wrappedObject, resourceName);
+ var manager = this._resource.manager();
+ if (manager)
+ manager.registerResource(resource);
+ this.overrideResult(resource.proxyObject());
+ resource.pushCall(this.call());
+ }
+}
+
+/**
+ * @constructor
+ * @param {!Resource} originalResource
+ * @param {!Object} data
+ */
+function ReplayableResource(originalResource, data)
+{
+ this._proto = originalResource.__proto__;
+ this._data = data;
+}
+
+ReplayableResource.prototype = {
+ /**
+ * @return {number}
+ */
+ id: function()
+ {
+ return this._data.id;
+ },
+
+ /**
+ * @return {string}
+ */
+ name: function()
+ {
+ return this._data.name;
+ },
+
+ /**
+ * @return {string}
+ */
+ description: function()
+ {
+ return this._data.name + "@" + this._data.kindId;
+ },
+
+ /**
+ * @return {!ReplayableResource}
+ */
+ replayableContextResource: function()
+ {
+ return this._data.contextResource || this;
+ },
+
+ /**
+ * @param {!Cache} cache
+ * @return {!Resource}
+ */
+ replay: function(cache)
+ {
+ var result = /** @type {!Resource} */ (Object.create(this._proto));
+ result = result.replay(this._data, cache)
+ console.assert(result.__proto__ === this._proto, "Wrong type of a replay result");
+ return result;
+ }
+}
+
+/**
+ * @param {ReplayableResource|*} obj
+ * @param {!Cache} cache
+ * @return {*}
+ */
+ReplayableResource.replay = function(obj, cache)
+{
+ return (obj instanceof ReplayableResource) ? obj.replay(cache).wrappedObject() : obj;
+}
+
+/**
+ * @constructor
+ * @extends {Resource}
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function ContextResource(wrappedObject, name)
+{
+ Resource.call(this, wrappedObject, name);
+}
+
+ContextResource.prototype = {
+ __proto__: Resource.prototype
+}
+
+/**
+ * @constructor
+ * @extends {Resource}
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function LogEverythingResource(wrappedObject, name)
+{
+ Resource.call(this, wrappedObject, name);
+}
+
+LogEverythingResource.prototype = {
+ /**
+ * @override
+ * @return {!Object.<string, Function>}
+ */
+ _customWrapFunctions: function()
+ {
+ var wrapFunctions = Object.create(null);
+ var wrappedObject = this.wrappedObject();
+ if (wrappedObject) {
+ for (var property in wrappedObject) {
+ /** @this Resource.WrapFunction */
+ wrapFunctions[property] = function()
+ {
+ this._resource.pushCall(this.call());
+ }
+ }
+ }
+ return wrapFunctions;
+ },
+
+ __proto__: Resource.prototype
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WebGL
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @constructor
+ * @extends {Resource}
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function WebGLBoundResource(wrappedObject, name)
+{
+ Resource.call(this, wrappedObject, name);
+ /** @type {!Object.<string, *>} */
+ this._state = {};
+}
+
+WebGLBoundResource.prototype = {
+ /**
+ * @override
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _populateReplayableData: function(data, cache)
+ {
+ var state = this._state;
+ data.state = {};
+ Object.keys(state).forEach(function(parameter) {
+ data.state[parameter] = Resource.toReplayable(state[parameter], cache);
+ });
+ },
+
+ /**
+ * @override
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _doReplayCalls: function(data, cache)
+ {
+ var gl = this._replayContextResource(data, cache).wrappedObject();
+
+ /** @type {!Object.<string, Array.<string>>} */
+ var bindingsData = {
+ TEXTURE_2D: ["bindTexture", "TEXTURE_BINDING_2D"],
+ TEXTURE_CUBE_MAP: ["bindTexture", "TEXTURE_BINDING_CUBE_MAP"],
+ ARRAY_BUFFER: ["bindBuffer", "ARRAY_BUFFER_BINDING"],
+ ELEMENT_ARRAY_BUFFER: ["bindBuffer", "ELEMENT_ARRAY_BUFFER_BINDING"],
+ FRAMEBUFFER: ["bindFramebuffer", "FRAMEBUFFER_BINDING"],
+ RENDERBUFFER: ["bindRenderbuffer", "RENDERBUFFER_BINDING"]
+ };
+ var originalBindings = {};
+ Object.keys(bindingsData).forEach(function(bindingTarget) {
+ var bindingParameter = bindingsData[bindingTarget][1];
+ originalBindings[bindingTarget] = gl.getParameter(gl[bindingParameter]);
+ });
+
+ var state = {};
+ Object.keys(data.state).forEach(function(parameter) {
+ state[parameter] = ReplayableResource.replay(data.state[parameter], cache);
+ });
+ this._state = state;
+ Resource.prototype._doReplayCalls.call(this, data, cache);
+
+ Object.keys(bindingsData).forEach(function(bindingTarget) {
+ var bindMethodName = bindingsData[bindingTarget][0];
+ gl[bindMethodName].call(gl, gl[bindingTarget], originalBindings[bindingTarget]);
+ });
+ },
+
+ /**
+ * @param {!Object} data
+ * @param {!Cache} cache
+ * @return {WebGLRenderingContextResource}
+ */
+ _replayContextResource: function(data, cache)
+ {
+ var calls = /** @type {!Array.<ReplayableCall>} */ (data.calls);
+ for (var i = 0, n = calls.length; i < n; ++i) {
+ var resource = ReplayableResource.replay(calls[i].replayableResource(), cache);
+ var contextResource = WebGLRenderingContextResource.forObject(resource);
+ if (contextResource)
+ return contextResource;
+ }
+ return null;
+ },
+
+ /**
+ * @param {number} target
+ * @param {string} bindMethodName
+ */
+ pushBinding: function(target, bindMethodName)
+ {
+ if (this._state.BINDING !== target) {
+ this._state.BINDING = target;
+ this.pushCall(new Call(WebGLRenderingContextResource.forObject(this), bindMethodName, [target, this]));
+ }
+ },
+
+ __proto__: Resource.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebGLBoundResource}
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function WebGLTextureResource(wrappedObject, name)
+{
+ WebGLBoundResource.call(this, wrappedObject, name);
+}
+
+WebGLTextureResource.prototype = {
+ /**
+ * @override
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _doReplayCalls: function(data, cache)
+ {
+ var gl = this._replayContextResource(data, cache).wrappedObject();
+
+ var state = {};
+ WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) {
+ state[parameter] = gl.getParameter(gl[parameter]);
+ });
+
+ WebGLBoundResource.prototype._doReplayCalls.call(this, data, cache);
+
+ WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) {
+ gl.pixelStorei(gl[parameter], state[parameter]);
+ });
+ },
+
+ /**
+ * @override
+ * @param {!Call} call
+ */
+ pushCall: function(call)
+ {
+ var gl = WebGLRenderingContextResource.forObject(call.resource()).wrappedObject();
+ WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) {
+ var value = gl.getParameter(gl[parameter]);
+ if (this._state[parameter] !== value) {
+ this._state[parameter] = value;
+ var pixelStoreCall = new Call(gl, "pixelStorei", [gl[parameter], value]);
+ WebGLBoundResource.prototype.pushCall.call(this, pixelStoreCall);
+ }
+ }, this);
+
+ // FIXME: remove any older calls that no longer contribute to the resource state.
+ // FIXME: optimize memory usage: maybe it's more efficient to store one texImage2D call instead of many texSubImage2D.
+ WebGLBoundResource.prototype.pushCall.call(this, call);
+ },
+
+ /**
+ * Handles: texParameteri, texParameterf
+ * @param {!Call} call
+ */
+ pushCall_texParameter: function(call)
+ {
+ var args = call.args();
+ var pname = args[1];
+ var param = args[2];
+ if (this._state[pname] !== param) {
+ this._state[pname] = param;
+ WebGLBoundResource.prototype.pushCall.call(this, call);
+ }
+ },
+
+ /**
+ * Handles: copyTexImage2D, copyTexSubImage2D
+ * copyTexImage2D and copyTexSubImage2D define a texture image with pixels from the current framebuffer.
+ * @param {!Call} call
+ */
+ pushCall_copyTexImage2D: function(call)
+ {
+ var glResource = WebGLRenderingContextResource.forObject(call.resource());
+ var gl = glResource.wrappedObject();
+ var framebufferResource = /** @type {WebGLFramebufferResource} */ (glResource.currentBinding(gl.FRAMEBUFFER));
+ if (framebufferResource)
+ this.pushCall(new Call(glResource, "bindFramebuffer", [gl.FRAMEBUFFER, framebufferResource]));
+ else {
+ // FIXME: Implement this case.
+ console.error("ASSERT_NOT_REACHED: Could not properly process a gl." + call.functionName() + " call while the DRAWING BUFFER is bound.");
+ }
+ this.pushCall(call);
+ },
+
+ __proto__: WebGLBoundResource.prototype
+}
+
+/**
+ * @constructor
+ * @extends {Resource}
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function WebGLProgramResource(wrappedObject, name)
+{
+ Resource.call(this, wrappedObject, name);
+}
+
+WebGLProgramResource.prototype = {
+ /**
+ * @override (overrides @return type)
+ * @return {WebGLProgram}
+ */
+ wrappedObject: function()
+ {
+ return this._wrappedObject;
+ },
+
+ /**
+ * @override
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _populateReplayableData: function(data, cache)
+ {
+ var glResource = WebGLRenderingContextResource.forObject(this);
+ var gl = glResource.wrappedObject();
+ var program = this.wrappedObject();
+
+ var originalErrors = glResource.getAllErrors();
+
+ var uniforms = [];
+ var uniformsCount = /** @type {number} */ (gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS));
+ for (var i = 0; i < uniformsCount; ++i) {
+ var activeInfo = gl.getActiveUniform(program, i);
+ if (!activeInfo)
+ continue;
+ var uniformLocation = gl.getUniformLocation(program, activeInfo.name);
+ if (!uniformLocation)
+ continue;
+ var value = gl.getUniform(program, uniformLocation);
+ uniforms.push({
+ name: activeInfo.name,
+ type: activeInfo.type,
+ value: value
+ });
+ }
+ data.uniforms = uniforms;
+
+ glResource.restoreErrors(originalErrors);
+ },
+
+ /**
+ * @override
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _doReplayCalls: function(data, cache)
+ {
+ Resource.prototype._doReplayCalls.call(this, data, cache);
+ var gl = WebGLRenderingContextResource.forObject(this).wrappedObject();
+ var program = this.wrappedObject();
+
+ var originalProgram = /** @type {WebGLProgram} */ (gl.getParameter(gl.CURRENT_PROGRAM));
+ var currentProgram = originalProgram;
+
+ data.uniforms.forEach(function(uniform) {
+ var uniformLocation = gl.getUniformLocation(program, uniform.name);
+ if (!uniformLocation)
+ return;
+ if (currentProgram !== program) {
+ currentProgram = program;
+ gl.useProgram(program);
+ }
+ var methodName = this._uniformMethodNameByType(gl, uniform.type);
+ if (methodName.indexOf("Matrix") === -1)
+ gl[methodName].call(gl, uniformLocation, uniform.value);
+ else
+ gl[methodName].call(gl, uniformLocation, false, uniform.value);
+ }.bind(this));
+
+ if (currentProgram !== originalProgram)
+ gl.useProgram(originalProgram);
+ },
+
+ /**
+ * @param {WebGLRenderingContext} gl
+ * @param {number} type
+ * @return {string}
+ */
+ _uniformMethodNameByType: function(gl, type)
+ {
+ var uniformMethodNames = WebGLProgramResource._uniformMethodNames;
+ if (!uniformMethodNames) {
+ uniformMethodNames = {};
+ uniformMethodNames[gl.FLOAT] = "uniform1f";
+ uniformMethodNames[gl.FLOAT_VEC2] = "uniform2fv";
+ uniformMethodNames[gl.FLOAT_VEC3] = "uniform3fv";
+ uniformMethodNames[gl.FLOAT_VEC4] = "uniform4fv";
+ uniformMethodNames[gl.INT] = "uniform1i";
+ uniformMethodNames[gl.BOOL] = "uniform1i";
+ uniformMethodNames[gl.SAMPLER_2D] = "uniform1i";
+ uniformMethodNames[gl.SAMPLER_CUBE] = "uniform1i";
+ uniformMethodNames[gl.INT_VEC2] = "uniform2iv";
+ uniformMethodNames[gl.BOOL_VEC2] = "uniform2iv";
+ uniformMethodNames[gl.INT_VEC3] = "uniform3iv";
+ uniformMethodNames[gl.BOOL_VEC3] = "uniform3iv";
+ uniformMethodNames[gl.INT_VEC4] = "uniform4iv";
+ uniformMethodNames[gl.BOOL_VEC4] = "uniform4iv";
+ uniformMethodNames[gl.FLOAT_MAT2] = "uniformMatrix2fv";
+ uniformMethodNames[gl.FLOAT_MAT3] = "uniformMatrix3fv";
+ uniformMethodNames[gl.FLOAT_MAT4] = "uniformMatrix4fv";
+ WebGLProgramResource._uniformMethodNames = uniformMethodNames;
+ }
+ console.assert(uniformMethodNames[type], "Unknown uniform type " + type);
+ return uniformMethodNames[type];
+ },
+
+ /**
+ * @override
+ * @param {!Call} call
+ */
+ pushCall: function(call)
+ {
+ // FIXME: remove any older calls that no longer contribute to the resource state.
+ // FIXME: handle multiple attachShader && detachShader.
+ Resource.prototype.pushCall.call(this, call);
+ },
+
+ __proto__: Resource.prototype
+}
+
+/**
+ * @constructor
+ * @extends {Resource}
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function WebGLShaderResource(wrappedObject, name)
+{
+ Resource.call(this, wrappedObject, name);
+}
+
+WebGLShaderResource.prototype = {
+ /**
+ * @return {number}
+ */
+ type: function()
+ {
+ var call = this._calls[0];
+ if (call && call.functionName() === "createShader")
+ return call.args()[0];
+ console.error("ASSERT_NOT_REACHED: Failed to restore shader type from the log.", call);
+ return 0;
+ },
+
+ /**
+ * @override
+ * @param {!Call} call
+ */
+ pushCall: function(call)
+ {
+ // FIXME: remove any older calls that no longer contribute to the resource state.
+ // FIXME: handle multiple shaderSource calls.
+ Resource.prototype.pushCall.call(this, call);
+ },
+
+ __proto__: Resource.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebGLBoundResource}
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function WebGLBufferResource(wrappedObject, name)
+{
+ WebGLBoundResource.call(this, wrappedObject, name);
+}
+
+WebGLBufferResource.prototype = {
+ /**
+ * @override
+ * @param {!Call} call
+ */
+ pushCall: function(call)
+ {
+ // FIXME: remove any older calls that no longer contribute to the resource state.
+ // FIXME: Optimize memory for bufferSubData.
+ WebGLBoundResource.prototype.pushCall.call(this, call);
+ },
+
+ __proto__: WebGLBoundResource.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebGLBoundResource}
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function WebGLFramebufferResource(wrappedObject, name)
+{
+ WebGLBoundResource.call(this, wrappedObject, name);
+}
+
+WebGLFramebufferResource.prototype = {
+ /**
+ * @override
+ * @param {!Call} call
+ */
+ pushCall: function(call)
+ {
+ // FIXME: remove any older calls that no longer contribute to the resource state.
+ WebGLBoundResource.prototype.pushCall.call(this, call);
+ },
+
+ __proto__: WebGLBoundResource.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebGLBoundResource}
+ * @param {!Object} wrappedObject
+ * @param {string} name
+ */
+function WebGLRenderbufferResource(wrappedObject, name)
+{
+ WebGLBoundResource.call(this, wrappedObject, name);
+}
+
+WebGLRenderbufferResource.prototype = {
+ /**
+ * @override
+ * @param {!Call} call
+ */
+ pushCall: function(call)
+ {
+ // FIXME: remove any older calls that no longer contribute to the resource state.
+ WebGLBoundResource.prototype.pushCall.call(this, call);
+ },
+
+ __proto__: WebGLBoundResource.prototype
+}
+
+/**
+ * @constructor
+ * @extends {ContextResource}
+ * @param {!WebGLRenderingContext} glContext
+ */
+function WebGLRenderingContextResource(glContext)
+{
+ ContextResource.call(this, glContext, "WebGLRenderingContext");
+ /** @type {Object.<number, boolean>} */
+ this._customErrors = null;
+ /** @type {!Object.<string, boolean>} */
+ this._extensions = {};
+}
+
+/**
+ * @const
+ * @type {!Array.<string>}
+ */
+WebGLRenderingContextResource.GLCapabilities = [
+ "BLEND",
+ "CULL_FACE",
+ "DEPTH_TEST",
+ "DITHER",
+ "POLYGON_OFFSET_FILL",
+ "SAMPLE_ALPHA_TO_COVERAGE",
+ "SAMPLE_COVERAGE",
+ "SCISSOR_TEST",
+ "STENCIL_TEST"
+];
+
+/**
+ * @const
+ * @type {!Array.<string>}
+ */
+WebGLRenderingContextResource.PixelStoreParameters = [
+ "PACK_ALIGNMENT",
+ "UNPACK_ALIGNMENT",
+ "UNPACK_COLORSPACE_CONVERSION_WEBGL",
+ "UNPACK_FLIP_Y_WEBGL",
+ "UNPACK_PREMULTIPLY_ALPHA_WEBGL"
+];
+
+/**
+ * @const
+ * @type {!Array.<string>}
+ */
+WebGLRenderingContextResource.StateParameters = [
+ "ACTIVE_TEXTURE",
+ "ARRAY_BUFFER_BINDING",
+ "BLEND_COLOR",
+ "BLEND_DST_ALPHA",
+ "BLEND_DST_RGB",
+ "BLEND_EQUATION_ALPHA",
+ "BLEND_EQUATION_RGB",
+ "BLEND_SRC_ALPHA",
+ "BLEND_SRC_RGB",
+ "COLOR_CLEAR_VALUE",
+ "COLOR_WRITEMASK",
+ "CULL_FACE_MODE",
+ "CURRENT_PROGRAM",
+ "DEPTH_CLEAR_VALUE",
+ "DEPTH_FUNC",
+ "DEPTH_RANGE",
+ "DEPTH_WRITEMASK",
+ "ELEMENT_ARRAY_BUFFER_BINDING",
+ "FRAMEBUFFER_BINDING",
+ "FRONT_FACE",
+ "GENERATE_MIPMAP_HINT",
+ "LINE_WIDTH",
+ "PACK_ALIGNMENT",
+ "POLYGON_OFFSET_FACTOR",
+ "POLYGON_OFFSET_UNITS",
+ "RENDERBUFFER_BINDING",
+ "SAMPLE_COVERAGE_INVERT",
+ "SAMPLE_COVERAGE_VALUE",
+ "SCISSOR_BOX",
+ "STENCIL_BACK_FAIL",
+ "STENCIL_BACK_FUNC",
+ "STENCIL_BACK_PASS_DEPTH_FAIL",
+ "STENCIL_BACK_PASS_DEPTH_PASS",
+ "STENCIL_BACK_REF",
+ "STENCIL_BACK_VALUE_MASK",
+ "STENCIL_BACK_WRITEMASK",
+ "STENCIL_CLEAR_VALUE",
+ "STENCIL_FAIL",
+ "STENCIL_FUNC",
+ "STENCIL_PASS_DEPTH_FAIL",
+ "STENCIL_PASS_DEPTH_PASS",
+ "STENCIL_REF",
+ "STENCIL_VALUE_MASK",
+ "STENCIL_WRITEMASK",
+ "UNPACK_ALIGNMENT",
+ "UNPACK_COLORSPACE_CONVERSION_WEBGL",
+ "UNPACK_FLIP_Y_WEBGL",
+ "UNPACK_PREMULTIPLY_ALPHA_WEBGL",
+ "VIEWPORT"
+];
+
+/**
+ * @const
+ * @type {!Object.<string, boolean>}
+ */
+WebGLRenderingContextResource.DrawingMethods = TypeUtils.createPrefixedPropertyNamesSet([
+ "clear",
+ "drawArrays",
+ "drawElements"
+]);
+
+/**
+ * @param {*} obj
+ * @return {WebGLRenderingContextResource}
+ */
+WebGLRenderingContextResource.forObject = function(obj)
+{
+ var resource = Resource.forObject(obj);
+ if (!resource)
+ return null;
+ resource = resource.contextResource();
+ return (resource instanceof WebGLRenderingContextResource) ? resource : null;
+}
+
+WebGLRenderingContextResource.prototype = {
+ /**
+ * @override (overrides @return type)
+ * @return {WebGLRenderingContext}
+ */
+ wrappedObject: function()
+ {
+ return this._wrappedObject;
+ },
+
+ /**
+ * @override
+ * @return {string}
+ */
+ toDataURL: function()
+ {
+ return this.wrappedObject().canvas.toDataURL();
+ },
+
+ /**
+ * @return {Array.<number>}
+ */
+ getAllErrors: function()
+ {
+ var errors = [];
+ var gl = this.wrappedObject();
+ if (gl) {
+ while (true) {
+ var error = gl.getError();
+ if (error === gl.NO_ERROR)
+ break;
+ this.clearError(error);
+ errors.push(error);
+ }
+ }
+ if (this._customErrors) {
+ for (var key in this._customErrors) {
+ var error = Number(key);
+ errors.push(error);
+ }
+ delete this._customErrors;
+ }
+ return errors;
+ },
+
+ /**
+ * @param {Array.<number>} errors
+ */
+ restoreErrors: function(errors)
+ {
+ var gl = this.wrappedObject();
+ if (gl) {
+ var wasError = false;
+ while (gl.getError() !== gl.NO_ERROR)
+ wasError = true;
+ console.assert(!wasError, "Error(s) while capturing current WebGL state.");
+ }
+ if (!errors.length)
+ delete this._customErrors;
+ else {
+ this._customErrors = {};
+ for (var i = 0, n = errors.length; i < n; ++i)
+ this._customErrors[errors[i]] = true;
+ }
+ },
+
+ /**
+ * @param {number} error
+ */
+ clearError: function(error)
+ {
+ if (this._customErrors)
+ delete this._customErrors[error];
+ },
+
+ /**
+ * @return {number}
+ */
+ nextError: function()
+ {
+ if (this._customErrors) {
+ for (var key in this._customErrors) {
+ var error = Number(key);
+ delete this._customErrors[error];
+ return error;
+ }
+ }
+ delete this._customErrors;
+ var gl = this.wrappedObject();
+ return gl ? gl.NO_ERROR : 0;
+ },
+
+ /**
+ * @param {string} name
+ */
+ addExtension: function(name)
+ {
+ // FIXME: Wrap OES_vertex_array_object extension.
+ this._extensions[name.toLowerCase()] = true;
+ },
+
+ /**
+ * @override
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _populateReplayableData: function(data, cache)
+ {
+ var gl = this.wrappedObject();
+ data.originalCanvas = gl.canvas;
+ data.originalContextAttributes = gl.getContextAttributes();
+ data.extensions = TypeUtils.cloneObject(this._extensions);
+
+ var originalErrors = this.getAllErrors();
+
+ // Take a full GL state snapshot.
+ var glState = {};
+ WebGLRenderingContextResource.GLCapabilities.forEach(function(parameter) {
+ glState[parameter] = gl.isEnabled(gl[parameter]);
+ });
+ WebGLRenderingContextResource.StateParameters.forEach(function(parameter) {
+ glState[parameter] = Resource.toReplayable(gl.getParameter(gl[parameter]), cache);
+ });
+
+ // VERTEX_ATTRIB_ARRAYS
+ var maxVertexAttribs = /** @type {number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
+ var vertexAttribParameters = ["VERTEX_ATTRIB_ARRAY_BUFFER_BINDING", "VERTEX_ATTRIB_ARRAY_ENABLED", "VERTEX_ATTRIB_ARRAY_SIZE", "VERTEX_ATTRIB_ARRAY_STRIDE", "VERTEX_ATTRIB_ARRAY_TYPE", "VERTEX_ATTRIB_ARRAY_NORMALIZED", "CURRENT_VERTEX_ATTRIB"];
+ var vertexAttribStates = [];
+ for (var i = 0; i < maxVertexAttribs; ++i) {
+ var state = {};
+ vertexAttribParameters.forEach(function(attribParameter) {
+ state[attribParameter] = Resource.toReplayable(gl.getVertexAttrib(i, gl[attribParameter]), cache);
+ });
+ state.VERTEX_ATTRIB_ARRAY_POINTER = gl.getVertexAttribOffset(i, gl.VERTEX_ATTRIB_ARRAY_POINTER);
+ vertexAttribStates.push(state);
+ }
+ glState.vertexAttribStates = vertexAttribStates;
+
+ // TEXTURES
+ var currentTextureBinding = /** @type {number} */ (gl.getParameter(gl.ACTIVE_TEXTURE));
+ var maxTextureImageUnits = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS));
+ var textureBindings = [];
+ for (var i = 0; i < maxTextureImageUnits; ++i) {
+ gl.activeTexture(gl.TEXTURE0 + i);
+ var state = {
+ TEXTURE_2D: Resource.toReplayable(gl.getParameter(gl.TEXTURE_BINDING_2D), cache),
+ TEXTURE_CUBE_MAP: Resource.toReplayable(gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP), cache)
+ };
+ textureBindings.push(state);
+ }
+ glState.textureBindings = textureBindings;
+ gl.activeTexture(currentTextureBinding);
+
+ data.glState = glState;
+
+ this.restoreErrors(originalErrors);
+ },
+
+ /**
+ * @override
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _doReplayCalls: function(data, cache)
+ {
+ this._customErrors = null;
+ this._extensions = TypeUtils.cloneObject(data.extensions) || {};
+
+ var canvas = data.originalCanvas.cloneNode(true);
+ var replayContext = null;
+ var contextIds = ["experimental-webgl", "webkit-3d", "3d"];
+ for (var i = 0, contextId; contextId = contextIds[i]; ++i) {
+ replayContext = canvas.getContext(contextId, data.originalContextAttributes);
+ if (replayContext)
+ break;
+ }
+
+ console.assert(replayContext, "Failed to create a WebGLRenderingContext for the replay.");
+
+ var gl = /** @type {!WebGLRenderingContext} */ (Resource.wrappedObject(replayContext));
+ this.setWrappedObject(gl);
+
+ // Enable corresponding WebGL extensions.
+ for (var name in this._extensions)
+ gl.getExtension(name);
+
+ var glState = data.glState;
+ gl.bindFramebuffer(gl.FRAMEBUFFER, /** @type {WebGLFramebuffer} */ (ReplayableResource.replay(glState.FRAMEBUFFER_BINDING, cache)));
+ gl.bindRenderbuffer(gl.RENDERBUFFER, /** @type {WebGLRenderbuffer} */ (ReplayableResource.replay(glState.RENDERBUFFER_BINDING, cache)));
+
+ // Enable or disable server-side GL capabilities.
+ WebGLRenderingContextResource.GLCapabilities.forEach(function(parameter) {
+ console.assert(parameter in glState);
+ if (glState[parameter])
+ gl.enable(gl[parameter]);
+ else
+ gl.disable(gl[parameter]);
+ });
+
+ gl.blendColor(glState.BLEND_COLOR[0], glState.BLEND_COLOR[1], glState.BLEND_COLOR[2], glState.BLEND_COLOR[3]);
+ gl.blendEquationSeparate(glState.BLEND_EQUATION_RGB, glState.BLEND_EQUATION_ALPHA);
+ gl.blendFuncSeparate(glState.BLEND_SRC_RGB, glState.BLEND_DST_RGB, glState.BLEND_SRC_ALPHA, glState.BLEND_DST_ALPHA);
+ gl.clearColor(glState.COLOR_CLEAR_VALUE[0], glState.COLOR_CLEAR_VALUE[1], glState.COLOR_CLEAR_VALUE[2], glState.COLOR_CLEAR_VALUE[3]);
+ gl.clearDepth(glState.DEPTH_CLEAR_VALUE);
+ gl.clearStencil(glState.STENCIL_CLEAR_VALUE);
+ gl.colorMask(glState.COLOR_WRITEMASK[0], glState.COLOR_WRITEMASK[1], glState.COLOR_WRITEMASK[2], glState.COLOR_WRITEMASK[3]);
+ gl.cullFace(glState.CULL_FACE_MODE);
+ gl.depthFunc(glState.DEPTH_FUNC);
+ gl.depthMask(glState.DEPTH_WRITEMASK);
+ gl.depthRange(glState.DEPTH_RANGE[0], glState.DEPTH_RANGE[1]);
+ gl.frontFace(glState.FRONT_FACE);
+ gl.hint(gl.GENERATE_MIPMAP_HINT, glState.GENERATE_MIPMAP_HINT);
+ gl.lineWidth(glState.LINE_WIDTH);
+
+ WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) {
+ gl.pixelStorei(gl[parameter], glState[parameter]);
+ });
+
+ gl.polygonOffset(glState.POLYGON_OFFSET_FACTOR, glState.POLYGON_OFFSET_UNITS);
+ gl.sampleCoverage(glState.SAMPLE_COVERAGE_VALUE, glState.SAMPLE_COVERAGE_INVERT);
+ gl.stencilFuncSeparate(gl.FRONT, glState.STENCIL_FUNC, glState.STENCIL_REF, glState.STENCIL_VALUE_MASK);
+ gl.stencilFuncSeparate(gl.BACK, glState.STENCIL_BACK_FUNC, glState.STENCIL_BACK_REF, glState.STENCIL_BACK_VALUE_MASK);
+ gl.stencilOpSeparate(gl.FRONT, glState.STENCIL_FAIL, glState.STENCIL_PASS_DEPTH_FAIL, glState.STENCIL_PASS_DEPTH_PASS);
+ gl.stencilOpSeparate(gl.BACK, glState.STENCIL_BACK_FAIL, glState.STENCIL_BACK_PASS_DEPTH_FAIL, glState.STENCIL_BACK_PASS_DEPTH_PASS);
+ gl.stencilMaskSeparate(gl.FRONT, glState.STENCIL_WRITEMASK);
+ gl.stencilMaskSeparate(gl.BACK, glState.STENCIL_BACK_WRITEMASK);
+
+ gl.scissor(glState.SCISSOR_BOX[0], glState.SCISSOR_BOX[1], glState.SCISSOR_BOX[2], glState.SCISSOR_BOX[3]);
+ gl.viewport(glState.VIEWPORT[0], glState.VIEWPORT[1], glState.VIEWPORT[2], glState.VIEWPORT[3]);
+
+ gl.useProgram(/** @type {WebGLProgram} */ (ReplayableResource.replay(glState.CURRENT_PROGRAM, cache)));
+
+ // VERTEX_ATTRIB_ARRAYS
+ var maxVertexAttribs = /** @type {number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
+ for (var i = 0; i < maxVertexAttribs; ++i) {
+ var state = glState.vertexAttribStates[i] || {};
+ if (state.VERTEX_ATTRIB_ARRAY_ENABLED)
+ gl.enableVertexAttribArray(i);
+ else
+ gl.disableVertexAttribArray(i);
+ if (state.CURRENT_VERTEX_ATTRIB)
+ gl.vertexAttrib4fv(i, state.CURRENT_VERTEX_ATTRIB);
+ var buffer = /** @type {WebGLBuffer} */ (ReplayableResource.replay(state.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, cache));
+ if (buffer) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.vertexAttribPointer(i, state.VERTEX_ATTRIB_ARRAY_SIZE, state.VERTEX_ATTRIB_ARRAY_TYPE, state.VERTEX_ATTRIB_ARRAY_NORMALIZED, state.VERTEX_ATTRIB_ARRAY_STRIDE, state.VERTEX_ATTRIB_ARRAY_POINTER);
+ }
+ }
+ gl.bindBuffer(gl.ARRAY_BUFFER, /** @type {WebGLBuffer} */ (ReplayableResource.replay(glState.ARRAY_BUFFER_BINDING, cache)));
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, /** @type {WebGLBuffer} */ (ReplayableResource.replay(glState.ELEMENT_ARRAY_BUFFER_BINDING, cache)));
+
+ // TEXTURES
+ var maxTextureImageUnits = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS));
+ for (var i = 0; i < maxTextureImageUnits; ++i) {
+ gl.activeTexture(gl.TEXTURE0 + i);
+ var state = glState.textureBindings[i] || {};
+ gl.bindTexture(gl.TEXTURE_2D, /** @type {WebGLTexture} */ (ReplayableResource.replay(state.TEXTURE_2D, cache)));
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, /** @type {WebGLTexture} */ (ReplayableResource.replay(state.TEXTURE_CUBE_MAP, cache)));
+ }
+ gl.activeTexture(glState.ACTIVE_TEXTURE);
+
+ ContextResource.prototype._doReplayCalls.call(this, data, cache);
+ },
+
+ /**
+ * @param {Object|number} target
+ * @return {Resource}
+ */
+ currentBinding: function(target)
+ {
+ var resource = Resource.forObject(target);
+ if (resource)
+ return resource;
+ var gl = this.wrappedObject();
+ var bindingParameter;
+ var bindMethodName;
+ var bindMethodTarget = target;
+ switch (target) {
+ case gl.ARRAY_BUFFER:
+ bindingParameter = gl.ARRAY_BUFFER_BINDING;
+ bindMethodName = "bindBuffer";
+ break;
+ case gl.ELEMENT_ARRAY_BUFFER:
+ bindingParameter = gl.ELEMENT_ARRAY_BUFFER_BINDING;
+ bindMethodName = "bindBuffer";
+ break;
+ case gl.TEXTURE_2D:
+ bindingParameter = gl.TEXTURE_BINDING_2D;
+ bindMethodName = "bindTexture";
+ break;
+ case gl.TEXTURE_CUBE_MAP:
+ case gl.TEXTURE_CUBE_MAP_POSITIVE_X:
+ case gl.TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case gl.TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case gl.TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case gl.TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case gl.TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ bindingParameter = gl.TEXTURE_BINDING_CUBE_MAP;
+ bindMethodTarget = gl.TEXTURE_CUBE_MAP;
+ bindMethodName = "bindTexture";
+ break;
+ case gl.FRAMEBUFFER:
+ bindingParameter = gl.FRAMEBUFFER_BINDING;
+ bindMethodName = "bindFramebuffer";
+ break;
+ case gl.RENDERBUFFER:
+ bindingParameter = gl.RENDERBUFFER_BINDING;
+ bindMethodName = "bindRenderbuffer";
+ break;
+ default:
+ console.error("ASSERT_NOT_REACHED: unknown binding target " + target);
+ return null;
+ }
+ resource = Resource.forObject(gl.getParameter(bindingParameter));
+ if (resource)
+ resource.pushBinding(bindMethodTarget, bindMethodName);
+ return resource;
+ },
+
+ /**
+ * @override
+ * @return {!Object.<string, Function>}
+ */
+ _customWrapFunctions: function()
+ {
+ var wrapFunctions = WebGLRenderingContextResource._wrapFunctions;
+ if (!wrapFunctions) {
+ wrapFunctions = Object.create(null);
+
+ wrapFunctions["createBuffer"] = Resource.WrapFunction.resourceFactoryMethod(WebGLBufferResource, "WebGLBuffer");
+ wrapFunctions["createShader"] = Resource.WrapFunction.resourceFactoryMethod(WebGLShaderResource, "WebGLShader");
+ wrapFunctions["createProgram"] = Resource.WrapFunction.resourceFactoryMethod(WebGLProgramResource, "WebGLProgram");
+ wrapFunctions["createTexture"] = Resource.WrapFunction.resourceFactoryMethod(WebGLTextureResource, "WebGLTexture");
+ wrapFunctions["createFramebuffer"] = Resource.WrapFunction.resourceFactoryMethod(WebGLFramebufferResource, "WebGLFramebuffer");
+ wrapFunctions["createRenderbuffer"] = Resource.WrapFunction.resourceFactoryMethod(WebGLRenderbufferResource, "WebGLRenderbuffer");
+ wrapFunctions["getUniformLocation"] = Resource.WrapFunction.resourceFactoryMethod(Resource, "WebGLUniformLocation");
+
+ /**
+ * @param {string} methodName
+ * @param {function(this:Resource, !Call)=} pushCallFunc
+ */
+ function stateModifyingWrapFunction(methodName, pushCallFunc)
+ {
+ if (pushCallFunc) {
+ /**
+ * @param {Object|number} target
+ * @this Resource.WrapFunction
+ */
+ wrapFunctions[methodName] = function(target)
+ {
+ var resource = this._resource.currentBinding(target);
+ if (resource)
+ pushCallFunc.call(resource, this.call());
+ }
+ } else {
+ /**
+ * @param {Object|number} target
+ * @this Resource.WrapFunction
+ */
+ wrapFunctions[methodName] = function(target)
+ {
+ var resource = this._resource.currentBinding(target);
+ if (resource)
+ resource.pushCall(this.call());
+ }
+ }
+ }
+ stateModifyingWrapFunction("bindAttribLocation");
+ stateModifyingWrapFunction("compileShader");
+ stateModifyingWrapFunction("detachShader");
+ stateModifyingWrapFunction("linkProgram");
+ stateModifyingWrapFunction("shaderSource");
+ stateModifyingWrapFunction("bufferData");
+ stateModifyingWrapFunction("bufferSubData");
+ stateModifyingWrapFunction("compressedTexImage2D");
+ stateModifyingWrapFunction("compressedTexSubImage2D");
+ stateModifyingWrapFunction("copyTexImage2D", WebGLTextureResource.prototype.pushCall_copyTexImage2D);
+ stateModifyingWrapFunction("copyTexSubImage2D", WebGLTextureResource.prototype.pushCall_copyTexImage2D);
+ stateModifyingWrapFunction("generateMipmap");
+ stateModifyingWrapFunction("texImage2D");
+ stateModifyingWrapFunction("texSubImage2D");
+ stateModifyingWrapFunction("texParameterf", WebGLTextureResource.prototype.pushCall_texParameter);
+ stateModifyingWrapFunction("texParameteri", WebGLTextureResource.prototype.pushCall_texParameter);
+ stateModifyingWrapFunction("renderbufferStorage");
+
+ /** @this Resource.WrapFunction */
+ wrapFunctions["getError"] = function()
+ {
+ var gl = /** @type {WebGLRenderingContext} */ (this._originalObject);
+ var error = this.result();
+ if (error !== gl.NO_ERROR)
+ this._resource.clearError(error);
+ else {
+ error = this._resource.nextError();
+ if (error !== gl.NO_ERROR)
+ this.overrideResult(error);
+ }
+ }
+
+ /**
+ * @param {string} name
+ * @this Resource.WrapFunction
+ */
+ wrapFunctions["getExtension"] = function(name)
+ {
+ this._resource.addExtension(name);
+ }
+
+ //
+ // Register bound WebGL resources.
+ //
+
+ /**
+ * @param {WebGLProgram} program
+ * @param {WebGLShader} shader
+ * @this Resource.WrapFunction
+ */
+ wrapFunctions["attachShader"] = function(program, shader)
+ {
+ var resource = this._resource.currentBinding(program);
+ if (resource) {
+ resource.pushCall(this.call());
+ var shaderResource = /** @type {WebGLShaderResource} */ (Resource.forObject(shader));
+ if (shaderResource) {
+ var shaderType = shaderResource.type();
+ resource._registerBoundResource("__attachShader_" + shaderType, shaderResource);
+ }
+ }
+ }
+ /**
+ * @param {number} target
+ * @param {number} attachment
+ * @param {number} objectTarget
+ * @param {WebGLRenderbuffer|WebGLTexture} obj
+ * @this Resource.WrapFunction
+ */
+ wrapFunctions["framebufferRenderbuffer"] = wrapFunctions["framebufferTexture2D"] = function(target, attachment, objectTarget, obj)
+ {
+ var resource = this._resource.currentBinding(target);
+ if (resource) {
+ resource.pushCall(this.call());
+ resource._registerBoundResource("__framebufferAttachmentObjectName", obj);
+ }
+ }
+ /**
+ * @param {number} target
+ * @param {Object} obj
+ * @this Resource.WrapFunction
+ */
+ wrapFunctions["bindBuffer"] = wrapFunctions["bindFramebuffer"] = wrapFunctions["bindRenderbuffer"] = function(target, obj)
+ {
+ this._resource._registerBoundResource("__bindBuffer_" + target, obj);
+ }
+ /**
+ * @param {number} target
+ * @param {WebGLTexture} obj
+ * @this Resource.WrapFunction
+ */
+ wrapFunctions["bindTexture"] = function(target, obj)
+ {
+ var gl = /** @type {WebGLRenderingContext} */ (this._originalObject);
+ var currentTextureBinding = /** @type {number} */ (gl.getParameter(gl.ACTIVE_TEXTURE));
+ this._resource._registerBoundResource("__bindTexture_" + target + "_" + currentTextureBinding, obj);
+ }
+ /**
+ * @param {WebGLProgram} program
+ * @this Resource.WrapFunction
+ */
+ wrapFunctions["useProgram"] = function(program)
+ {
+ this._resource._registerBoundResource("__useProgram", program);
+ }
+ /**
+ * @param {number} index
+ * @this Resource.WrapFunction
+ */
+ wrapFunctions["vertexAttribPointer"] = function(index)
+ {
+ var gl = /** @type {WebGLRenderingContext} */ (this._originalObject);
+ this._resource._registerBoundResource("__vertexAttribPointer_" + index, gl.getParameter(gl.ARRAY_BUFFER_BINDING));
+ }
+
+ WebGLRenderingContextResource._wrapFunctions = wrapFunctions;
+ }
+ return wrapFunctions;
+ },
+
+ __proto__: ContextResource.prototype
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// 2D Canvas
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @constructor
+ * @extends {ContextResource}
+ * @param {!CanvasRenderingContext2D} context
+ */
+function CanvasRenderingContext2DResource(context)
+{
+ ContextResource.call(this, context, "CanvasRenderingContext2D");
+}
+
+/**
+ * @const
+ * @type {!Array.<string>}
+ */
+CanvasRenderingContext2DResource.AttributeProperties = [
+ "strokeStyle",
+ "fillStyle",
+ "globalAlpha",
+ "lineWidth",
+ "lineCap",
+ "lineJoin",
+ "miterLimit",
+ "shadowOffsetX",
+ "shadowOffsetY",
+ "shadowBlur",
+ "shadowColor",
+ "globalCompositeOperation",
+ "font",
+ "textAlign",
+ "textBaseline",
+ "lineDashOffset",
+ // FIXME: Temporary properties implemented in JSC, but not in V8.
+ "webkitLineDash",
+ "webkitLineDashOffset"
+];
+
+/**
+ * @const
+ * @type {!Array.<string>}
+ */
+CanvasRenderingContext2DResource.PathMethods = [
+ "beginPath",
+ "moveTo",
+ "closePath",
+ "lineTo",
+ "quadraticCurveTo",
+ "bezierCurveTo",
+ "arcTo",
+ "arc",
+ "rect"
+];
+
+/**
+ * @const
+ * @type {!Array.<string>}
+ */
+CanvasRenderingContext2DResource.TransformationMatrixMethods = [
+ "scale",
+ "rotate",
+ "translate",
+ "transform",
+ "setTransform"
+];
+
+/**
+ * @const
+ * @type {!Object.<string, boolean>}
+ */
+CanvasRenderingContext2DResource.DrawingMethods = TypeUtils.createPrefixedPropertyNamesSet([
+ "clearRect",
+ "drawImage",
+ "drawImageFromRect",
+ "drawCustomFocusRing",
+ "drawSystemFocusRing",
+ "fill",
+ "fillRect",
+ "fillText",
+ "putImageData",
+ "putImageDataHD",
+ "stroke",
+ "strokeRect",
+ "strokeText"
+]);
+
+CanvasRenderingContext2DResource.prototype = {
+ /**
+ * @override (overrides @return type)
+ * @return {CanvasRenderingContext2D}
+ */
+ wrappedObject: function()
+ {
+ return this._wrappedObject;
+ },
+
+ /**
+ * @override
+ * @return {string}
+ */
+ toDataURL: function()
+ {
+ return this.wrappedObject().canvas.toDataURL();
+ },
+
+ /**
+ * @override
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _populateReplayableData: function(data, cache)
+ {
+ data.currentAttributes = this._currentAttributesState();
+ data.originalCanvasCloned = TypeUtils.cloneIntoCanvas(this.wrappedObject().canvas);
+ },
+
+ /**
+ * @override
+ * @param {!Object} data
+ * @param {!Cache} cache
+ */
+ _doReplayCalls: function(data, cache)
+ {
+ var canvas = TypeUtils.cloneIntoCanvas(data.originalCanvasCloned);
+ var ctx = /** @type {!CanvasRenderingContext2D} */ (Resource.wrappedObject(canvas.getContext("2d")));
+ this.setWrappedObject(ctx);
+
+ for (var i = 0, n = data.calls.length; i < n; ++i) {
+ var replayableCall = /** @type {ReplayableCall} */ (data.calls[i]);
+ if (replayableCall.functionName() === "save")
+ this._applyAttributesState(replayableCall.attachment("canvas2dAttributesState"));
+ this._calls.push(replayableCall.replay(cache));
+ }
+ this._applyAttributesState(data.currentAttributes);
+ },
+
+ /**
+ * @param {!Call} call
+ */
+ pushCall_setTransform: function(call)
+ {
+ var saveCallIndex = this._lastIndexOfMatchingSaveCall();
+ var index = this._lastIndexOfAnyCall(CanvasRenderingContext2DResource.PathMethods);
+ index = Math.max(index, saveCallIndex);
+ if (this._removeCallsFromLog(CanvasRenderingContext2DResource.TransformationMatrixMethods, index + 1))
+ this._removeAllObsoleteCallsFromLog();
+ this.pushCall(call);
+ },
+
+ /**
+ * @param {!Call} call
+ */
+ pushCall_beginPath: function(call)
+ {
+ var index = this._lastIndexOfAnyCall(["clip"]);
+ if (this._removeCallsFromLog(CanvasRenderingContext2DResource.PathMethods, index + 1))
+ this._removeAllObsoleteCallsFromLog();
+ this.pushCall(call);
+ },
+
+ /**
+ * @param {!Call} call
+ */
+ pushCall_save: function(call)
+ {
+ call.setAttachment("canvas2dAttributesState", this._currentAttributesState());
+ this.pushCall(call);
+ },
+
+ /**
+ * @param {!Call} call
+ */
+ pushCall_restore: function(call)
+ {
+ var lastIndexOfSave = this._lastIndexOfMatchingSaveCall();
+ if (lastIndexOfSave === -1)
+ return;
+ this._calls[lastIndexOfSave].setAttachment("canvas2dAttributesState", null); // No longer needed, free memory.
+
+ var modified = false;
+ if (this._removeCallsFromLog(["clip"], lastIndexOfSave + 1))
+ modified = true;
+
+ var lastIndexOfAnyPathMethod = this._lastIndexOfAnyCall(CanvasRenderingContext2DResource.PathMethods);
+ var index = Math.max(lastIndexOfSave, lastIndexOfAnyPathMethod);
+ if (this._removeCallsFromLog(CanvasRenderingContext2DResource.TransformationMatrixMethods, index + 1))
+ modified = true;
+
+ if (modified)
+ this._removeAllObsoleteCallsFromLog();
+
+ var lastCall = this._calls[this._calls.length - 1];
+ if (lastCall && lastCall.functionName() === "save")
+ this._calls.pop();
+ else
+ this.pushCall(call);
+ },
+
+ /**
+ * @param {number=} fromIndex
+ * @return {number}
+ */
+ _lastIndexOfMatchingSaveCall: function(fromIndex)
+ {
+ if (typeof fromIndex !== "number")
+ fromIndex = this._calls.length - 1;
+ else
+ fromIndex = Math.min(fromIndex, this._calls.length - 1);
+ var stackDepth = 1;
+ for (var i = fromIndex; i >= 0; --i) {
+ var functionName = this._calls[i].functionName();
+ if (functionName === "restore")
+ ++stackDepth;
+ else if (functionName === "save") {
+ --stackDepth;
+ if (!stackDepth)
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ /**
+ * @param {!Array.<string>} functionNames
+ * @param {number=} fromIndex
+ * @return {number}
+ */
+ _lastIndexOfAnyCall: function(functionNames, fromIndex)
+ {
+ if (typeof fromIndex !== "number")
+ fromIndex = this._calls.length - 1;
+ else
+ fromIndex = Math.min(fromIndex, this._calls.length - 1);
+ for (var i = fromIndex; i >= 0; --i) {
+ if (functionNames.indexOf(this._calls[i].functionName()) !== -1)
+ return i;
+ }
+ return -1;
+ },
+
+ _removeAllObsoleteCallsFromLog: function()
+ {
+ // Remove all PATH methods between clip() and beginPath() calls.
+ var lastIndexOfBeginPath = this._lastIndexOfAnyCall(["beginPath"]);
+ while (lastIndexOfBeginPath !== -1) {
+ var index = this._lastIndexOfAnyCall(["clip"], lastIndexOfBeginPath - 1);
+ this._removeCallsFromLog(CanvasRenderingContext2DResource.PathMethods, index + 1, lastIndexOfBeginPath);
+ lastIndexOfBeginPath = this._lastIndexOfAnyCall(["beginPath"], index - 1);
+ }
+
+ // Remove all TRASFORMATION MATRIX methods before restore() or setTransform() but after any PATH or corresponding save() method.
+ var lastRestore = this._lastIndexOfAnyCall(["restore", "setTransform"]);
+ while (lastRestore !== -1) {
+ var saveCallIndex = this._lastIndexOfMatchingSaveCall(lastRestore - 1);
+ var index = this._lastIndexOfAnyCall(CanvasRenderingContext2DResource.PathMethods, lastRestore - 1);
+ index = Math.max(index, saveCallIndex);
+ this._removeCallsFromLog(CanvasRenderingContext2DResource.TransformationMatrixMethods, index + 1, lastRestore);
+ lastRestore = this._lastIndexOfAnyCall(["restore", "setTransform"], index - 1);
+ }
+
+ // Remove all save-restore consecutive pairs.
+ var restoreCalls = 0;
+ for (var i = this._calls.length - 1; i >= 0; --i) {
+ var functionName = this._calls[i].functionName();
+ if (functionName === "restore") {
+ ++restoreCalls;
+ continue;
+ }
+ if (functionName === "save" && restoreCalls > 0) {
+ var saveCallIndex = i;
+ for (var j = i - 1; j >= 0 && i - j < restoreCalls; --j) {
+ if (this._calls[j].functionName() === "save")
+ saveCallIndex = j;
+ else
+ break;
+ }
+ this._calls.splice(saveCallIndex, (i - saveCallIndex + 1) * 2);
+ i = saveCallIndex;
+ }
+ restoreCalls = 0;
+ }
+ },
+
+ /**
+ * @param {!Array.<string>} functionNames
+ * @param {number} fromIndex
+ * @param {number=} toIndex
+ * @return {boolean}
+ */
+ _removeCallsFromLog: function(functionNames, fromIndex, toIndex)
+ {
+ var oldLength = this._calls.length;
+ if (typeof toIndex !== "number")
+ toIndex = oldLength;
+ else
+ toIndex = Math.min(toIndex, oldLength);
+ var newIndex = Math.min(fromIndex, oldLength);
+ for (var i = newIndex; i < toIndex; ++i) {
+ var call = this._calls[i];
+ if (functionNames.indexOf(call.functionName()) === -1)
+ this._calls[newIndex++] = call;
+ }
+ if (newIndex >= toIndex)
+ return false;
+ this._calls.splice(newIndex, toIndex - newIndex);
+ return true;
+ },
+
+ /**
+ * @return {!Object.<string, string>}
+ */
+ _currentAttributesState: function()
+ {
+ var ctx = this.wrappedObject();
+ var state = {};
+ state.attributes = {};
+ CanvasRenderingContext2DResource.AttributeProperties.forEach(function(attribute) {
+ state.attributes[attribute] = ctx[attribute];
+ });
+ if (ctx.getLineDash)
+ state.lineDash = ctx.getLineDash();
+ return state;
+ },
+
+ /**
+ * @param {Object.<string, string>=} state
+ */
+ _applyAttributesState: function(state)
+ {
+ if (!state)
+ return;
+ var ctx = this.wrappedObject();
+ if (state.attributes) {
+ Object.keys(state.attributes).forEach(function(attribute) {
+ ctx[attribute] = state.attributes[attribute];
+ });
+ }
+ if (ctx.setLineDash)
+ ctx.setLineDash(state.lineDash);
+ },
+
+ /**
+ * @override
+ * @return {!Object.<string, Function>}
+ */
+ _customWrapFunctions: function()
+ {
+ var wrapFunctions = CanvasRenderingContext2DResource._wrapFunctions;
+ if (!wrapFunctions) {
+ wrapFunctions = Object.create(null);
+
+ wrapFunctions["createLinearGradient"] = Resource.WrapFunction.resourceFactoryMethod(LogEverythingResource, "CanvasGradient");
+ wrapFunctions["createRadialGradient"] = Resource.WrapFunction.resourceFactoryMethod(LogEverythingResource, "CanvasGradient");
+ wrapFunctions["createPattern"] = Resource.WrapFunction.resourceFactoryMethod(LogEverythingResource, "CanvasPattern");
+
+ /**
+ * @param {string} methodName
+ * @param {function(this:Resource, !Call)=} func
+ */
+ function stateModifyingWrapFunction(methodName, func)
+ {
+ if (func) {
+ /** @this Resource.WrapFunction */
+ wrapFunctions[methodName] = function()
+ {
+ func.call(this._resource, this.call());
+ }
+ } else {
+ /** @this Resource.WrapFunction */
+ wrapFunctions[methodName] = function()
+ {
+ this._resource.pushCall(this.call());
+ }
+ }
+ }
+
+ for (var i = 0, methodName; methodName = CanvasRenderingContext2DResource.TransformationMatrixMethods[i]; ++i)
+ stateModifyingWrapFunction(methodName, methodName === "setTransform" ? this.pushCall_setTransform : undefined);
+ for (var i = 0, methodName; methodName = CanvasRenderingContext2DResource.PathMethods[i]; ++i)
+ stateModifyingWrapFunction(methodName, methodName === "beginPath" ? this.pushCall_beginPath : undefined);
+
+ stateModifyingWrapFunction("save", this.pushCall_save);
+ stateModifyingWrapFunction("restore", this.pushCall_restore);
+ stateModifyingWrapFunction("clip");
+
+ CanvasRenderingContext2DResource._wrapFunctions = wrapFunctions;
+ }
+ return wrapFunctions;
+ },
+
+ __proto__: ContextResource.prototype
+}
+
+/**
+ * @constructor
+ * @param {!Object.<string, boolean>=} drawingMethodNames
+ */
+function CallFormatter(drawingMethodNames)
+{
+ this._drawingMethodNames = drawingMethodNames || Object.create(null);
+}
+
+CallFormatter.prototype = {
+ /**
+ * @param {!ReplayableCall} replayableCall
+ * @return {!Object}
+ */
+ formatCall: function(replayableCall)
+ {
+ var result = {};
+ var functionName = replayableCall.functionName();
+ if (functionName) {
+ result.functionName = functionName;
+ result.arguments = replayableCall.args().map(this.formatValue.bind(this));
+ if (replayableCall.result() !== undefined)
+ result.result = this.formatValue(replayableCall.result());
+ if (this._drawingMethodNames[functionName])
+ result.isDrawingCall = true;
+ } else {
+ result.property = replayableCall.args()[0];
+ result.value = this.formatValue(replayableCall.args()[1]);
+ }
+ return result;
+ },
+
+ /**
+ * @param {*} value
+ * @return {!Object}
+ */
+ formatValue: function(value)
+ {
+ if (value instanceof ReplayableResource)
+ var description = value.description();
+ else
+ var description = "" + value;
+ return { description: description };
+ }
+}
+
+/**
+ * @const
+ * @type {!Object.<string, !CallFormatter>}
+ */
+CallFormatter._formatters = {};
+
+/**
+ * @param {string} resourceName
+ * @param {!CallFormatter} callFormatter
+ */
+CallFormatter.register = function(resourceName, callFormatter)
+{
+ CallFormatter._formatters[resourceName] = callFormatter;
+}
+
+/**
+ * @param {!ReplayableCall} replayableCall
+ * @return {!Object}
+ */
+CallFormatter.formatCall = function(replayableCall)
+{
+ var resource = replayableCall.replayableResource();
+ var formatter = CallFormatter._formatters[resource.name()];
+ if (!formatter) {
+ var contextResource = resource.replayableContextResource();
+ formatter = CallFormatter._formatters[contextResource.name()] || new CallFormatter();
+ }
+ return formatter.formatCall(replayableCall);
+}
+
+CallFormatter.register("CanvasRenderingContext2D", new CallFormatter(CanvasRenderingContext2DResource.DrawingMethods));
+CallFormatter.register("WebGLRenderingContext", new CallFormatter(WebGLRenderingContextResource.DrawingMethods));
+
+/**
+ * @constructor
+ */
+function TraceLog()
+{
+ /** @type {!Array.<ReplayableCall>} */
+ this._replayableCalls = [];
+ /** @type {!Cache} */
+ this._replayablesCache = new Cache();
+ /** @type {!Object.<number, boolean>} */
+ this._frameEndCallIndexes = {};
+}
+
+TraceLog.prototype = {
+ /**
+ * @return {number}
+ */
+ size: function()
+ {
+ return this._replayableCalls.length;
+ },
+
+ /**
+ * @return {!Array.<ReplayableCall>}
+ */
+ replayableCalls: function()
+ {
+ return this._replayableCalls;
+ },
+
+ /**
+ * @param {number} id
+ * @return {ReplayableResource}
+ */
+ replayableResource: function(id)
+ {
+ return /** @type {ReplayableResource} */ (this._replayablesCache.get(id));
+ },
+
+ /**
+ * @param {!Resource} resource
+ */
+ captureResource: function(resource)
+ {
+ resource.toReplayable(this._replayablesCache);
+ },
+
+ /**
+ * @param {!Call} call
+ */
+ addCall: function(call)
+ {
+ this._replayableCalls.push(call.toReplayable(this._replayablesCache));
+ },
+
+ addFrameEndMark: function()
+ {
+ var index = this._replayableCalls.length - 1;
+ if (index >= 0)
+ this._frameEndCallIndexes[index] = true;
+ },
+
+ /**
+ * @param {number} index
+ * @return {boolean}
+ */
+ isFrameEndCallAt: function(index)
+ {
+ return !!this._frameEndCallIndexes[index];
+ }
+}
+
+/**
+ * @constructor
+ * @param {!TraceLog} traceLog
+ */
+function TraceLogPlayer(traceLog)
+{
+ /** @type {!TraceLog} */
+ this._traceLog = traceLog;
+ /** @type {number} */
+ this._nextReplayStep = 0;
+ /** @type {!Cache} */
+ this._replayWorldCache = new Cache();
+}
+
+TraceLogPlayer.prototype = {
+ /**
+ * @return {!TraceLog}
+ */
+ traceLog: function()
+ {
+ return this._traceLog;
+ },
+
+ /**
+ * @param {number} id
+ * @return {Resource}
+ */
+ replayWorldResource: function(id)
+ {
+ return /** @type {Resource} */ (this._replayWorldCache.get(id));
+ },
+
+ /**
+ * @return {number}
+ */
+ nextReplayStep: function()
+ {
+ return this._nextReplayStep;
+ },
+
+ reset: function()
+ {
+ this._nextReplayStep = 0;
+ this._replayWorldCache.reset();
+ },
+
+ /**
+ * @return {Call}
+ */
+ step: function()
+ {
+ return this.stepTo(this._nextReplayStep);
+ },
+
+ /**
+ * @param {number} stepNum
+ * @return {Call}
+ */
+ stepTo: function(stepNum)
+ {
+ stepNum = Math.min(stepNum, this._traceLog.size() - 1);
+ console.assert(stepNum >= 0);
+ if (this._nextReplayStep > stepNum)
+ this.reset();
+ // FIXME: Replay all the cached resources first to warm-up.
+ var lastCall = null;
+ var replayableCalls = this._traceLog.replayableCalls();
+ while (this._nextReplayStep <= stepNum)
+ lastCall = replayableCalls[this._nextReplayStep++].replay(this._replayWorldCache);
+ return lastCall;
+ },
+
+ /**
+ * @return {Call}
+ */
+ replay: function()
+ {
+ return this.stepTo(this._traceLog.size() - 1);
+ }
+}
+
+/**
+ * @constructor
+ */
+function ResourceTrackingManager()
+{
+ this._capturing = false;
+ this._stopCapturingOnFrameEnd = false;
+ this._lastTraceLog = null;
+}
+
+ResourceTrackingManager.prototype = {
+ /**
+ * @return {boolean}
+ */
+ capturing: function()
+ {
+ return this._capturing;
+ },
+
+ /**
+ * @return {TraceLog}
+ */
+ lastTraceLog: function()
+ {
+ return this._lastTraceLog;
+ },
+
+ /**
+ * @param {!Resource} resource
+ */
+ registerResource: function(resource)
+ {
+ resource.setManager(this);
+ },
+
+ startCapturing: function()
+ {
+ if (!this._capturing)
+ this._lastTraceLog = new TraceLog();
+ this._capturing = true;
+ this._stopCapturingOnFrameEnd = false;
+ },
+
+ /**
+ * @param {TraceLog=} traceLog
+ */
+ stopCapturing: function(traceLog)
+ {
+ if (traceLog && this._lastTraceLog !== traceLog)
+ return;
+ this._capturing = false;
+ this._stopCapturingOnFrameEnd = false;
+ if (this._lastTraceLog)
+ this._lastTraceLog.addFrameEndMark();
+ },
+
+ /**
+ * @param {!TraceLog} traceLog
+ */
+ dropTraceLog: function(traceLog)
+ {
+ this.stopCapturing(traceLog);
+ if (this._lastTraceLog === traceLog)
+ this._lastTraceLog = null;
+ },
+
+ captureFrame: function()
+ {
+ this._lastTraceLog = new TraceLog();
+ this._capturing = true;
+ this._stopCapturingOnFrameEnd = true;
+ },
+
+ /**
+ * @param {!Resource} resource
+ * @param {Array|Arguments} args
+ */
+ captureArguments: function(resource, args)
+ {
+ if (!this._capturing)
+ return;
+ this._lastTraceLog.captureResource(resource);
+ for (var i = 0, n = args.length; i < n; ++i) {
+ var res = Resource.forObject(args[i]);
+ if (res)
+ this._lastTraceLog.captureResource(res);
+ }
+ },
+
+ /**
+ * @param {!Call} call
+ */
+ captureCall: function(call)
+ {
+ if (!this._capturing)
+ return;
+ this._lastTraceLog.addCall(call);
+ },
+
+ markFrameEnd: function()
+ {
+ if (!this._lastTraceLog)
+ return;
+ this._lastTraceLog.addFrameEndMark();
+ if (this._stopCapturingOnFrameEnd && this._lastTraceLog.size())
+ this.stopCapturing(this._lastTraceLog);
+ }
+}
+
+/**
+ * @constructor
+ */
+var InjectedCanvasModule = function()
+{
+ /** @type {!ResourceTrackingManager} */
+ this._manager = new ResourceTrackingManager();
+ /** @type {number} */
+ this._lastTraceLogId = 0;
+ /** @type {!Object.<string, TraceLog>} */
+ this._traceLogs = {};
+ /** @type {!Object.<string, TraceLogPlayer>} */
+ this._traceLogPlayers = {};
+}
+
+InjectedCanvasModule.prototype = {
+ /**
+ * @param {!WebGLRenderingContext} glContext
+ * @return {Object}
+ */
+ wrapWebGLContext: function(glContext)
+ {
+ var resource = Resource.forObject(glContext) || new WebGLRenderingContextResource(glContext);
+ this._manager.registerResource(resource);
+ return resource.proxyObject();
+ },
+
+ /**
+ * @param {!CanvasRenderingContext2D} context
+ * @return {Object}
+ */
+ wrapCanvas2DContext: function(context)
+ {
+ var resource = Resource.forObject(context) || new CanvasRenderingContext2DResource(context);
+ this._manager.registerResource(resource);
+ return resource.proxyObject();
+ },
+
+ /**
+ * @return {CanvasAgent.TraceLogId}
+ */
+ captureFrame: function()
+ {
+ return this._callStartCapturingFunction(this._manager.captureFrame);
+ },
+
+ /**
+ * @return {CanvasAgent.TraceLogId}
+ */
+ startCapturing: function()
+ {
+ return this._callStartCapturingFunction(this._manager.startCapturing);
+ },
+
+ markFrameEnd: function()
+ {
+ this._manager.markFrameEnd();
+ },
+
+ /**
+ * @param {function(this:ResourceTrackingManager)} func
+ * @return {CanvasAgent.TraceLogId}
+ */
+ _callStartCapturingFunction: function(func)
+ {
+ var oldTraceLog = this._manager.lastTraceLog();
+ func.call(this._manager);
+ var traceLog = this._manager.lastTraceLog();
+ if (traceLog === oldTraceLog) {
+ for (var id in this._traceLogs) {
+ if (this._traceLogs[id] === traceLog)
+ return id;
+ }
+ }
+ var id = this._makeTraceLogId();
+ this._traceLogs[id] = traceLog;
+ return id;
+ },
+
+ /**
+ * @param {CanvasAgent.TraceLogId} id
+ */
+ stopCapturing: function(id)
+ {
+ var traceLog = this._traceLogs[id];
+ if (traceLog)
+ this._manager.stopCapturing(traceLog);
+ },
+
+ /**
+ * @param {CanvasAgent.TraceLogId} id
+ */
+ dropTraceLog: function(id)
+ {
+ var traceLog = this._traceLogs[id];
+ if (traceLog)
+ this._manager.dropTraceLog(traceLog);
+ delete this._traceLogs[id];
+ delete this._traceLogPlayers[id];
+ },
+
+ /**
+ * @param {CanvasAgent.TraceLogId} id
+ * @param {number=} startOffset
+ * @param {number=} maxLength
+ * @return {!CanvasAgent.TraceLog|string}
+ */
+ traceLog: function(id, startOffset, maxLength)
+ {
+ var traceLog = this._traceLogs[id];
+ if (!traceLog)
+ return "Error: Trace log with the given ID not found.";
+
+ // Ensure last call ends a frame.
+ traceLog.addFrameEndMark();
+
+ var replayableCalls = traceLog.replayableCalls();
+ if (typeof startOffset !== "number")
+ startOffset = 0;
+ if (typeof maxLength !== "number")
+ maxLength = replayableCalls.length;
+
+ var fromIndex = Math.max(0, startOffset);
+ var toIndex = Math.min(replayableCalls.length - 1, fromIndex + maxLength - 1);
+
+ var alive = this._manager.capturing() && this._manager.lastTraceLog() === traceLog;
+ var result = {
+ id: id,
+ /** @type {Array.<CanvasAgent.Call>} */
+ calls: [],
+ alive: alive,
+ startOffset: fromIndex,
+ totalAvailableCalls: replayableCalls.length
+ };
+ for (var i = fromIndex; i <= toIndex; ++i) {
+ var call = replayableCalls[i];
+ var contextResource = call.replayableResource().replayableContextResource();
+ var stackTrace = call.stackTrace();
+ var callFrame = stackTrace ? stackTrace.callFrame(0) || {} : {};
+ var item = CallFormatter.formatCall(call);
+ item.contextId = this._makeStringResourceId(contextResource.id());
+ item.sourceURL = callFrame.sourceURL;
+ item.lineNumber = callFrame.lineNumber;
+ item.columnNumber = callFrame.columnNumber;
+ item.isFrameEndCall = traceLog.isFrameEndCallAt(i);
+ result.calls.push(item);
+ }
+ return result;
+ },
+
+ /**
+ * @param {*} obj
+ * @return {!CanvasAgent.CallArgument}
+ */
+ _makeCallArgument: function(obj)
+ {
+ if (obj instanceof ReplayableResource)
+ var description = obj.description();
+ else
+ var description = "" + obj;
+ return { description: description };
+ },
+
+ /**
+ * @param {CanvasAgent.TraceLogId} traceLogId
+ * @param {number} stepNo
+ * @return {!CanvasAgent.ResourceState|string}
+ */
+ replayTraceLog: function(traceLogId, stepNo)
+ {
+ var traceLog = this._traceLogs[traceLogId];
+ if (!traceLog)
+ return "Error: Trace log with the given ID not found.";
+ this._traceLogPlayers[traceLogId] = this._traceLogPlayers[traceLogId] || new TraceLogPlayer(traceLog);
+ var lastCall = this._traceLogPlayers[traceLogId].stepTo(stepNo);
+ var resource = lastCall.resource();
+ var dataURL = resource.toDataURL();
+ if (!dataURL) {
+ resource = resource.contextResource();
+ dataURL = resource.toDataURL();
+ }
+ return this._makeResourceState(this._makeStringResourceId(resource.id()), traceLogId, dataURL);
+ },
+
+ /**
+ * @param {CanvasAgent.ResourceId} stringResourceId
+ * @return {!CanvasAgent.ResourceInfo|string}
+ */
+ resourceInfo: function(stringResourceId)
+ {
+ var resourceId = this._parseStringId(stringResourceId).resourceId;
+ if (!resourceId)
+ return "Error: Wrong resource ID: " + stringResourceId;
+
+ var replayableResource = null;
+ for (var id in this._traceLogs) {
+ replayableResource = this._traceLogs[id].replayableResource(resourceId);
+ if (replayableResource)
+ break;
+ }
+ if (!replayableResource)
+ return "Error: Resource with the given ID not found.";
+
+ return this._makeResourceInfo(stringResourceId, replayableResource.description());
+ },
+
+ /**
+ * @param {CanvasAgent.TraceLogId} traceLogId
+ * @param {CanvasAgent.ResourceId} stringResourceId
+ * @return {!CanvasAgent.ResourceState|string}
+ */
+ resourceState: function(traceLogId, stringResourceId)
+ {
+ var traceLog = this._traceLogs[traceLogId];
+ if (!traceLog)
+ return "Error: Trace log with the given ID not found.";
+
+ var traceLogPlayer = this._traceLogPlayers[traceLogId];
+ if (!traceLogPlayer)
+ return "Error: Trace log replay has not started yet.";
+
+ var parsedStringId1 = this._parseStringId(traceLogId);
+ var parsedStringId2 = this._parseStringId(stringResourceId);
+ if (parsedStringId1.injectedScriptId !== parsedStringId2.injectedScriptId)
+ return "Error: Both IDs must point to the same injected script.";
+
+ var resourceId = parsedStringId2.resourceId;
+ if (!resourceId)
+ return "Error: Wrong resource ID: " + stringResourceId;
+
+ var resource = traceLogPlayer.replayWorldResource(resourceId);
+ if (!resource)
+ return "Error: Resource with the given ID has not been replayed yet.";
+
+ return this._makeResourceState(stringResourceId, traceLogId, resource.toDataURL());
+ },
+
+ /**
+ * @return {CanvasAgent.TraceLogId}
+ */
+ _makeTraceLogId: function()
+ {
+ return "{\"injectedScriptId\":" + injectedScriptId + ",\"traceLogId\":" + (++this._lastTraceLogId) + "}";
+ },
+
+ /**
+ * @param {number} resourceId
+ * @return {CanvasAgent.ResourceId}
+ */
+ _makeStringResourceId: function(resourceId)
+ {
+ return "{\"injectedScriptId\":" + injectedScriptId + ",\"resourceId\":" + resourceId + "}";
+ },
+
+ /**
+ * @param {CanvasAgent.ResourceId} stringResourceId
+ * @param {string} description
+ * @return {!CanvasAgent.ResourceInfo}
+ */
+ _makeResourceInfo: function(stringResourceId, description)
+ {
+ return {
+ id: stringResourceId,
+ description: description
+ };
+ },
+
+ /**
+ * @param {CanvasAgent.ResourceId} stringResourceId
+ * @param {CanvasAgent.TraceLogId} traceLogId
+ * @param {string} imageURL
+ * @return {!CanvasAgent.ResourceState}
+ */
+ _makeResourceState: function(stringResourceId, traceLogId, imageURL)
+ {
+ return {
+ id: stringResourceId,
+ traceLogId: traceLogId,
+ imageURL: imageURL
+ };
+ },
+
+ /**
+ * @param {string} stringId
+ * @return {{injectedScriptId: number, traceLogId: ?number, resourceId: ?number}}
+ */
+ _parseStringId: function(stringId)
+ {
+ return InjectedScriptHost.evaluate("(" + stringId + ")");
+ }
+}
+
+var injectedCanvasModule = new InjectedCanvasModule();
+return injectedCanvasModule;
+
+})
diff --git a/Source/core/inspector/InjectedScriptExterns.js b/Source/core/inspector/InjectedScriptExterns.js
new file mode 100644
index 0000000..d6d1a78
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptExterns.js
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+// WebKit Web Facing API
+var console = { }
+/** @param {...*} vararg */
+console.log = function(vararg) { }
+/** @param {...*} vararg */
+console.table = function(vararg) { }
+
+/**
+ * @constructor
+ */
+function InjectedScriptHost() { }
+InjectedScriptHost.prototype.storageId = function(object) { }
+InjectedScriptHost.prototype.getInternalProperties = function(object) { }
+/**
+ * @param {Function} func
+ */
+InjectedScriptHost.prototype.functionDetails = function(func) { }
+/**
+ * @param {*} object
+ */
+InjectedScriptHost.prototype.isHTMLAllCollection = function(object) { }
+/**
+ * @param {*} object
+ */
+InjectedScriptHost.prototype.internalConstructorName = function(object) { }
+/**
+ * @param {*} object
+ */
+InjectedScriptHost.prototype.copyText = function(object) { }
+InjectedScriptHost.prototype.clearConsoleMessages = function() { }
+/**
+ * @param {number} index
+ */
+InjectedScriptHost.prototype.inspectedObject = function(index) { }
+/**
+ * @param {*} object
+ * @return {number}
+ */
+InjectedScriptHost.prototype.objectId = function(object) { }
+/**
+ * @param {*} object
+ */
+InjectedScriptHost.prototype.releaseObjectId = function(object) { }
+/**
+ * @param {*} object
+ */
+InjectedScriptHost.prototype.databaseId = function(object) { }
+/**
+ * @param {*} object
+ * @param {Object} hints
+ */
+InjectedScriptHost.prototype.inspect = function(object, hints) { }
+/**
+ * @param {*} object
+ */
+InjectedScriptHost.prototype.type = function(object) { }
+/**
+ * @param {*} object
+ */
+InjectedScriptHost.prototype.getEventListeners = function(object) { }
+/**
+ * @param {string} expression
+ */
+InjectedScriptHost.prototype.evaluate = function(expression) { }
+
+/**
+ * @param {function(...)} fun
+ * @param {number} scopeNumber
+ * @param {string} variableName
+ * @param {*} newValue
+ */
+InjectedScriptHost.prototype.setFunctionVariableValue = function(fun, scopeNumber, variableName, newValue) { }
+
+/**
+ * @constructor
+ */
+function JavaScriptCallFrame()
+{
+ /** @type {number} */
+ this.sourceID;
+ /** @type {number} */
+ this.line;
+ /** @type {number} */
+ this.column;
+ /** @type {*} */
+ this.thisObject;
+}
+
+/**
+ * @param {number} index
+ */
+JavaScriptCallFrame.prototype.scopeType = function(index) { }
+
+JavaScriptCallFrame.prototype.restart = function() { }
+
+/**
+ * @param {number} scopeNumber
+ * @param {string} variableName
+ * @param {*} newValue
+ */
+JavaScriptCallFrame.prototype.setVariableValue = function(scopeNumber, variableName, newValue) {}
+
+/**
+ * @constructor
+ */
+function JavaScriptFunction()
+{
+ /** @type {Array} */
+ this.rawScopes;
+}
+
+var InspectorBackend = { };
+
+// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
+/**
+ * @constructor
+ */
+function CallSite()
+{
+}
+/**
+ * @return {string}
+ */
+CallSite.prototype.getFileName = function() { }
+/**
+ * @return {number}
+ */
+CallSite.prototype.getLineNumber = function() { }
+/**
+ * @return {number}
+ */
+CallSite.prototype.getColumnNumber = function() { }
diff --git a/Source/core/inspector/InjectedScriptHost.cpp b/Source/core/inspector/InjectedScriptHost.cpp
new file mode 100644
index 0000000..b530f6a
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptHost.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ * Copyright (C) 2010 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InjectedScriptHost.h"
+
+#include "InspectorFrontend.h"
+#include "core/dom/Element.h"
+#include "core/html/HTMLFrameOwnerElement.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InspectorAgent.h"
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorConsoleAgent.h"
+#include "core/inspector/InspectorDOMAgent.h"
+#include "core/inspector/InspectorDOMStorageAgent.h"
+#include "core/inspector/InspectorDatabaseAgent.h"
+#include "core/inspector/InspectorDebuggerAgent.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/loader/FrameLoader.h"
+#include "core/page/Frame.h"
+#include "core/platform/Pasteboard.h"
+#include "core/storage/Storage.h"
+#include "modules/webdatabase/Database.h"
+
+
+#include "core/editing/markup.h"
+
+#include <wtf/RefPtr.h>
+#include <wtf/StdLibExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+PassRefPtr<InjectedScriptHost> InjectedScriptHost::create()
+{
+ return adoptRef(new InjectedScriptHost());
+}
+
+InjectedScriptHost::InjectedScriptHost()
+ : m_inspectorAgent(0)
+ , m_consoleAgent(0)
+ , m_databaseAgent(0)
+ , m_domStorageAgent(0)
+ , m_domAgent(0)
+{
+ m_defaultInspectableObject = adoptPtr(new InspectableObject());
+}
+
+InjectedScriptHost::~InjectedScriptHost()
+{
+}
+
+void InjectedScriptHost::disconnect()
+{
+ m_inspectorAgent = 0;
+ m_consoleAgent = 0;
+ m_databaseAgent = 0;
+ m_domStorageAgent = 0;
+ m_domAgent = 0;
+}
+
+void InjectedScriptHost::inspectImpl(PassRefPtr<InspectorValue> object, PassRefPtr<InspectorValue> hints)
+{
+ if (m_inspectorAgent) {
+ RefPtr<TypeBuilder::Runtime::RemoteObject> remoteObject = TypeBuilder::Runtime::RemoteObject::runtimeCast(object);
+ m_inspectorAgent->inspect(remoteObject, hints->asObject());
+ }
+}
+
+void InjectedScriptHost::getEventListenersImpl(Node* node, Vector<EventListenerInfo>& listenersArray)
+{
+ if (m_domAgent)
+ m_domAgent->getEventListeners(node, listenersArray, false);
+}
+
+void InjectedScriptHost::clearConsoleMessages()
+{
+ if (m_consoleAgent) {
+ ErrorString error;
+ m_consoleAgent->clearMessages(&error);
+ }
+}
+
+void InjectedScriptHost::copyText(const String& text)
+{
+ Pasteboard::generalPasteboard()->writePlainText(text, Pasteboard::CannotSmartReplace);
+}
+
+ScriptValue InjectedScriptHost::InspectableObject::get(ScriptState*)
+{
+ return ScriptValue();
+};
+
+void InjectedScriptHost::addInspectedObject(PassOwnPtr<InjectedScriptHost::InspectableObject> object)
+{
+ m_inspectedObjects.prepend(object);
+ while (m_inspectedObjects.size() > 5)
+ m_inspectedObjects.removeLast();
+}
+
+void InjectedScriptHost::clearInspectedObjects()
+{
+ m_inspectedObjects.clear();
+}
+
+InjectedScriptHost::InspectableObject* InjectedScriptHost::inspectedObject(unsigned int num)
+{
+ if (num >= m_inspectedObjects.size())
+ return m_defaultInspectableObject.get();
+ return m_inspectedObjects[num].get();
+}
+
+String InjectedScriptHost::databaseIdImpl(Database* database)
+{
+ if (m_databaseAgent)
+ return m_databaseAgent->databaseId(database);
+ return String();
+}
+
+String InjectedScriptHost::storageIdImpl(Storage* storage)
+{
+ if (m_domStorageAgent)
+ return m_domStorageAgent->storageId(storage);
+ return String();
+}
+
+ScriptDebugServer& InjectedScriptHost::scriptDebugServer()
+{
+ return m_debuggerAgent->scriptDebugServer();
+}
+
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InjectedScriptHost.h b/Source/core/inspector/InjectedScriptHost.h
new file mode 100644
index 0000000..7c63ae3
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptHost.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InjectedScriptHost_h
+#define InjectedScriptHost_h
+
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/InspectorAgent.h"
+#include "core/page/ConsoleTypes.h"
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Database;
+class InjectedScript;
+class InspectorAgent;
+class InspectorConsoleAgent;
+class InspectorDOMAgent;
+class InspectorDOMStorageAgent;
+class InspectorDatabaseAgent;
+class InspectorDebuggerAgent;
+class InspectorFrontend;
+class InspectorObject;
+class InspectorValue;
+class Node;
+class ScriptDebugServer;
+class ScriptObject;
+class ScriptValue;
+class Storage;
+
+struct EventListenerInfo;
+
+class InjectedScriptHost : public RefCounted<InjectedScriptHost> {
+public:
+ static PassRefPtr<InjectedScriptHost> create();
+ ~InjectedScriptHost();
+
+ void init(InspectorAgent* inspectorAgent
+ , InspectorConsoleAgent* consoleAgent
+ , InspectorDatabaseAgent* databaseAgent
+ , InspectorDOMStorageAgent* domStorageAgent
+ , InspectorDOMAgent* domAgent
+ , InspectorDebuggerAgent* debuggerAgent
+ )
+ {
+ m_inspectorAgent = inspectorAgent;
+ m_consoleAgent = consoleAgent;
+ m_databaseAgent = databaseAgent;
+ m_domStorageAgent = domStorageAgent;
+ m_domAgent = domAgent;
+ m_debuggerAgent = debuggerAgent;
+ }
+
+ static Node* scriptValueAsNode(ScriptValue);
+ static ScriptValue nodeAsScriptValue(ScriptState*, Node*);
+
+ void disconnect();
+
+ class InspectableObject {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ virtual ScriptValue get(ScriptState*);
+ virtual ~InspectableObject() { }
+ };
+ void addInspectedObject(PassOwnPtr<InspectableObject>);
+ void clearInspectedObjects();
+ InspectableObject* inspectedObject(unsigned int num);
+
+ void inspectImpl(PassRefPtr<InspectorValue> objectToInspect, PassRefPtr<InspectorValue> hints);
+ void getEventListenersImpl(Node*, Vector<EventListenerInfo>& listenersArray);
+
+ void clearConsoleMessages();
+ void copyText(const String& text);
+ String databaseIdImpl(Database*);
+ String storageIdImpl(Storage*);
+
+ ScriptDebugServer& scriptDebugServer();
+
+private:
+ InjectedScriptHost();
+
+ InspectorAgent* m_inspectorAgent;
+ InspectorConsoleAgent* m_consoleAgent;
+ InspectorDatabaseAgent* m_databaseAgent;
+ InspectorDOMStorageAgent* m_domStorageAgent;
+ InspectorDOMAgent* m_domAgent;
+ InspectorDebuggerAgent* m_debuggerAgent;
+ Vector<OwnPtr<InspectableObject> > m_inspectedObjects;
+ OwnPtr<InspectableObject> m_defaultInspectableObject;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InjectedScriptHost_h)
diff --git a/Source/core/inspector/InjectedScriptHost.idl b/Source/core/inspector/InjectedScriptHost.idl
new file mode 100644
index 0000000..b285d67
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptHost.idl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ * Copyright (C) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+[
+ ImplementationLacksVTable
+] interface InjectedScriptHost {
+ void clearConsoleMessages();
+
+ void copyText(DOMString text);
+ [Custom] void inspect(any objectId, any hints);
+ [Custom] any inspectedObject(long num);
+ [Custom] any internalConstructorName(any object);
+ [Custom] boolean isHTMLAllCollection(any object);
+ [Custom] DOMString type(any object);
+ [Custom] any functionDetails(any object);
+ [Custom] Array getInternalProperties(any object);
+ [Custom] Array getEventListeners(Node node);
+ [Custom] any evaluate(DOMString text);
+ [Custom] DOMString databaseId(any database);
+ [Custom] DOMString storageId(any storage);
+
+ // Only declarative scope (local, with and catch) is accepted. Returns undefined.
+ [Custom] any setFunctionVariableValue(any functionObject, int scopeIndex, DOMString variableName, any newValue);
+};
diff --git a/Source/core/inspector/InjectedScriptManager.cpp b/Source/core/inspector/InjectedScriptManager.cpp
new file mode 100644
index 0000000..8ea669c
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptManager.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ * Copyright (C) 2012 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InjectedScriptManager.h"
+
+#include "InjectedScriptSource.h"
+#include "bindings/v8/ScriptObject.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptHost.h"
+#include "core/inspector/InspectorValues.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<InjectedScriptManager> InjectedScriptManager::createForPage()
+{
+ return adoptPtr(new InjectedScriptManager(&InjectedScriptManager::canAccessInspectedWindow));
+}
+
+PassOwnPtr<InjectedScriptManager> InjectedScriptManager::createForWorker()
+{
+ return adoptPtr(new InjectedScriptManager(&InjectedScriptManager::canAccessInspectedWorkerContext));
+}
+
+InjectedScriptManager::InjectedScriptManager(InspectedStateAccessCheck accessCheck)
+ : m_nextInjectedScriptId(1)
+ , m_injectedScriptHost(InjectedScriptHost::create())
+ , m_inspectedStateAccessCheck(accessCheck)
+{
+}
+
+InjectedScriptManager::~InjectedScriptManager()
+{
+}
+
+void InjectedScriptManager::disconnect()
+{
+ m_injectedScriptHost->disconnect();
+ m_injectedScriptHost.clear();
+}
+
+InjectedScriptHost* InjectedScriptManager::injectedScriptHost()
+{
+ return m_injectedScriptHost.get();
+}
+
+InjectedScript InjectedScriptManager::injectedScriptForId(int id)
+{
+ IdToInjectedScriptMap::iterator it = m_idToInjectedScript.find(id);
+ if (it != m_idToInjectedScript.end())
+ return it->value;
+ for (ScriptStateToId::iterator it = m_scriptStateToId.begin(); it != m_scriptStateToId.end(); ++it) {
+ if (it->value == id)
+ return injectedScriptFor(it->key);
+ }
+ return InjectedScript();
+}
+
+int InjectedScriptManager::injectedScriptIdFor(ScriptState* scriptState)
+{
+ ScriptStateToId::iterator it = m_scriptStateToId.find(scriptState);
+ if (it != m_scriptStateToId.end())
+ return it->value;
+ int id = m_nextInjectedScriptId++;
+ m_scriptStateToId.set(scriptState, id);
+ return id;
+}
+
+InjectedScript InjectedScriptManager::injectedScriptForObjectId(const String& objectId)
+{
+ RefPtr<InspectorValue> parsedObjectId = InspectorValue::parseJSON(objectId);
+ if (parsedObjectId && parsedObjectId->type() == InspectorValue::TypeObject) {
+ long injectedScriptId = 0;
+ bool success = parsedObjectId->asObject()->getNumber("injectedScriptId", &injectedScriptId);
+ if (success)
+ return m_idToInjectedScript.get(injectedScriptId);
+ }
+ return InjectedScript();
+}
+
+void InjectedScriptManager::discardInjectedScripts()
+{
+ m_idToInjectedScript.clear();
+ m_scriptStateToId.clear();
+}
+
+void InjectedScriptManager::discardInjectedScriptsFor(DOMWindow* window)
+{
+ if (m_scriptStateToId.isEmpty())
+ return;
+
+ Vector<long> idsToRemove;
+ IdToInjectedScriptMap::iterator end = m_idToInjectedScript.end();
+ for (IdToInjectedScriptMap::iterator it = m_idToInjectedScript.begin(); it != end; ++it) {
+ ScriptState* scriptState = it->value.scriptState();
+ if (window != domWindowFromScriptState(scriptState))
+ continue;
+ m_scriptStateToId.remove(scriptState);
+ idsToRemove.append(it->key);
+ }
+
+ for (size_t i = 0; i < idsToRemove.size(); i++)
+ m_idToInjectedScript.remove(idsToRemove[i]);
+
+ // Now remove script states that have id but no injected script.
+ Vector<ScriptState*> scriptStatesToRemove;
+ for (ScriptStateToId::iterator it = m_scriptStateToId.begin(); it != m_scriptStateToId.end(); ++it) {
+ ScriptState* scriptState = it->key;
+ if (window == domWindowFromScriptState(scriptState))
+ scriptStatesToRemove.append(scriptState);
+ }
+ for (size_t i = 0; i < scriptStatesToRemove.size(); i++)
+ m_scriptStateToId.remove(scriptStatesToRemove[i]);
+}
+
+bool InjectedScriptManager::canAccessInspectedWorkerContext(ScriptState*)
+{
+ return true;
+}
+
+void InjectedScriptManager::releaseObjectGroup(const String& objectGroup)
+{
+ for (IdToInjectedScriptMap::iterator it = m_idToInjectedScript.begin(); it != m_idToInjectedScript.end(); ++it)
+ it->value.releaseObjectGroup(objectGroup);
+}
+
+String InjectedScriptManager::injectedScriptSource()
+{
+ return String(reinterpret_cast<const char*>(InjectedScriptSource_js), sizeof(InjectedScriptSource_js));
+}
+
+InjectedScript InjectedScriptManager::injectedScriptFor(ScriptState* inspectedScriptState)
+{
+ ScriptStateToId::iterator it = m_scriptStateToId.find(inspectedScriptState);
+ if (it != m_scriptStateToId.end()) {
+ IdToInjectedScriptMap::iterator it1 = m_idToInjectedScript.find(it->value);
+ if (it1 != m_idToInjectedScript.end())
+ return it1->value;
+ }
+
+ if (!m_inspectedStateAccessCheck(inspectedScriptState))
+ return InjectedScript();
+
+ int id = injectedScriptIdFor(inspectedScriptState);
+ ScriptObject injectedScriptObject = createInjectedScript(injectedScriptSource(), inspectedScriptState, id);
+ InjectedScript result(injectedScriptObject, m_inspectedStateAccessCheck);
+ m_idToInjectedScript.set(id, result);
+ return result;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InjectedScriptManager.h b/Source/core/inspector/InjectedScriptManager.h
new file mode 100644
index 0000000..e048e93
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptManager.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InjectedScriptManager_h
+#define InjectedScriptManager_h
+
+#include "bindings/v8/ScriptState.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class DOMWindow;
+class InjectedScript;
+class InjectedScriptHost;
+class InspectorObject;
+class ScriptObject;
+
+class InjectedScriptManager {
+ WTF_MAKE_NONCOPYABLE(InjectedScriptManager); WTF_MAKE_FAST_ALLOCATED;
+public:
+ static PassOwnPtr<InjectedScriptManager> createForPage();
+ static PassOwnPtr<InjectedScriptManager> createForWorker();
+ ~InjectedScriptManager();
+
+ void disconnect();
+
+ InjectedScriptHost* injectedScriptHost();
+
+ InjectedScript injectedScriptFor(ScriptState*);
+ InjectedScript injectedScriptForId(int);
+ int injectedScriptIdFor(ScriptState*);
+ InjectedScript injectedScriptForObjectId(const String& objectId);
+ void discardInjectedScripts();
+ void discardInjectedScriptsFor(DOMWindow*);
+ void releaseObjectGroup(const String& objectGroup);
+
+ typedef bool (*InspectedStateAccessCheck)(ScriptState*);
+ InspectedStateAccessCheck inspectedStateAccessCheck() const { return m_inspectedStateAccessCheck; }
+
+private:
+ explicit InjectedScriptManager(InspectedStateAccessCheck);
+
+ String injectedScriptSource();
+ ScriptObject createInjectedScript(const String& source, ScriptState*, int id);
+
+ static bool canAccessInspectedWindow(ScriptState*);
+ static bool canAccessInspectedWorkerContext(ScriptState*);
+
+ int m_nextInjectedScriptId;
+ typedef HashMap<int, InjectedScript> IdToInjectedScriptMap;
+ IdToInjectedScriptMap m_idToInjectedScript;
+ RefPtr<InjectedScriptHost> m_injectedScriptHost;
+ InspectedStateAccessCheck m_inspectedStateAccessCheck;
+ typedef HashMap<ScriptState*, int> ScriptStateToId;
+ ScriptStateToId m_scriptStateToId;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InjectedScriptManager_h)
diff --git a/Source/core/inspector/InjectedScriptModule.cpp b/Source/core/inspector/InjectedScriptModule.cpp
new file mode 100644
index 0000000..f95a476
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptModule.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InjectedScriptModule.h"
+
+#include "bindings/v8/ScriptFunctionCall.h"
+#include "bindings/v8/ScriptObject.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptManager.h"
+
+namespace WebCore {
+
+InjectedScriptModule::InjectedScriptModule(const String& name)
+ : InjectedScriptBase(name)
+{
+}
+
+void InjectedScriptModule::ensureInjected(InjectedScriptManager* injectedScriptManager, ScriptState* scriptState)
+{
+ InjectedScript injectedScript = injectedScriptManager->injectedScriptFor(scriptState);
+ ASSERT(!injectedScript.hasNoValue());
+ if (injectedScript.hasNoValue())
+ return;
+
+ // FIXME: Make the InjectedScript a module itself.
+ ScriptFunctionCall function(injectedScript.injectedScriptObject(), "module");
+ function.appendArgument(name());
+ bool hadException = false;
+ ScriptValue resultValue = injectedScript.callFunctionWithEvalEnabled(function, hadException);
+ ASSERT(!hadException);
+ if (hadException || resultValue.hasNoValue() || !resultValue.isObject()) {
+ ScriptFunctionCall function(injectedScript.injectedScriptObject(), "injectModule");
+ function.appendArgument(name());
+ function.appendArgument(source());
+ resultValue = injectedScript.callFunctionWithEvalEnabled(function, hadException);
+ if (hadException || resultValue.hasNoValue() || !resultValue.isObject()) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ }
+
+ ScriptObject moduleObject(scriptState, resultValue);
+ initialize(moduleObject, injectedScriptManager->inspectedStateAccessCheck());
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InjectedScriptModule.h b/Source/core/inspector/InjectedScriptModule.h
new file mode 100644
index 0000000..b4295a2
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptModule.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InjectedScriptModule_h
+#define InjectedScriptModule_h
+
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/InjectedScriptBase.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InjectedScriptManager;
+
+
+class InjectedScriptModule : public InjectedScriptBase {
+public:
+ virtual String source() const = 0;
+
+protected:
+ // Do not expose constructor in the child classes as well. Instead provide
+ // a static factory method that would create a new instance of the class
+ // and call its ensureInjected() method immediately.
+ InjectedScriptModule(const String& name);
+ void ensureInjected(InjectedScriptManager*, ScriptState*);
+};
+
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/inspector/InjectedScriptSource.js b/Source/core/inspector/InjectedScriptSource.js
new file mode 100644
index 0000000..34e163e
--- /dev/null
+++ b/Source/core/inspector/InjectedScriptSource.js
@@ -0,0 +1,1364 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+/**
+ * @param {InjectedScriptHost} InjectedScriptHost
+ * @param {Window} inspectedWindow
+ * @param {number} injectedScriptId
+ */
+(function (InjectedScriptHost, inspectedWindow, injectedScriptId) {
+
+// Protect against Object overwritten by the user code.
+var Object = {}.constructor;
+
+/**
+ * @param {Arguments} array
+ * @param {number=} index
+ * @return {Array.<*>}
+ */
+function slice(array, index)
+{
+ var result = [];
+ for (var i = index || 0; i < array.length; ++i)
+ result.push(array[i]);
+ return result;
+}
+
+/**
+ * Please use this bind, not the one from Function.prototype
+ * @param {function(...)} func
+ * @param {Object} thisObject
+ * @param {...number} var_args
+ */
+function bind(func, thisObject, var_args)
+{
+ var args = slice(arguments, 2);
+
+ /**
+ * @param {...number} var_args
+ */
+ function bound(var_args)
+ {
+ return func.apply(thisObject, args.concat(slice(arguments)));
+ }
+ bound.toString = function() {
+ return "bound: " + func;
+ };
+ return bound;
+}
+
+/**
+ * @constructor
+ */
+var InjectedScript = function()
+{
+ this._lastBoundObjectId = 1;
+ this._idToWrappedObject = {};
+ this._idToObjectGroupName = {};
+ this._objectGroups = {};
+ this._modules = {};
+}
+
+/**
+ * @type {Object.<string, boolean>}
+ * @const
+ */
+InjectedScript.primitiveTypes = {
+ undefined: true,
+ boolean: true,
+ number: true,
+ string: true
+}
+
+InjectedScript.prototype = {
+ /**
+ * @param {*} object
+ * @return {boolean}
+ */
+ isPrimitiveValue: function(object)
+ {
+ // FIXME(33716): typeof document.all is always 'undefined'.
+ return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllCollection(object);
+ },
+
+ /**
+ * @param {*} object
+ * @param {string} groupName
+ * @param {boolean} canAccessInspectedWindow
+ * @param {boolean} generatePreview
+ * @return {!RuntimeAgent.RemoteObject}
+ */
+ wrapObject: function(object, groupName, canAccessInspectedWindow, generatePreview)
+ {
+ if (canAccessInspectedWindow)
+ return this._wrapObject(object, groupName, false, generatePreview);
+ return this._fallbackWrapper(object);
+ },
+
+ /**
+ * @param {*} object
+ * @return {!RuntimeAgent.RemoteObject}
+ */
+ _fallbackWrapper: function(object)
+ {
+ var result = {};
+ result.type = typeof object;
+ if (this.isPrimitiveValue(object))
+ result.value = object;
+ else
+ result.description = this._toString(object);
+ return /** @type {!RuntimeAgent.RemoteObject} */ (result);
+ },
+
+ /**
+ * @param {boolean} canAccessInspectedWindow
+ * @param {Object} table
+ * @param {Array.<string>|string|boolean} columns
+ * @return {!RuntimeAgent.RemoteObject}
+ */
+ wrapTable: function(canAccessInspectedWindow, table, columns)
+ {
+ if (!canAccessInspectedWindow)
+ return this._fallbackWrapper(table);
+ var columnNames = null;
+ if (typeof columns === "string")
+ columns = [columns];
+ if (InjectedScriptHost.type(columns) == "array") {
+ columnNames = [];
+ for (var i = 0; i < columns.length; ++i)
+ columnNames.push(String(columns[i]));
+ }
+ return this._wrapObject(table, "console", false, true, columnNames);
+ },
+
+ /**
+ * @param {*} object
+ */
+ inspectNode: function(object)
+ {
+ this._inspect(object);
+ },
+
+ /**
+ * @param {*} object
+ * @return {*}
+ */
+ _inspect: function(object)
+ {
+ if (arguments.length === 0)
+ return;
+
+ var objectId = this._wrapObject(object, "");
+ var hints = {};
+
+ switch (injectedScript._describe(object)) {
+ case "Database":
+ var databaseId = InjectedScriptHost.databaseId(object)
+ if (databaseId)
+ hints.databaseId = databaseId;
+ break;
+ case "Storage":
+ var storageId = InjectedScriptHost.storageId(object)
+ if (storageId)
+ hints.domStorageId = InjectedScriptHost.evaluate("(" + storageId + ")");
+ break;
+ }
+ InjectedScriptHost.inspect(objectId, hints);
+ return object;
+ },
+
+ /**
+ * This method cannot throw.
+ * @param {*} object
+ * @param {string=} objectGroupName
+ * @param {boolean=} forceValueType
+ * @param {boolean=} generatePreview
+ * @param {?Array.<string>=} columnNames
+ * @return {!RuntimeAgent.RemoteObject}
+ * @suppress {checkTypes}
+ */
+ _wrapObject: function(object, objectGroupName, forceValueType, generatePreview, columnNames)
+ {
+ try {
+ return new InjectedScript.RemoteObject(object, objectGroupName, forceValueType, generatePreview, columnNames);
+ } catch (e) {
+ try {
+ var description = injectedScript._describe(e);
+ } catch (ex) {
+ var description = "<failed to convert exception to string>";
+ }
+ return new InjectedScript.RemoteObject(description);
+ }
+ },
+
+ /**
+ * @param {*} object
+ * @param {string=} objectGroupName
+ * @return {string}
+ */
+ _bind: function(object, objectGroupName)
+ {
+ var id = this._lastBoundObjectId++;
+ this._idToWrappedObject[id] = object;
+ var objectId = "{\"injectedScriptId\":" + injectedScriptId + ",\"id\":" + id + "}";
+ if (objectGroupName) {
+ var group = this._objectGroups[objectGroupName];
+ if (!group) {
+ group = [];
+ this._objectGroups[objectGroupName] = group;
+ }
+ group.push(id);
+ this._idToObjectGroupName[id] = objectGroupName;
+ }
+ return objectId;
+ },
+
+ /**
+ * @param {string} objectId
+ * @return {Object}
+ */
+ _parseObjectId: function(objectId)
+ {
+ return InjectedScriptHost.evaluate("(" + objectId + ")");
+ },
+
+ /**
+ * @param {string} objectGroupName
+ */
+ releaseObjectGroup: function(objectGroupName)
+ {
+ var group = this._objectGroups[objectGroupName];
+ if (!group)
+ return;
+ for (var i = 0; i < group.length; i++)
+ this._releaseObject(group[i]);
+ delete this._objectGroups[objectGroupName];
+ },
+
+ /**
+ * @param {string} methodName
+ * @param {string} args
+ * @return {*}
+ */
+ dispatch: function(methodName, args)
+ {
+ var argsArray = InjectedScriptHost.evaluate("(" + args + ")");
+ var result = this[methodName].apply(this, argsArray);
+ if (typeof result === "undefined") {
+ inspectedWindow.console.error("Web Inspector error: InjectedScript.%s returns undefined", methodName);
+ result = null;
+ }
+ return result;
+ },
+
+ /**
+ * @param {string} objectId
+ * @param {boolean} ownProperties
+ * @return {Array.<RuntimeAgent.PropertyDescriptor>|boolean}
+ */
+ getProperties: function(objectId, ownProperties)
+ {
+ var parsedObjectId = this._parseObjectId(objectId);
+ var object = this._objectForId(parsedObjectId);
+ var objectGroupName = this._idToObjectGroupName[parsedObjectId.id];
+
+ if (!this._isDefined(object))
+ return false;
+ var descriptors = this._propertyDescriptors(object, ownProperties);
+
+ // Go over properties, wrap object values.
+ for (var i = 0; i < descriptors.length; ++i) {
+ var descriptor = descriptors[i];
+ if ("get" in descriptor)
+ descriptor.get = this._wrapObject(descriptor.get, objectGroupName);
+ if ("set" in descriptor)
+ descriptor.set = this._wrapObject(descriptor.set, objectGroupName);
+ if ("value" in descriptor)
+ descriptor.value = this._wrapObject(descriptor.value, objectGroupName);
+ if (!("configurable" in descriptor))
+ descriptor.configurable = false;
+ if (!("enumerable" in descriptor))
+ descriptor.enumerable = false;
+ }
+ return descriptors;
+ },
+
+ /**
+ * @param {string} objectId
+ * @return {Array.<Object>|boolean}
+ */
+ getInternalProperties: function(objectId, ownProperties)
+ {
+ var parsedObjectId = this._parseObjectId(objectId);
+ var object = this._objectForId(parsedObjectId);
+ var objectGroupName = this._idToObjectGroupName[parsedObjectId.id];
+ if (!this._isDefined(object))
+ return false;
+ var descriptors = [];
+ var internalProperties = InjectedScriptHost.getInternalProperties(object);
+ if (internalProperties) {
+ for (var i = 0; i < internalProperties.length; i++) {
+ var property = internalProperties[i];
+ var descriptor = {
+ name: property.name,
+ value: this._wrapObject(property.value, objectGroupName)
+ };
+ descriptors.push(descriptor);
+ }
+ }
+ return descriptors;
+ },
+
+ /**
+ * @param {string} functionId
+ * @return {!DebuggerAgent.FunctionDetails|string}
+ */
+ getFunctionDetails: function(functionId)
+ {
+ var parsedFunctionId = this._parseObjectId(functionId);
+ var func = this._objectForId(parsedFunctionId);
+ if (typeof func !== "function")
+ return "Cannot resolve function by id.";
+ var details = InjectedScriptHost.functionDetails(func);
+ if ("rawScopes" in details) {
+ var objectGroupName = this._idToObjectGroupName[parsedFunctionId.id];
+ var rawScopes = details.rawScopes;
+ var scopes = [];
+ delete details.rawScopes;
+ for (var i = 0; i < rawScopes.length; i++)
+ scopes.push(InjectedScript.CallFrameProxy._createScopeJson(rawScopes[i].type, rawScopes[i].object, objectGroupName));
+ details.scopeChain = scopes;
+ }
+ return details;
+ },
+
+ /**
+ * @param {string} objectId
+ */
+ releaseObject: function(objectId)
+ {
+ var parsedObjectId = this._parseObjectId(objectId);
+ this._releaseObject(parsedObjectId.id);
+ },
+
+ /**
+ * @param {string} id
+ */
+ _releaseObject: function(id)
+ {
+ delete this._idToWrappedObject[id];
+ delete this._idToObjectGroupName[id];
+ },
+
+ /**
+ * @param {Object} object
+ * @param {boolean} ownProperties
+ * @return {Array.<Object>}
+ */
+ _propertyDescriptors: function(object, ownProperties)
+ {
+ var descriptors = [];
+ var nameProcessed = {};
+ nameProcessed["__proto__"] = null;
+ for (var o = object; this._isDefined(o); o = o.__proto__) {
+ var names = Object.getOwnPropertyNames(/** @type {!Object} */ (o));
+ for (var i = 0; i < names.length; ++i) {
+ var name = names[i];
+ if (nameProcessed[name])
+ continue;
+
+ try {
+ nameProcessed[name] = true;
+ var descriptor = Object.getOwnPropertyDescriptor(/** @type {!Object} */ (object), name);
+ if (!descriptor) {
+ // Not all bindings provide proper descriptors. Fall back to the writable, configurable property.
+ try {
+ descriptor = { name: name, value: object[name], writable: false, configurable: false, enumerable: false};
+ if (o === object)
+ descriptor.isOwn = true;
+ descriptors.push(descriptor);
+ } catch (e) {
+ // Silent catch.
+ }
+ continue;
+ }
+ } catch (e) {
+ var descriptor = {};
+ descriptor.value = e;
+ descriptor.wasThrown = true;
+ }
+
+ descriptor.name = name;
+ if (o === object)
+ descriptor.isOwn = true;
+ descriptors.push(descriptor);
+ }
+ if (ownProperties) {
+ if (object.__proto__)
+ descriptors.push({ name: "__proto__", value: object.__proto__, writable: true, configurable: true, enumerable: false, isOwn: true});
+ break;
+ }
+ }
+ return descriptors;
+ },
+
+ /**
+ * @param {string} expression
+ * @param {string} objectGroup
+ * @param {boolean} injectCommandLineAPI
+ * @param {boolean} returnByValue
+ * @param {boolean} generatePreview
+ * @return {*}
+ */
+ evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
+ {
+ return this._evaluateAndWrap(InjectedScriptHost.evaluate, InjectedScriptHost, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview);
+ },
+
+ /**
+ * @param {string} objectId
+ * @param {string} expression
+ * @param {boolean} returnByValue
+ * @return {Object|string}
+ */
+ callFunctionOn: function(objectId, expression, args, returnByValue)
+ {
+ var parsedObjectId = this._parseObjectId(objectId);
+ var object = this._objectForId(parsedObjectId);
+ if (!this._isDefined(object))
+ return "Could not find object with given id";
+
+ if (args) {
+ var resolvedArgs = [];
+ args = InjectedScriptHost.evaluate(args);
+ for (var i = 0; i < args.length; ++i) {
+ var resolvedCallArgument;
+ try {
+ resolvedCallArgument = this._resolveCallArgument(args[i]);
+ } catch (e) {
+ return String(e);
+ }
+ resolvedArgs.push(resolvedCallArgument)
+ }
+ }
+
+ try {
+ var objectGroup = this._idToObjectGroupName[parsedObjectId.id];
+ var func = InjectedScriptHost.evaluate("(" + expression + ")");
+ if (typeof func !== "function")
+ return "Given expression does not evaluate to a function";
+
+ return { wasThrown: false,
+ result: this._wrapObject(func.apply(object, resolvedArgs), objectGroup, returnByValue) };
+ } catch (e) {
+ return this._createThrownValue(e, objectGroup);
+ }
+ },
+
+ /**
+ * Resolves a value from CallArgument description.
+ * @param {RuntimeAgent.CallArgument} callArgumentJson
+ * @return {*} resolved value
+ * @throws {string} error message
+ */
+ _resolveCallArgument: function(callArgumentJson) {
+ var objectId = callArgumentJson.objectId;
+ if (objectId) {
+ var parsedArgId = this._parseObjectId(objectId);
+ if (!parsedArgId || parsedArgId["injectedScriptId"] !== injectedScriptId)
+ throw "Arguments should belong to the same JavaScript world as the target object.";
+
+ var resolvedArg = this._objectForId(parsedArgId);
+ if (!this._isDefined(resolvedArg))
+ throw "Could not find object with given id";
+
+ return resolvedArg;
+ } else if ("value" in callArgumentJson)
+ return callArgumentJson.value;
+ else
+ return undefined;
+ },
+
+ /**
+ * @param {Function} evalFunction
+ * @param {Object} object
+ * @param {string} objectGroup
+ * @param {boolean} isEvalOnCallFrame
+ * @param {boolean} injectCommandLineAPI
+ * @param {boolean} returnByValue
+ * @param {boolean} generatePreview
+ * @return {*}
+ */
+ _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview)
+ {
+ try {
+ return { wasThrown: false,
+ result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI), objectGroup, returnByValue, generatePreview) };
+ } catch (e) {
+ return this._createThrownValue(e, objectGroup);
+ }
+ },
+
+ /**
+ * @param {*} value
+ * @param {string} objectGroup
+ * @return {Object}
+ */
+ _createThrownValue: function(value, objectGroup)
+ {
+ var remoteObject = this._wrapObject(value, objectGroup);
+ try {
+ remoteObject.description = this._toString(value);
+ } catch (e) {}
+ return { wasThrown: true,
+ result: remoteObject };
+ },
+
+ /**
+ * @param {Function} evalFunction
+ * @param {Object} object
+ * @param {string} objectGroup
+ * @param {string} expression
+ * @param {boolean} isEvalOnCallFrame
+ * @param {boolean} injectCommandLineAPI
+ * @return {*}
+ */
+ _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI)
+ {
+ // Only install command line api object for the time of evaluation.
+ // Surround the expression in with statements to inject our command line API so that
+ // the window object properties still take more precedent than our API functions.
+
+ try {
+ if (injectCommandLineAPI && inspectedWindow.console) {
+ inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null);
+ expression = "with ((window && window.console && window.console._commandLineAPI) || {}) {\n" + expression + "\n}";
+ }
+ var result = evalFunction.call(object, expression);
+ if (objectGroup === "console")
+ this._lastResult = result;
+ return result;
+ } finally {
+ if (injectCommandLineAPI && inspectedWindow.console)
+ delete inspectedWindow.console._commandLineAPI;
+ }
+ },
+
+ /**
+ * @param {Object} callFrame
+ * @return {Array.<InjectedScript.CallFrameProxy>|boolean}
+ */
+ wrapCallFrames: function(callFrame)
+ {
+ if (!callFrame)
+ return false;
+
+ var result = [];
+ var depth = 0;
+ do {
+ result.push(new InjectedScript.CallFrameProxy(depth++, callFrame));
+ callFrame = callFrame.caller;
+ } while (callFrame);
+ return result;
+ },
+
+ /**
+ * @param {Object} topCallFrame
+ * @param {string} callFrameId
+ * @param {string} expression
+ * @param {string} objectGroup
+ * @param {boolean} injectCommandLineAPI
+ * @param {boolean} returnByValue
+ * @param {boolean} generatePreview
+ * @return {*}
+ */
+ evaluateOnCallFrame: function(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
+ {
+ var callFrame = this._callFrameForId(topCallFrame, callFrameId);
+ if (!callFrame)
+ return "Could not find call frame with given id";
+ return this._evaluateAndWrap(callFrame.evaluate, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview);
+ },
+
+ /**
+ * @param {Object} topCallFrame
+ * @param {string} callFrameId
+ * @return {*}
+ */
+ restartFrame: function(topCallFrame, callFrameId)
+ {
+ var callFrame = this._callFrameForId(topCallFrame, callFrameId);
+ if (!callFrame)
+ return "Could not find call frame with given id";
+ var result = callFrame.restart();
+ if (result === false)
+ result = "Restart frame is not supported";
+ return result;
+ },
+
+ /**
+ * Either callFrameId or functionObjectId must be specified.
+ * @param {Object} topCallFrame
+ * @param {string|boolean} callFrameId or false
+ * @param {string|boolean} functionObjectId or false
+ * @param {number} scopeNumber
+ * @param {string} variableName
+ * @param {string} newValueJsonString RuntimeAgent.CallArgument structure serialized as string
+ * @return {string|undefined} undefined if success or an error message
+ */
+ setVariableValue: function(topCallFrame, callFrameId, functionObjectId, scopeNumber, variableName, newValueJsonString)
+ {
+ var setter;
+ if (typeof callFrameId === "string") {
+ var callFrame = this._callFrameForId(topCallFrame, callFrameId);
+ if (!callFrame)
+ return "Could not find call frame with given id";
+ setter = callFrame.setVariableValue.bind(callFrame);
+ } else {
+ var parsedFunctionId = this._parseObjectId(/** @type {string} */(functionObjectId));
+ var func = this._objectForId(parsedFunctionId);
+ if (typeof func !== "function")
+ return "Cannot resolve function by id.";
+ setter = InjectedScriptHost.setFunctionVariableValue.bind(InjectedScriptHost, func);
+ }
+ var newValueJson;
+ try {
+ newValueJson = InjectedScriptHost.evaluate("(" + newValueJsonString + ")");
+ } catch (e) {
+ return "Failed to parse new value JSON " + newValueJsonString + " : " + e;
+ }
+ var resolvedValue;
+ try {
+ resolvedValue = this._resolveCallArgument(newValueJson);
+ } catch (e) {
+ return String(e);
+ }
+ try {
+ setter(scopeNumber, variableName, resolvedValue);
+ } catch (e) {
+ return "Failed to change variable value: " + e;
+ }
+ return undefined;
+ },
+
+ /**
+ * @param {Object} topCallFrame
+ * @param {string} callFrameId
+ * @return {Object}
+ */
+ _callFrameForId: function(topCallFrame, callFrameId)
+ {
+ var parsedCallFrameId = InjectedScriptHost.evaluate("(" + callFrameId + ")");
+ var ordinal = parsedCallFrameId["ordinal"];
+ var callFrame = topCallFrame;
+ while (--ordinal >= 0 && callFrame)
+ callFrame = callFrame.caller;
+ return callFrame;
+ },
+
+ /**
+ * @param {Object} objectId
+ * @return {Object}
+ */
+ _objectForId: function(objectId)
+ {
+ return this._idToWrappedObject[objectId.id];
+ },
+
+ /**
+ * @param {string} objectId
+ * @return {Object}
+ */
+ findObjectById: function(objectId)
+ {
+ var parsedObjectId = this._parseObjectId(objectId);
+ return this._objectForId(parsedObjectId);
+ },
+
+ /**
+ * @param {string} objectId
+ * @return {Node}
+ */
+ nodeForObjectId: function(objectId)
+ {
+ var object = this.findObjectById(objectId);
+ if (!object || this._subtype(object) !== "node")
+ return null;
+ return /** @type {Node} */ (object);
+ },
+
+ /**
+ * @param {string} name
+ * @return {Object}
+ */
+ module: function(name)
+ {
+ return this._modules[name];
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} source
+ * @return {Object}
+ */
+ injectModule: function(name, source)
+ {
+ delete this._modules[name];
+ var moduleFunction = InjectedScriptHost.evaluate("(" + source + ")");
+ if (typeof moduleFunction !== "function") {
+ inspectedWindow.console.error("Web Inspector error: A function was expected for module %s evaluation", name);
+ return null;
+ }
+ var module = moduleFunction.call(inspectedWindow, InjectedScriptHost, inspectedWindow, injectedScriptId);
+ this._modules[name] = module;
+ return module;
+ },
+
+ /**
+ * @param {*} object
+ * @return {boolean}
+ */
+ _isDefined: function(object)
+ {
+ return !!object || this._isHTMLAllCollection(object);
+ },
+
+ /**
+ * @param {*} object
+ * @return {boolean}
+ */
+ _isHTMLAllCollection: function(object)
+ {
+ // document.all is reported as undefined, but we still want to process it.
+ return (typeof object === "undefined") && InjectedScriptHost.isHTMLAllCollection(object);
+ },
+
+ /**
+ * @param {Object=} obj
+ * @return {string?}
+ */
+ _subtype: function(obj)
+ {
+ if (obj === null)
+ return "null";
+
+ if (this.isPrimitiveValue(obj))
+ return null;
+
+ if (this._isHTMLAllCollection(obj))
+ return "array";
+
+ var preciseType = InjectedScriptHost.type(obj);
+ if (preciseType)
+ return preciseType;
+
+ // FireBug's array detection.
+ try {
+ if (typeof obj.splice === "function" && isFinite(obj.length))
+ return "array";
+ if (Object.prototype.toString.call(obj) === "[object Arguments]" && isFinite(obj.length)) // arguments.
+ return "array";
+ } catch (e) {
+ }
+
+ // If owning frame has navigated to somewhere else window properties will be undefined.
+ return null;
+ },
+
+ /**
+ * @param {*} obj
+ * @return {string?}
+ */
+ _describe: function(obj)
+ {
+ if (this.isPrimitiveValue(obj))
+ return null;
+
+ obj = /** @type {Object} */ (obj);
+
+ // Type is object, get subtype.
+ var subtype = this._subtype(obj);
+
+ if (subtype === "regexp")
+ return this._toString(obj);
+
+ if (subtype === "date")
+ return this._toString(obj);
+
+ if (subtype === "node") {
+ var description = obj.nodeName.toLowerCase();
+ switch (obj.nodeType) {
+ case 1 /* Node.ELEMENT_NODE */:
+ description += obj.id ? "#" + obj.id : "";
+ var className = obj.className;
+ description += className ? "." + className : "";
+ break;
+ case 10 /*Node.DOCUMENT_TYPE_NODE */:
+ description = "<!DOCTYPE " + description + ">";
+ break;
+ }
+ return description;
+ }
+
+ var className = InjectedScriptHost.internalConstructorName(obj);
+ if (subtype === "array") {
+ if (typeof obj.length === "number")
+ className += "[" + obj.length + "]";
+ return className;
+ }
+
+ // NodeList in JSC is a function, check for array prior to this.
+ if (typeof obj === "function")
+ return this._toString(obj);
+
+ if (className === "Object") {
+ // In Chromium DOM wrapper prototypes will have Object as their constructor name,
+ // get the real DOM wrapper name from the constructor property.
+ var constructorName = obj.constructor && obj.constructor.name;
+ if (constructorName)
+ return constructorName;
+ }
+ return className;
+ },
+
+ /**
+ * @param {*} obj
+ * @return {string}
+ */
+ _toString: function(obj)
+ {
+ // We don't use String(obj) because inspectedWindow.String is undefined if owning frame navigated to another page.
+ return "" + obj;
+ }
+}
+
+/**
+ * @type {InjectedScript}
+ * @const
+ */
+var injectedScript = new InjectedScript();
+
+/**
+ * @constructor
+ * @param {*} object
+ * @param {string=} objectGroupName
+ * @param {boolean=} forceValueType
+ * @param {boolean=} generatePreview
+ * @param {?Array.<string>=} columnNames
+ */
+InjectedScript.RemoteObject = function(object, objectGroupName, forceValueType, generatePreview, columnNames)
+{
+ this.type = typeof object;
+ if (injectedScript.isPrimitiveValue(object) || object === null || forceValueType) {
+ // We don't send undefined values over JSON.
+ if (typeof object !== "undefined")
+ this.value = object;
+
+ // Null object is object with 'null' subtype'
+ if (object === null)
+ this.subtype = "null";
+
+ // Provide user-friendly number values.
+ if (typeof object === "number")
+ this.description = object + "";
+ return;
+ }
+
+ object = /** @type {Object} */ (object);
+
+ this.objectId = injectedScript._bind(object, objectGroupName);
+ var subtype = injectedScript._subtype(object);
+ if (subtype)
+ this.subtype = subtype;
+ this.className = InjectedScriptHost.internalConstructorName(object);
+ this.description = injectedScript._describe(object);
+
+ if (generatePreview && (this.type === "object" || injectedScript._isHTMLAllCollection(object)))
+ this.preview = this._generatePreview(object, undefined, columnNames);
+}
+
+InjectedScript.RemoteObject.prototype = {
+ /**
+ * @param {Object} object
+ * @param {Array.<string>=} firstLevelKeys
+ * @param {?Array.<string>=} secondLevelKeys
+ * @return {Object} preview
+ */
+ _generatePreview: function(object, firstLevelKeys, secondLevelKeys)
+ {
+ var preview = {};
+ preview.lossless = true;
+ preview.overflow = false;
+ preview.properties = [];
+
+ var isTableRowsRequest = secondLevelKeys === null || secondLevelKeys;
+ var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0;
+
+ var propertiesThreshold = {
+ properties: isTableRowsRequest ? 1000 : Math.max(5, firstLevelKeysCount),
+ indexes: isTableRowsRequest ? 1000 : Math.max(100, firstLevelKeysCount)
+ };
+ for (var o = object; injectedScript._isDefined(o); o = o.__proto__)
+ this._generateProtoPreview(o, preview, propertiesThreshold, firstLevelKeys, secondLevelKeys);
+ return preview;
+ },
+
+ /**
+ * @param {Object} object
+ * @param {Object} preview
+ * @param {Object} propertiesThreshold
+ * @param {Array.<string>=} firstLevelKeys
+ * @param {Array.<string>=} secondLevelKeys
+ */
+ _generateProtoPreview: function(object, preview, propertiesThreshold, firstLevelKeys, secondLevelKeys)
+ {
+ var propertyNames = firstLevelKeys ? firstLevelKeys : Object.keys(/** @type {!Object} */(object));
+ try {
+ for (var i = 0; i < propertyNames.length; ++i) {
+ if (!propertiesThreshold.properties || !propertiesThreshold.indexes) {
+ preview.overflow = true;
+ preview.lossless = false;
+ break;
+ }
+ var name = propertyNames[i];
+ if (this.subtype === "array" && name === "length")
+ continue;
+
+ var descriptor = Object.getOwnPropertyDescriptor(/** @type {!Object} */(object), name);
+ if (!("value" in descriptor) || !descriptor.enumerable) {
+ preview.lossless = false;
+ continue;
+ }
+
+ var value = descriptor.value;
+ if (value === null) {
+ this._appendPropertyPreview(preview, { name: name, type: "object", value: "null" }, propertiesThreshold);
+ continue;
+ }
+
+ const maxLength = 100;
+ var type = typeof value;
+
+ if (InjectedScript.primitiveTypes[type]) {
+ if (type === "string") {
+ if (value.length > maxLength) {
+ value = this._abbreviateString(value, maxLength, true);
+ preview.lossless = false;
+ }
+ value = value.replace(/\n/g, "\u21B5");
+ }
+ this._appendPropertyPreview(preview, { name: name, type: type, value: value + "" }, propertiesThreshold);
+ continue;
+ }
+
+ if (secondLevelKeys === null || secondLevelKeys) {
+ var subPreview = this._generatePreview(value, secondLevelKeys || undefined);
+ var property = { name: name, type: type, valuePreview: subPreview };
+ this._appendPropertyPreview(preview, property, propertiesThreshold);
+ if (!subPreview.lossless)
+ preview.lossless = false;
+ if (subPreview.overflow)
+ preview.overflow = true;
+ continue;
+ }
+
+ preview.lossless = false;
+
+ var subtype = injectedScript._subtype(value);
+ var description = "";
+ if (type !== "function")
+ description = this._abbreviateString(/** @type {string} */ (injectedScript._describe(value)), maxLength, subtype === "regexp");
+
+ var property = { name: name, type: type, value: description };
+ if (subtype)
+ property.subtype = subtype;
+ this._appendPropertyPreview(preview, property, propertiesThreshold);
+ }
+ } catch (e) {
+ }
+ },
+
+ /**
+ * @param {Object} preview
+ * @param {Object} property
+ * @param {Object} propertiesThreshold
+ */
+ _appendPropertyPreview: function(preview, property, propertiesThreshold)
+ {
+ if (isNaN(property.name))
+ propertiesThreshold.properties--;
+ else
+ propertiesThreshold.indexes--;
+ preview.properties.push(property);
+ },
+
+ /**
+ * @param {string} string
+ * @param {number} maxLength
+ * @param {boolean=} middle
+ * @returns
+ */
+ _abbreviateString: function(string, maxLength, middle)
+ {
+ if (string.length <= maxLength)
+ return string;
+ if (middle) {
+ var leftHalf = maxLength >> 1;
+ var rightHalf = maxLength - leftHalf - 1;
+ return string.substr(0, leftHalf) + "\u2026" + string.substr(string.length - rightHalf, rightHalf);
+ }
+ return string.substr(0, maxLength) + "\u2026";
+ }
+}
+/**
+ * @constructor
+ * @param {number} ordinal
+ * @param {Object} callFrame
+ */
+InjectedScript.CallFrameProxy = function(ordinal, callFrame)
+{
+ this.callFrameId = "{\"ordinal\":" + ordinal + ",\"injectedScriptId\":" + injectedScriptId + "}";
+ this.functionName = (callFrame.type === "function" ? callFrame.functionName : "");
+ this.location = { scriptId: String(callFrame.sourceID), lineNumber: callFrame.line, columnNumber: callFrame.column };
+ this.scopeChain = this._wrapScopeChain(callFrame);
+ this.this = injectedScript._wrapObject(callFrame.thisObject, "backtrace");
+}
+
+InjectedScript.CallFrameProxy.prototype = {
+ /**
+ * @param {Object} callFrame
+ * @return {!Array.<DebuggerAgent.Scope>}
+ */
+ _wrapScopeChain: function(callFrame)
+ {
+ var scopeChain = callFrame.scopeChain;
+ var scopeChainProxy = [];
+ for (var i = 0; i < scopeChain.length; i++) {
+ var scope = InjectedScript.CallFrameProxy._createScopeJson(callFrame.scopeType(i), scopeChain[i], "backtrace");
+ scopeChainProxy.push(scope);
+ }
+ return scopeChainProxy;
+ }
+}
+
+/**
+ * @param {number} scopeTypeCode
+ * @param {*} scopeObject
+ * @param {string} groupId
+ * @return {!DebuggerAgent.Scope}
+ */
+InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeObject, groupId) {
+ const GLOBAL_SCOPE = 0;
+ const LOCAL_SCOPE = 1;
+ const WITH_SCOPE = 2;
+ const CLOSURE_SCOPE = 3;
+ const CATCH_SCOPE = 4;
+
+ /** @type {!Object.<number, string>} */
+ var scopeTypeNames = {};
+ scopeTypeNames[GLOBAL_SCOPE] = "global";
+ scopeTypeNames[LOCAL_SCOPE] = "local";
+ scopeTypeNames[WITH_SCOPE] = "with";
+ scopeTypeNames[CLOSURE_SCOPE] = "closure";
+ scopeTypeNames[CATCH_SCOPE] = "catch";
+
+ return {
+ object: injectedScript._wrapObject(scopeObject, groupId),
+ type: /** @type {DebuggerAgent.ScopeType} */ (scopeTypeNames[scopeTypeCode])
+ };
+}
+
+/**
+ * @constructor
+ * @param {CommandLineAPIImpl} commandLineAPIImpl
+ * @param {Object} callFrame
+ */
+function CommandLineAPI(commandLineAPIImpl, callFrame)
+{
+ /**
+ * @param {string} member
+ * @return {boolean}
+ */
+ function inScopeVariables(member)
+ {
+ if (!callFrame)
+ return false;
+
+ var scopeChain = callFrame.scopeChain;
+ for (var i = 0; i < scopeChain.length; ++i) {
+ if (member in scopeChain[i])
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param {string} name The name of the method for which a toString method should be generated.
+ * @return {function():string}
+ */
+ function customToStringMethod(name)
+ {
+ return function () { return "function " + name + "() { [Command Line API] }"; };
+ }
+
+ for (var i = 0; i < CommandLineAPI.members_.length; ++i) {
+ var member = CommandLineAPI.members_[i];
+ if (member in inspectedWindow || inScopeVariables(member))
+ continue;
+
+ this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl);
+ this[member].toString = customToStringMethod(member);
+ }
+
+ for (var i = 0; i < 5; ++i) {
+ var member = "$" + i;
+ if (member in inspectedWindow || inScopeVariables(member))
+ continue;
+
+ this.__defineGetter__("$" + i, bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl, i));
+ }
+
+ this.$_ = injectedScript._lastResult;
+}
+
+// NOTE: Please keep the list of API methods below snchronized to that in WebInspector.RuntimeModel!
+/**
+ * @type {Array.<string>}
+ * @const
+ */
+CommandLineAPI.members_ = [
+ "$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd",
+ "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "table"
+];
+
+/**
+ * @constructor
+ */
+function CommandLineAPIImpl()
+{
+}
+
+CommandLineAPIImpl.prototype = {
+ /**
+ * @param {string} selector
+ * @param {Node=} start
+ */
+ $: function (selector, start)
+ {
+ if (this._canQuerySelectorOnNode(start))
+ return start.querySelector(selector);
+
+ return inspectedWindow.document.querySelector(selector);
+ },
+
+ /**
+ * @param {string} selector
+ * @param {Node=} start
+ */
+ $$: function (selector, start)
+ {
+ if (this._canQuerySelectorOnNode(start))
+ return start.querySelectorAll(selector);
+ return inspectedWindow.document.querySelectorAll(selector);
+ },
+
+ /**
+ * @param {Node=} node
+ * @return {boolean}
+ */
+ _canQuerySelectorOnNode: function(node)
+ {
+ return !!node && InjectedScriptHost.type(node) === "node" && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE);
+ },
+
+ /**
+ * @param {string} xpath
+ * @param {Node=} context
+ */
+ $x: function(xpath, context)
+ {
+ var doc = (context && context.ownerDocument) || inspectedWindow.document;
+ var result = doc.evaluate(xpath, context || doc, null, XPathResult.ANY_TYPE, null);
+ switch (result.resultType) {
+ case XPathResult.NUMBER_TYPE:
+ return result.numberValue;
+ case XPathResult.STRING_TYPE:
+ return result.stringValue;
+ case XPathResult.BOOLEAN_TYPE:
+ return result.booleanValue;
+ default:
+ var nodes = [];
+ var node;
+ while (node = result.iterateNext())
+ nodes.push(node);
+ return nodes;
+ }
+ },
+
+ dir: function()
+ {
+ return inspectedWindow.console.dir.apply(inspectedWindow.console, arguments)
+ },
+
+ dirxml: function()
+ {
+ return inspectedWindow.console.dirxml.apply(inspectedWindow.console, arguments)
+ },
+
+ keys: function(object)
+ {
+ return Object.keys(object);
+ },
+
+ values: function(object)
+ {
+ var result = [];
+ for (var key in object)
+ result.push(object[key]);
+ return result;
+ },
+
+ profile: function()
+ {
+ return inspectedWindow.console.profile.apply(inspectedWindow.console, arguments)
+ },
+
+ profileEnd: function()
+ {
+ return inspectedWindow.console.profileEnd.apply(inspectedWindow.console, arguments)
+ },
+
+ /**
+ * @param {Object} object
+ * @param {Array.<string>|string=} types
+ */
+ monitorEvents: function(object, types)
+ {
+ if (!object || !object.addEventListener || !object.removeEventListener)
+ return;
+ types = this._normalizeEventTypes(types);
+ for (var i = 0; i < types.length; ++i) {
+ object.removeEventListener(types[i], this._logEvent, false);
+ object.addEventListener(types[i], this._logEvent, false);
+ }
+ },
+
+ /**
+ * @param {Object} object
+ * @param {Array.<string>|string=} types
+ */
+ unmonitorEvents: function(object, types)
+ {
+ if (!object || !object.addEventListener || !object.removeEventListener)
+ return;
+ types = this._normalizeEventTypes(types);
+ for (var i = 0; i < types.length; ++i)
+ object.removeEventListener(types[i], this._logEvent, false);
+ },
+
+ /**
+ * @param {*} object
+ * @return {*}
+ */
+ inspect: function(object)
+ {
+ return injectedScript._inspect(object);
+ },
+
+ copy: function(object)
+ {
+ if (injectedScript._subtype(object) === "node")
+ object = object.outerHTML;
+ InjectedScriptHost.copyText(object);
+ },
+
+ clear: function()
+ {
+ InjectedScriptHost.clearConsoleMessages();
+ },
+
+ /**
+ * @param {Node} node
+ */
+ getEventListeners: function(node)
+ {
+ return InjectedScriptHost.getEventListeners(node);
+ },
+
+ table: function()
+ {
+ inspectedWindow.console.table.apply(inspectedWindow.console, arguments);
+ },
+
+ /**
+ * @param {number} num
+ */
+ _inspectedObject: function(num)
+ {
+ return InjectedScriptHost.inspectedObject(num);
+ },
+
+ /**
+ * @param {Array.<string>|string=} types
+ * @return {Array.<string>}
+ */
+ _normalizeEventTypes: function(types)
+ {
+ if (typeof types === "undefined")
+ types = [ "mouse", "key", "touch", "control", "load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll", "search", "devicemotion", "deviceorientation" ];
+ else if (typeof types === "string")
+ types = [ types ];
+
+ var result = [];
+ for (var i = 0; i < types.length; i++) {
+ if (types[i] === "mouse")
+ result.splice(0, 0, "mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout", "mousewheel");
+ else if (types[i] === "key")
+ result.splice(0, 0, "keydown", "keyup", "keypress", "textInput");
+ else if (types[i] === "touch")
+ result.splice(0, 0, "touchstart", "touchmove", "touchend", "touchcancel");
+ else if (types[i] === "control")
+ result.splice(0, 0, "resize", "scroll", "zoom", "focus", "blur", "select", "change", "submit", "reset");
+ else
+ result.push(types[i]);
+ }
+ return result;
+ },
+
+ /**
+ * @param {Event} event
+ */
+ _logEvent: function(event)
+ {
+ inspectedWindow.console.log(event.type, event);
+ }
+}
+
+injectedScript._commandLineAPIImpl = new CommandLineAPIImpl();
+return injectedScript;
+})
diff --git a/Source/core/inspector/InspectorAgent.cpp b/Source/core/inspector/InspectorAgent.cpp
new file mode 100644
index 0000000..b60f7d6
--- /dev/null
+++ b/Source/core/inspector/InspectorAgent.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ * Copyright (C) 2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InspectorAgent.h"
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/ScriptFunctionCall.h"
+#include "bindings/v8/ScriptObject.h"
+#include "core/dom/Document.h"
+#include "core/inspector/InjectedScriptHost.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorController.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/page/Settings.h"
+#include "core/platform/graphics/GraphicsContext.h"
+#include "core/platform/network/ResourceRequest.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+using namespace std;
+
+namespace WebCore {
+
+namespace InspectorAgentState {
+static const char inspectorAgentEnabled[] = "inspectorAgentEnabled";
+}
+
+InspectorAgent::InspectorAgent(Page* page, InjectedScriptManager* injectedScriptManager, InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state)
+ : InspectorBaseAgent<InspectorAgent>("Inspector", instrumentingAgents, state)
+ , m_inspectedPage(page)
+ , m_frontend(0)
+ , m_injectedScriptManager(injectedScriptManager)
+{
+ ASSERT_ARG(page, page);
+ m_instrumentingAgents->setInspectorAgent(this);
+}
+
+InspectorAgent::~InspectorAgent()
+{
+ m_instrumentingAgents->setInspectorAgent(0);
+}
+
+void InspectorAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld* world)
+{
+ if (world != mainThreadNormalWorld())
+ return;
+
+ if (m_injectedScriptForOrigin.isEmpty())
+ return;
+
+ String origin = frame->document()->securityOrigin()->toRawString();
+ String script = m_injectedScriptForOrigin.get(origin);
+ if (script.isEmpty())
+ return;
+ int injectedScriptId = m_injectedScriptManager->injectedScriptIdFor(mainWorldScriptState(frame));
+ StringBuilder scriptSource;
+ scriptSource.append(script);
+ scriptSource.append("(");
+ scriptSource.appendNumber(injectedScriptId);
+ scriptSource.append(")");
+ frame->script()->executeScript(scriptSource.toString());
+}
+
+void InspectorAgent::setFrontend(InspectorFrontend* inspectorFrontend)
+{
+ m_frontend = inspectorFrontend;
+}
+
+void InspectorAgent::clearFrontend()
+{
+ m_pendingEvaluateTestCommands.clear();
+ m_frontend = 0;
+ m_injectedScriptManager->discardInjectedScripts();
+ ErrorString error;
+ disable(&error);
+}
+
+void InspectorAgent::didCommitLoad()
+{
+ m_injectedScriptManager->discardInjectedScripts();
+}
+
+void InspectorAgent::enable(ErrorString*)
+{
+ m_state->setBoolean(InspectorAgentState::inspectorAgentEnabled, true);
+
+ if (m_pendingInspectData.first)
+ inspect(m_pendingInspectData.first, m_pendingInspectData.second);
+
+ for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); m_frontend && it != m_pendingEvaluateTestCommands.end(); ++it)
+ m_frontend->inspector()->evaluateForTestInFrontend(static_cast<int>((*it).first), (*it).second);
+ m_pendingEvaluateTestCommands.clear();
+}
+
+void InspectorAgent::disable(ErrorString*)
+{
+ m_state->setBoolean(InspectorAgentState::inspectorAgentEnabled, false);
+}
+
+void InspectorAgent::domContentLoadedEventFired()
+{
+ m_injectedScriptManager->injectedScriptHost()->clearInspectedObjects();
+}
+
+bool InspectorAgent::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
+{
+ return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
+}
+
+void InspectorAgent::evaluateForTestInFrontend(long callId, const String& script)
+{
+ if (m_state->getBoolean(InspectorAgentState::inspectorAgentEnabled))
+ m_frontend->inspector()->evaluateForTestInFrontend(static_cast<int>(callId), script);
+ else
+ m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
+}
+
+void InspectorAgent::setInjectedScriptForOrigin(const String& origin, const String& source)
+{
+ m_injectedScriptForOrigin.set(origin, source);
+}
+
+void InspectorAgent::inspect(PassRefPtr<TypeBuilder::Runtime::RemoteObject> objectToInspect, PassRefPtr<InspectorObject> hints)
+{
+ if (m_state->getBoolean(InspectorAgentState::inspectorAgentEnabled) && m_frontend) {
+ m_frontend->inspector()->inspect(objectToInspect, hints);
+ m_pendingInspectData.first = 0;
+ m_pendingInspectData.second = 0;
+ return;
+ }
+ m_pendingInspectData.first = objectToInspect;
+ m_pendingInspectData.second = hints;
+}
+
+KURL InspectorAgent::inspectedURL() const
+{
+ return m_inspectedPage->mainFrame()->document()->url();
+}
+
+KURL InspectorAgent::inspectedURLWithoutFragment() const
+{
+ KURL url = inspectedURL();
+ url.removeFragmentIdentifier();
+ return url;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorAgent.h b/Source/core/inspector/InspectorAgent.h
new file mode 100644
index 0000000..137474a
--- /dev/null
+++ b/Source/core/inspector/InspectorAgent.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorAgent_h
+#define InspectorAgent_h
+
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class DOMWrapperWorld;
+class DocumentLoader;
+class Frame;
+class InjectedScriptManager;
+class InspectorFrontend;
+class InspectorObject;
+class InstrumentingAgents;
+class KURL;
+class Page;
+
+typedef String ErrorString;
+
+class InspectorAgent : public InspectorBaseAgent<InspectorAgent>, public InspectorBackendDispatcher::InspectorCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorAgent);
+public:
+ static PassOwnPtr<InspectorAgent> create(Page* page, InjectedScriptManager* injectedScriptManager, InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state)
+ {
+ return adoptPtr(new InspectorAgent(page, injectedScriptManager, instrumentingAgents, state));
+ }
+
+ virtual ~InspectorAgent();
+
+ // Inspector front-end API.
+ void enable(ErrorString*);
+ void disable(ErrorString*);
+
+ KURL inspectedURL() const;
+ KURL inspectedURLWithoutFragment() const;
+
+ InspectorFrontend* frontend() const { return m_frontend; }
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+
+ void didClearWindowObjectInWorld(Frame*, DOMWrapperWorld*);
+
+ void didCommitLoad();
+ void domContentLoadedEventFired();
+
+ bool hasFrontend() const { return m_frontend; }
+
+ // Generic code called from custom implementations.
+ void evaluateForTestInFrontend(long testCallId, const String& script);
+
+ void setInjectedScriptForOrigin(const String& origin, const String& source);
+
+ void inspect(PassRefPtr<TypeBuilder::Runtime::RemoteObject> objectToInspect, PassRefPtr<InspectorObject> hints);
+
+private:
+ InspectorAgent(Page*, InjectedScriptManager*, InstrumentingAgents*, InspectorCompositeState*);
+
+ void unbindAllResources();
+
+ void toggleRecordButton(bool);
+
+ bool isMainResourceLoader(DocumentLoader*, const KURL& requestUrl);
+
+ Page* m_inspectedPage;
+ InspectorFrontend* m_frontend;
+ InjectedScriptManager* m_injectedScriptManager;
+
+ Vector<pair<long, String> > m_pendingEvaluateTestCommands;
+ pair<RefPtr<TypeBuilder::Runtime::RemoteObject>, RefPtr<InspectorObject> > m_pendingInspectData;
+ typedef HashMap<String, String> InjectedScriptForOriginMap;
+ InjectedScriptForOriginMap m_injectedScriptForOrigin;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorAgent_h)
diff --git a/Source/core/inspector/InspectorApplicationCacheAgent.cpp b/Source/core/inspector/InspectorApplicationCacheAgent.cpp
new file mode 100644
index 0000000..8bf09bf
--- /dev/null
+++ b/Source/core/inspector/InspectorApplicationCacheAgent.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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 "core/inspector/InspectorApplicationCacheAgent.h"
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorAgent.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/appcache/ApplicationCacheHost.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/platform/network/NetworkStateNotifier.h"
+#include "core/platform/network/ResourceResponse.h"
+
+namespace WebCore {
+
+namespace ApplicationCacheAgentState {
+static const char applicationCacheAgentEnabled[] = "applicationCacheAgentEnabled";
+}
+
+InspectorApplicationCacheAgent::InspectorApplicationCacheAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorPageAgent* pageAgent)
+ : InspectorBaseAgent<InspectorApplicationCacheAgent>("ApplicationCache", instrumentingAgents, state)
+ , m_pageAgent(pageAgent)
+ , m_frontend(0)
+{
+}
+
+void InspectorApplicationCacheAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->applicationcache();
+}
+
+void InspectorApplicationCacheAgent::clearFrontend()
+{
+ m_instrumentingAgents->setInspectorApplicationCacheAgent(0);
+ m_frontend = 0;
+}
+
+void InspectorApplicationCacheAgent::restore()
+{
+ if (m_state->getBoolean(ApplicationCacheAgentState::applicationCacheAgentEnabled)) {
+ ErrorString error;
+ enable(&error);
+ }
+}
+
+void InspectorApplicationCacheAgent::enable(ErrorString*)
+{
+ m_state->setBoolean(ApplicationCacheAgentState::applicationCacheAgentEnabled, true);
+ m_instrumentingAgents->setInspectorApplicationCacheAgent(this);
+
+ // We need to pass initial navigator.onOnline.
+ networkStateChanged();
+}
+
+void InspectorApplicationCacheAgent::updateApplicationCacheStatus(Frame* frame)
+{
+ DocumentLoader* documentLoader = frame->loader()->documentLoader();
+ if (!documentLoader)
+ return;
+
+ ApplicationCacheHost* host = documentLoader->applicationCacheHost();
+ ApplicationCacheHost::Status status = host->status();
+ ApplicationCacheHost::CacheInfo info = host->applicationCacheInfo();
+
+ String manifestURL = info.m_manifest.string();
+ m_frontend->applicationCacheStatusUpdated(m_pageAgent->frameId(frame), manifestURL, static_cast<int>(status));
+}
+
+void InspectorApplicationCacheAgent::networkStateChanged()
+{
+ bool isNowOnline = networkStateNotifier().onLine();
+ m_frontend->networkStateUpdated(isNowOnline);
+}
+
+void InspectorApplicationCacheAgent::getFramesWithManifests(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::ApplicationCache::FrameWithManifest> >& result)
+{
+ result = TypeBuilder::Array<TypeBuilder::ApplicationCache::FrameWithManifest>::create();
+
+ Frame* mainFrame = m_pageAgent->mainFrame();
+ for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext(mainFrame)) {
+ DocumentLoader* documentLoader = frame->loader()->documentLoader();
+ if (!documentLoader)
+ continue;
+
+ ApplicationCacheHost* host = documentLoader->applicationCacheHost();
+ ApplicationCacheHost::CacheInfo info = host->applicationCacheInfo();
+ String manifestURL = info.m_manifest.string();
+ if (!manifestURL.isEmpty()) {
+ RefPtr<TypeBuilder::ApplicationCache::FrameWithManifest> value = TypeBuilder::ApplicationCache::FrameWithManifest::create()
+ .setFrameId(m_pageAgent->frameId(frame))
+ .setManifestURL(manifestURL)
+ .setStatus(static_cast<int>(host->status()));
+ result->addItem(value);
+ }
+ }
+}
+
+DocumentLoader* InspectorApplicationCacheAgent::assertFrameWithDocumentLoader(ErrorString* errorString, String frameId)
+{
+ Frame* frame = m_pageAgent->assertFrame(errorString, frameId);
+ if (!frame)
+ return 0;
+
+ return InspectorPageAgent::assertDocumentLoader(errorString, frame);
+}
+
+void InspectorApplicationCacheAgent::getManifestForFrame(ErrorString* errorString, const String& frameId, String* manifestURL)
+{
+ DocumentLoader* documentLoader = assertFrameWithDocumentLoader(errorString, frameId);
+ if (!documentLoader)
+ return;
+
+ ApplicationCacheHost::CacheInfo info = documentLoader->applicationCacheHost()->applicationCacheInfo();
+ *manifestURL = info.m_manifest.string();
+}
+
+void InspectorApplicationCacheAgent::getApplicationCacheForFrame(ErrorString* errorString, const String& frameId, RefPtr<TypeBuilder::ApplicationCache::ApplicationCache>& applicationCache)
+{
+ DocumentLoader* documentLoader = assertFrameWithDocumentLoader(errorString, frameId);
+ if (!documentLoader)
+ return;
+
+ ApplicationCacheHost* host = documentLoader->applicationCacheHost();
+ ApplicationCacheHost::CacheInfo info = host->applicationCacheInfo();
+
+ ApplicationCacheHost::ResourceInfoList resources;
+ host->fillResourceList(&resources);
+
+ applicationCache = buildObjectForApplicationCache(resources, info);
+}
+
+PassRefPtr<TypeBuilder::ApplicationCache::ApplicationCache> InspectorApplicationCacheAgent::buildObjectForApplicationCache(const ApplicationCacheHost::ResourceInfoList& applicationCacheResources, const ApplicationCacheHost::CacheInfo& applicationCacheInfo)
+{
+ return TypeBuilder::ApplicationCache::ApplicationCache::create()
+ .setManifestURL(applicationCacheInfo.m_manifest.string())
+ .setSize(applicationCacheInfo.m_size)
+ .setCreationTime(applicationCacheInfo.m_creationTime)
+ .setUpdateTime(applicationCacheInfo.m_updateTime)
+ .setResources(buildArrayForApplicationCacheResources(applicationCacheResources))
+ .release();
+}
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::ApplicationCache::ApplicationCacheResource> > InspectorApplicationCacheAgent::buildArrayForApplicationCacheResources(const ApplicationCacheHost::ResourceInfoList& applicationCacheResources)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::ApplicationCache::ApplicationCacheResource> > resources = TypeBuilder::Array<TypeBuilder::ApplicationCache::ApplicationCacheResource>::create();
+
+ ApplicationCacheHost::ResourceInfoList::const_iterator end = applicationCacheResources.end();
+ ApplicationCacheHost::ResourceInfoList::const_iterator it = applicationCacheResources.begin();
+ for (int i = 0; it != end; ++it, i++)
+ resources->addItem(buildObjectForApplicationCacheResource(*it));
+
+ return resources;
+}
+
+PassRefPtr<TypeBuilder::ApplicationCache::ApplicationCacheResource> InspectorApplicationCacheAgent::buildObjectForApplicationCacheResource(const ApplicationCacheHost::ResourceInfo& resourceInfo)
+{
+ String types;
+ if (resourceInfo.m_isMaster)
+ types.append("Master ");
+
+ if (resourceInfo.m_isManifest)
+ types.append("Manifest ");
+
+ if (resourceInfo.m_isFallback)
+ types.append("Fallback ");
+
+ if (resourceInfo.m_isForeign)
+ types.append("Foreign ");
+
+ if (resourceInfo.m_isExplicit)
+ types.append("Explicit ");
+
+ RefPtr<TypeBuilder::ApplicationCache::ApplicationCacheResource> value = TypeBuilder::ApplicationCache::ApplicationCacheResource::create()
+ .setUrl(resourceInfo.m_resource.string())
+ .setSize(static_cast<int>(resourceInfo.m_size))
+ .setType(types);
+ return value;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorApplicationCacheAgent.h b/Source/core/inspector/InspectorApplicationCacheAgent.h
new file mode 100644
index 0000000..142e752
--- /dev/null
+++ b/Source/core/inspector/InspectorApplicationCacheAgent.h
@@ -0,0 +1,89 @@
+/*
+ * 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 InspectorApplicationCacheAgent_h
+#define InspectorApplicationCacheAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/loader/appcache/ApplicationCacheHost.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class Frame;
+class InspectorArray;
+class InspectorAgent;
+class InspectorFrontend;
+class InspectorObject;
+class InspectorPageAgent;
+class InspectorValue;
+class InspectorState;
+class InstrumentingAgents;
+class Page;
+class ResourceResponse;
+
+typedef String ErrorString;
+
+class InspectorApplicationCacheAgent : public InspectorBaseAgent<InspectorApplicationCacheAgent>, public InspectorBackendDispatcher::ApplicationCacheCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorApplicationCacheAgent); WTF_MAKE_FAST_ALLOCATED;
+public:
+ static PassOwnPtr<InspectorApplicationCacheAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorPageAgent* pageAgent)
+ {
+ return adoptPtr(new InspectorApplicationCacheAgent(instrumentingAgents, state, pageAgent));
+ }
+ ~InspectorApplicationCacheAgent() { }
+
+ // InspectorBaseAgent
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ // InspectorInstrumentation API
+ void updateApplicationCacheStatus(Frame*);
+ void networkStateChanged();
+
+ // ApplicationCache API for InspectorFrontend
+ virtual void enable(ErrorString*);
+ virtual void getFramesWithManifests(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::ApplicationCache::FrameWithManifest> >& result);
+ virtual void getManifestForFrame(ErrorString*, const String& frameId, String* manifestURL);
+ virtual void getApplicationCacheForFrame(ErrorString*, const String& frameId, RefPtr<TypeBuilder::ApplicationCache::ApplicationCache>&);
+
+private:
+ InspectorApplicationCacheAgent(InstrumentingAgents*, InspectorCompositeState*, InspectorPageAgent*);
+ PassRefPtr<TypeBuilder::ApplicationCache::ApplicationCache> buildObjectForApplicationCache(const ApplicationCacheHost::ResourceInfoList&, const ApplicationCacheHost::CacheInfo&);
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::ApplicationCache::ApplicationCacheResource> > buildArrayForApplicationCacheResources(const ApplicationCacheHost::ResourceInfoList&);
+ PassRefPtr<TypeBuilder::ApplicationCache::ApplicationCacheResource> buildObjectForApplicationCacheResource(const ApplicationCacheHost::ResourceInfo&);
+
+ DocumentLoader* assertFrameWithDocumentLoader(ErrorString*, String frameId);
+
+ InspectorPageAgent* m_pageAgent;
+ InspectorFrontend::ApplicationCache* m_frontend;
+};
+
+} // namespace WebCore
+
+#endif // InspectorApplicationCacheAgent_h
diff --git a/Source/core/inspector/InspectorBaseAgent.cpp b/Source/core/inspector/InspectorBaseAgent.cpp
new file mode 100644
index 0000000..950e422
--- /dev/null
+++ b/Source/core/inspector/InspectorBaseAgent.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorBaseAgent.h"
+
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include "core/inspector/InspectorState.h"
+
+namespace WebCore {
+
+InspectorBaseAgentInterface::InspectorBaseAgentInterface(const String& name, InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState)
+ : m_instrumentingAgents(instrumentingAgents)
+ , m_state(inspectorState->createAgentState(name))
+ , m_name(name)
+{
+}
+
+InspectorBaseAgentInterface::~InspectorBaseAgentInterface()
+{
+}
+
+void InspectorBaseAgentInterface::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Inspector);
+ info.addMember(m_name, "name");
+ info.addWeakPointer(m_instrumentingAgents);
+ info.addWeakPointer(m_state);
+}
+
+void InspectorAgentRegistry::append(PassOwnPtr<InspectorBaseAgentInterface> agent)
+{
+ m_agents.append(agent);
+}
+
+void InspectorAgentRegistry::setFrontend(InspectorFrontend* frontend)
+{
+ for (size_t i = 0; i < m_agents.size(); i++)
+ m_agents[i]->setFrontend(frontend);
+}
+
+void InspectorAgentRegistry::clearFrontend()
+{
+ for (size_t i = 0; i < m_agents.size(); i++)
+ m_agents[i]->clearFrontend();
+}
+
+void InspectorAgentRegistry::restore()
+{
+ for (size_t i = 0; i < m_agents.size(); i++)
+ m_agents[i]->restore();
+}
+
+void InspectorAgentRegistry::registerInDispatcher(InspectorBackendDispatcher* dispatcher)
+{
+ for (size_t i = 0; i < m_agents.size(); i++)
+ m_agents[i]->registerInDispatcher(dispatcher);
+}
+
+void InspectorAgentRegistry::discardAgents()
+{
+ for (size_t i = 0; i < m_agents.size(); i++)
+ m_agents[i]->discardAgent();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorBaseAgent.h b/Source/core/inspector/InspectorBaseAgent.h
new file mode 100644
index 0000000..75bd7b4
--- /dev/null
+++ b/Source/core/inspector/InspectorBaseAgent.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorBaseAgent_h
+#define InspectorBaseAgent_h
+
+#include "InspectorBackendDispatcher.h"
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InspectorFrontend;
+class InspectorCompositeState;
+class InspectorState;
+class InstrumentingAgents;
+
+class InspectorBaseAgentInterface {
+public:
+ InspectorBaseAgentInterface(const String&, InstrumentingAgents*, InspectorCompositeState*);
+ virtual ~InspectorBaseAgentInterface();
+
+ virtual void setFrontend(InspectorFrontend*) { }
+ virtual void clearFrontend() { }
+ virtual void restore() { }
+ virtual void registerInDispatcher(InspectorBackendDispatcher*) = 0;
+ virtual void discardAgent() { }
+
+ String name() { return m_name; }
+
+ virtual void reportMemoryUsage(MemoryObjectInfo*) const;
+
+protected:
+ InstrumentingAgents* m_instrumentingAgents;
+ InspectorState* m_state;
+
+private:
+ String m_name;
+};
+
+class InspectorAgentRegistry {
+public:
+ void append(PassOwnPtr<InspectorBaseAgentInterface>);
+
+ void setFrontend(InspectorFrontend*);
+ void clearFrontend();
+ void restore();
+ void registerInDispatcher(InspectorBackendDispatcher*);
+ void discardAgents();
+
+private:
+ Vector<OwnPtr<InspectorBaseAgentInterface> > m_agents;
+};
+
+template<typename T>
+class InspectorBaseAgent : public InspectorBaseAgentInterface {
+public:
+ virtual ~InspectorBaseAgent() { }
+
+ virtual void registerInDispatcher(InspectorBackendDispatcher* dispatcher)
+ {
+ dispatcher->registerAgent(static_cast<T*>(this));
+ }
+
+protected:
+ InspectorBaseAgent(const String& name, InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState)
+ : InspectorBaseAgentInterface(name, instrumentingAgents, inspectorState)
+ {
+ }
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorBaseAgent_h)
diff --git a/Source/core/inspector/InspectorCSSAgent.cpp b/Source/core/inspector/InspectorCSSAgent.cpp
new file mode 100644
index 0000000..5a9a191
--- /dev/null
+++ b/Source/core/inspector/InspectorCSSAgent.cpp
@@ -0,0 +1,1473 @@
+/*
+ * Copyright (C) 2010, Google 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 "core/inspector/InspectorCSSAgent.h"
+
+#include "CSSPropertyNames.h"
+#include "InspectorTypeBuilder.h"
+#include "core/css/CSSComputedStyleDeclaration.h"
+#include "core/css/CSSImportRule.h"
+#include "core/css/CSSPropertySourceData.h"
+#include "core/css/CSSRule.h"
+#include "core/css/CSSRuleList.h"
+#include "core/css/CSSStyleRule.h"
+#include "core/css/CSSStyleSheet.h"
+#include "core/css/StylePropertySet.h"
+#include "core/css/StylePropertyShorthand.h"
+#include "core/css/StyleResolver.h"
+#include "core/css/StyleRule.h"
+#include "core/css/StyleSheet.h"
+#include "core/css/StyleSheetList.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/NamedFlow.h"
+#include "core/dom/NamedFlowCollection.h"
+#include "core/dom/Node.h"
+#include "core/dom/NodeList.h"
+#include "core/html/HTMLHeadElement.h"
+#include "core/html/HTMLStyleElement.h"
+#include "core/inspector/InspectorDOMAgent.h"
+#include "core/inspector/InspectorHistory.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/page/ContentSecurityPolicy.h"
+#include "core/page/DOMWindow.h"
+#include "core/rendering/RenderRegion.h"
+#include "core/svg/SVGStyleElement.h"
+
+#include <wtf/CurrentTime.h>
+#include <wtf/HashSet.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+#include <wtf/Vector.h>
+
+namespace CSSAgentState {
+static const char cssAgentEnabled[] = "cssAgentEnabled";
+static const char isSelectorProfiling[] = "isSelectorProfiling";
+}
+
+namespace WebCore {
+
+enum ForcePseudoClassFlags {
+ PseudoNone = 0,
+ PseudoHover = 1 << 0,
+ PseudoFocus = 1 << 1,
+ PseudoActive = 1 << 2,
+ PseudoVisited = 1 << 3
+};
+
+struct RuleMatchData {
+ String selector;
+ String url;
+ unsigned lineNumber;
+ double startTime;
+};
+
+struct RuleMatchingStats {
+ RuleMatchingStats()
+ : lineNumber(0), totalTime(0.0), hits(0), matches(0)
+ {
+ }
+ RuleMatchingStats(const RuleMatchData& data, double totalTime, unsigned hits, unsigned matches)
+ : selector(data.selector), url(data.url), lineNumber(data.lineNumber), totalTime(totalTime), hits(hits), matches(matches)
+ {
+ }
+
+ String selector;
+ String url;
+ unsigned lineNumber;
+ double totalTime;
+ unsigned hits;
+ unsigned matches;
+};
+
+class SelectorProfile {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ SelectorProfile()
+ : m_totalMatchingTimeMs(0.0)
+ {
+ }
+ virtual ~SelectorProfile()
+ {
+ }
+
+ double totalMatchingTimeMs() const { return m_totalMatchingTimeMs; }
+
+ String makeKey();
+ void startSelector(const CSSStyleRule*);
+ void commitSelector(bool);
+ void commitSelectorTime();
+ PassRefPtr<TypeBuilder::CSS::SelectorProfile> toInspectorObject() const;
+
+private:
+
+ // Key is "selector?url:line".
+ typedef HashMap<String, RuleMatchingStats> RuleMatchingStatsMap;
+
+ double m_totalMatchingTimeMs;
+ RuleMatchingStatsMap m_ruleMatchingStats;
+ RuleMatchData m_currentMatchData;
+};
+
+class StyleSheetAppender {
+public:
+ StyleSheetAppender(CSSStyleSheetToInspectorStyleSheet& cssStyleSheetToInspectorStyleSheet, Vector<CSSStyleSheet*>& result)
+ : m_cssStyleSheetToInspectorStyleSheet(cssStyleSheetToInspectorStyleSheet)
+ , m_result(result) { }
+
+ void run(CSSStyleSheet* styleSheet)
+ {
+ RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(static_cast<CSSStyleSheet*>(styleSheet));
+ // Avoid creating m_childRuleCSSOMWrappers in the stylesheet if it is in the process of re-parsing.
+ // Otherwise m_childRuleCSSOMWrappers size will be initialized only for a part of rules, resulting in an ASSERT failure in CSSStyleSheet::item().
+ // Instead, wait for the RuleMutationScope destruction and handle the complete CSSStyleSheet.
+ if (inspectorStyleSheet && inspectorStyleSheet->isReparsing())
+ return;
+ m_result.append(styleSheet);
+ for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
+ CSSRule* rule = styleSheet->item(i);
+ if (rule->type() == CSSRule::IMPORT_RULE) {
+ CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet();
+ if (importedStyleSheet)
+ run(importedStyleSheet);
+ }
+ }
+ }
+
+private:
+ CSSStyleSheetToInspectorStyleSheet& m_cssStyleSheetToInspectorStyleSheet;
+ Vector<CSSStyleSheet*>& m_result;
+};
+
+static unsigned computePseudoClassMask(InspectorArray* pseudoClassArray)
+{
+ DEFINE_STATIC_LOCAL(String, active, (ASCIILiteral("active")));
+ DEFINE_STATIC_LOCAL(String, hover, (ASCIILiteral("hover")));
+ DEFINE_STATIC_LOCAL(String, focus, (ASCIILiteral("focus")));
+ DEFINE_STATIC_LOCAL(String, visited, (ASCIILiteral("visited")));
+ if (!pseudoClassArray || !pseudoClassArray->length())
+ return PseudoNone;
+
+ unsigned result = PseudoNone;
+ for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
+ RefPtr<InspectorValue> pseudoClassValue = pseudoClassArray->get(i);
+ String pseudoClass;
+ bool success = pseudoClassValue->asString(&pseudoClass);
+ if (!success)
+ continue;
+ if (pseudoClass == active)
+ result |= PseudoActive;
+ else if (pseudoClass == hover)
+ result |= PseudoHover;
+ else if (pseudoClass == focus)
+ result |= PseudoFocus;
+ else if (pseudoClass == visited)
+ result |= PseudoVisited;
+ }
+
+ return result;
+}
+
+inline String SelectorProfile::makeKey()
+{
+ return makeString(m_currentMatchData.selector, "?", m_currentMatchData.url, ":", String::number(m_currentMatchData.lineNumber));
+}
+
+inline void SelectorProfile::startSelector(const CSSStyleRule* rule)
+{
+ m_currentMatchData.selector = rule->selectorText();
+ CSSStyleSheet* styleSheet = rule->parentStyleSheet();
+ String url = emptyString();
+ if (styleSheet) {
+ url = InspectorStyleSheet::styleSheetURL(styleSheet);
+ if (url.isEmpty())
+ url = InspectorDOMAgent::documentURLString(styleSheet->ownerDocument());
+ }
+ m_currentMatchData.url = url;
+ m_currentMatchData.lineNumber = rule->styleRule()->sourceLine();
+ m_currentMatchData.startTime = WTF::currentTimeMS();
+}
+
+inline void SelectorProfile::commitSelector(bool matched)
+{
+ double matchTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTime;
+ m_totalMatchingTimeMs += matchTimeMs;
+
+ RuleMatchingStatsMap::AddResult result = m_ruleMatchingStats.add(makeKey(), RuleMatchingStats(m_currentMatchData, matchTimeMs, 1, matched ? 1 : 0));
+ if (!result.isNewEntry) {
+ result.iterator->value.totalTime += matchTimeMs;
+ result.iterator->value.hits += 1;
+ if (matched)
+ result.iterator->value.matches += 1;
+ }
+}
+
+inline void SelectorProfile::commitSelectorTime()
+{
+ double processingTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTime;
+ m_totalMatchingTimeMs += processingTimeMs;
+
+ RuleMatchingStatsMap::iterator it = m_ruleMatchingStats.find(makeKey());
+ if (it == m_ruleMatchingStats.end())
+ return;
+
+ it->value.totalTime += processingTimeMs;
+}
+
+PassRefPtr<TypeBuilder::CSS::SelectorProfile> SelectorProfile::toInspectorObject() const
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry> > selectorProfileData = TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry>::create();
+ for (RuleMatchingStatsMap::const_iterator it = m_ruleMatchingStats.begin(); it != m_ruleMatchingStats.end(); ++it) {
+ RefPtr<TypeBuilder::CSS::SelectorProfileEntry> entry = TypeBuilder::CSS::SelectorProfileEntry::create()
+ .setSelector(it->value.selector)
+ .setUrl(it->value.url)
+ .setLineNumber(it->value.lineNumber)
+ .setTime(it->value.totalTime)
+ .setHitCount(it->value.hits)
+ .setMatchCount(it->value.matches);
+ selectorProfileData->addItem(entry.release());
+ }
+
+ RefPtr<TypeBuilder::CSS::SelectorProfile> result = TypeBuilder::CSS::SelectorProfile::create()
+ .setTotalTime(totalMatchingTimeMs())
+ .setData(selectorProfileData);
+ return result.release();
+}
+
+class UpdateRegionLayoutTask {
+public:
+ UpdateRegionLayoutTask(InspectorCSSAgent*);
+ void scheduleFor(NamedFlow*, int documentNodeId);
+ void unschedule(NamedFlow*);
+ void reset();
+ void onTimer(Timer<UpdateRegionLayoutTask>*);
+
+private:
+ InspectorCSSAgent* m_cssAgent;
+ Timer<UpdateRegionLayoutTask> m_timer;
+ HashMap<NamedFlow*, int> m_namedFlows;
+};
+
+UpdateRegionLayoutTask::UpdateRegionLayoutTask(InspectorCSSAgent* cssAgent)
+ : m_cssAgent(cssAgent)
+ , m_timer(this, &UpdateRegionLayoutTask::onTimer)
+{
+}
+
+void UpdateRegionLayoutTask::scheduleFor(NamedFlow* namedFlow, int documentNodeId)
+{
+ m_namedFlows.add(namedFlow, documentNodeId);
+
+ if (!m_timer.isActive())
+ m_timer.startOneShot(0);
+}
+
+void UpdateRegionLayoutTask::unschedule(NamedFlow* namedFlow)
+{
+ m_namedFlows.remove(namedFlow);
+}
+
+void UpdateRegionLayoutTask::reset()
+{
+ m_timer.stop();
+ m_namedFlows.clear();
+}
+
+void UpdateRegionLayoutTask::onTimer(Timer<UpdateRegionLayoutTask>*)
+{
+ // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed.
+ Vector<std::pair<NamedFlow*, int> > namedFlows;
+
+ for (HashMap<NamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it)
+ namedFlows.append(std::make_pair(it->key, it->value));
+
+ for (unsigned i = 0, size = namedFlows.size(); i < size; ++i) {
+ NamedFlow* namedFlow = namedFlows.at(i).first;
+ int documentNodeId = namedFlows.at(i).second;
+
+ if (m_namedFlows.contains(namedFlow)) {
+ m_cssAgent->regionLayoutUpdated(namedFlow, documentNodeId);
+ m_namedFlows.remove(namedFlow);
+ }
+ }
+
+ if (!m_namedFlows.isEmpty() && !m_timer.isActive())
+ m_timer.startOneShot(0);
+}
+
+class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
+ WTF_MAKE_NONCOPYABLE(StyleSheetAction);
+public:
+ StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
+ : InspectorHistory::Action(name)
+ , m_styleSheet(styleSheet)
+ {
+ }
+
+protected:
+ RefPtr<InspectorStyleSheet> m_styleSheet;
+};
+
+class InspectorCSSAgent::SetStyleSheetTextAction : public InspectorCSSAgent::StyleSheetAction {
+ WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
+public:
+ SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
+ : InspectorCSSAgent::StyleSheetAction("SetStyleSheetText", styleSheet)
+ , m_text(text)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ if (!m_styleSheet->getText(&m_oldText))
+ return false;
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ if (m_styleSheet->setText(m_oldText, ec)) {
+ m_styleSheet->reparseStyleSheet(m_oldText);
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ if (m_styleSheet->setText(m_text, ec)) {
+ m_styleSheet->reparseStyleSheet(m_text);
+ return true;
+ }
+ return false;
+ }
+
+ virtual String mergeId()
+ {
+ return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
+ }
+
+ virtual void merge(PassOwnPtr<Action> action)
+ {
+ ASSERT(action->mergeId() == mergeId());
+
+ SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get());
+ m_text = other->m_text;
+ }
+
+private:
+ String m_text;
+ String m_oldText;
+};
+
+class InspectorCSSAgent::SetStyleTextAction : public InspectorCSSAgent::StyleSheetAction {
+ WTF_MAKE_NONCOPYABLE(SetStyleTextAction);
+public:
+ SetStyleTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& text)
+ : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
+ , m_cssId(cssId)
+ , m_text(text)
+ {
+ }
+
+ virtual String toString()
+ {
+ return mergeId() + ": " + m_oldText + " -> " + m_text;
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ String placeholder;
+ return m_styleSheet->setStyleText(m_cssId, m_oldText, &placeholder, ec);
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ return m_styleSheet->setStyleText(m_cssId, m_text, &m_oldText, ec);
+ }
+
+ virtual String mergeId()
+ {
+ return String::format("SetStyleText %s:%u", m_cssId.styleSheetId().utf8().data(), m_cssId.ordinal());
+ }
+
+ virtual void merge(PassOwnPtr<Action> action)
+ {
+ ASSERT(action->mergeId() == mergeId());
+
+ SetStyleTextAction* other = static_cast<SetStyleTextAction*>(action.get());
+ m_text = other->m_text;
+ }
+
+private:
+ InspectorCSSId m_cssId;
+ String m_text;
+ String m_oldText;
+};
+
+class InspectorCSSAgent::SetPropertyTextAction : public InspectorCSSAgent::StyleSheetAction {
+ WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
+public:
+ SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
+ : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
+ , m_cssId(cssId)
+ , m_propertyIndex(propertyIndex)
+ , m_text(text)
+ , m_overwrite(overwrite)
+ {
+ }
+
+ virtual String toString()
+ {
+ return mergeId() + ": " + m_oldText + " -> " + m_text;
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ String placeholder;
+ return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, ec);
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ String oldText;
+ bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, ec);
+ m_oldText = oldText.stripWhiteSpace();
+ // FIXME: remove this once the model handles this case.
+ if (!m_oldText.endsWith(';'))
+ m_oldText.append(';');
+ return result;
+ }
+
+ virtual String mergeId()
+ {
+ return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false");
+ }
+
+ virtual void merge(PassOwnPtr<Action> action)
+ {
+ ASSERT(action->mergeId() == mergeId());
+
+ SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
+ m_text = other->m_text;
+ }
+
+private:
+ InspectorCSSId m_cssId;
+ unsigned m_propertyIndex;
+ String m_text;
+ String m_oldText;
+ bool m_overwrite;
+};
+
+class InspectorCSSAgent::TogglePropertyAction : public InspectorCSSAgent::StyleSheetAction {
+ WTF_MAKE_NONCOPYABLE(TogglePropertyAction);
+public:
+ TogglePropertyAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, bool disable)
+ : InspectorCSSAgent::StyleSheetAction("ToggleProperty", styleSheet)
+ , m_cssId(cssId)
+ , m_propertyIndex(propertyIndex)
+ , m_disable(disable)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, !m_disable, ec);
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, m_disable, ec);
+ }
+
+private:
+ InspectorCSSId m_cssId;
+ unsigned m_propertyIndex;
+ bool m_disable;
+};
+
+class InspectorCSSAgent::SetRuleSelectorAction : public InspectorCSSAgent::StyleSheetAction {
+ WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
+public:
+ SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
+ : InspectorCSSAgent::StyleSheetAction("SetRuleSelector", styleSheet)
+ , m_cssId(cssId)
+ , m_selector(selector)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ m_oldSelector = m_styleSheet->ruleSelector(m_cssId, ec);
+ if (ec)
+ return false;
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, ec);
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ return m_styleSheet->setRuleSelector(m_cssId, m_selector, ec);
+ }
+
+private:
+ InspectorCSSId m_cssId;
+ String m_selector;
+ String m_oldSelector;
+};
+
+class InspectorCSSAgent::AddRuleAction : public InspectorCSSAgent::StyleSheetAction {
+ WTF_MAKE_NONCOPYABLE(AddRuleAction);
+public:
+ AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
+ : InspectorCSSAgent::StyleSheetAction("AddRule", styleSheet)
+ , m_selector(selector)
+ {
+ }
+
+ virtual bool perform(ExceptionCode& ec)
+ {
+ return redo(ec);
+ }
+
+ virtual bool undo(ExceptionCode& ec)
+ {
+ return m_styleSheet->deleteRule(m_newId, ec);
+ }
+
+ virtual bool redo(ExceptionCode& ec)
+ {
+ CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, ec);
+ if (ec)
+ return false;
+ m_newId = m_styleSheet->ruleId(cssStyleRule);
+ return true;
+ }
+
+ InspectorCSSId newRuleId() { return m_newId; }
+
+private:
+ InspectorCSSId m_newId;
+ String m_selector;
+ String m_oldSelector;
+};
+
+// static
+CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
+{
+ if (rule->type() != CSSRule::STYLE_RULE)
+ return 0;
+ return static_cast<CSSStyleRule*>(rule);
+}
+
+InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorDOMAgent* domAgent)
+ : InspectorBaseAgent<InspectorCSSAgent>("CSS", instrumentingAgents, state)
+ , m_frontend(0)
+ , m_domAgent(domAgent)
+ , m_lastStyleSheetId(1)
+ , m_creatingViaInspectorStyleSheet(false)
+{
+ m_domAgent->setDOMListener(this);
+}
+
+InspectorCSSAgent::~InspectorCSSAgent()
+{
+ ASSERT(!m_domAgent);
+ reset();
+}
+
+void InspectorCSSAgent::setFrontend(InspectorFrontend* frontend)
+{
+ ASSERT(!m_frontend);
+ m_frontend = frontend->css();
+}
+
+void InspectorCSSAgent::clearFrontend()
+{
+ ASSERT(m_frontend);
+ m_frontend = 0;
+ resetNonPersistentData();
+ stopSelectorProfilerImpl(0, false);
+}
+
+void InspectorCSSAgent::discardAgent()
+{
+ m_domAgent->setDOMListener(0);
+ m_domAgent = 0;
+}
+
+void InspectorCSSAgent::restore()
+{
+ if (m_state->getBoolean(CSSAgentState::cssAgentEnabled)) {
+ ErrorString error;
+ enable(&error);
+ }
+ if (m_state->getBoolean(CSSAgentState::isSelectorProfiling)) {
+ String errorString;
+ startSelectorProfiler(&errorString);
+ }
+}
+
+void InspectorCSSAgent::reset()
+{
+ m_idToInspectorStyleSheet.clear();
+ m_cssStyleSheetToInspectorStyleSheet.clear();
+ m_nodeToInspectorStyleSheet.clear();
+ m_documentToInspectorStyleSheet.clear();
+ resetNonPersistentData();
+}
+
+void InspectorCSSAgent::resetNonPersistentData()
+{
+ m_namedFlowCollectionsRequested.clear();
+ if (m_updateRegionLayoutTask)
+ m_updateRegionLayoutTask->reset();
+ resetPseudoStates();
+}
+
+void InspectorCSSAgent::enable(ErrorString*)
+{
+ m_state->setBoolean(CSSAgentState::cssAgentEnabled, true);
+ m_instrumentingAgents->setInspectorCSSAgent(this);
+
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader> > styleInfos = TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>::create();
+ Vector<InspectorStyleSheet*> styleSheets;
+ collectAllStyleSheets(styleSheets);
+ for (size_t i = 0; i < styleSheets.size(); ++i)
+ m_frontend->styleSheetAdded(styleSheets.at(i)->buildObjectForStyleSheetInfo());
+}
+
+void InspectorCSSAgent::disable(ErrorString*)
+{
+ m_instrumentingAgents->setInspectorCSSAgent(0);
+ m_state->setBoolean(CSSAgentState::cssAgentEnabled, false);
+}
+
+void InspectorCSSAgent::mediaQueryResultChanged()
+{
+ if (m_frontend)
+ m_frontend->mediaQueryResultChanged();
+}
+
+void InspectorCSSAgent::didCreateNamedFlow(Document* document, NamedFlow* namedFlow)
+{
+ int documentNodeId = documentNodeWithRequestedFlowsId(document);
+ if (!documentNodeId)
+ return;
+
+ ErrorString errorString;
+ m_frontend->namedFlowCreated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
+}
+
+void InspectorCSSAgent::willRemoveNamedFlow(Document* document, NamedFlow* namedFlow)
+{
+ int documentNodeId = documentNodeWithRequestedFlowsId(document);
+ if (!documentNodeId)
+ return;
+
+ if (m_updateRegionLayoutTask)
+ m_updateRegionLayoutTask->unschedule(namedFlow);
+
+ m_frontend->namedFlowRemoved(documentNodeId, namedFlow->name().string());
+}
+
+void InspectorCSSAgent::didUpdateRegionLayout(Document* document, NamedFlow* namedFlow)
+{
+ int documentNodeId = documentNodeWithRequestedFlowsId(document);
+ if (!documentNodeId)
+ return;
+
+ if (!m_updateRegionLayoutTask)
+ m_updateRegionLayoutTask = adoptPtr(new UpdateRegionLayoutTask(this));
+ m_updateRegionLayoutTask->scheduleFor(namedFlow, documentNodeId);
+}
+
+void InspectorCSSAgent::regionLayoutUpdated(NamedFlow* namedFlow, int documentNodeId)
+{
+ if (namedFlow->flowState() == NamedFlow::FlowStateNull)
+ return;
+
+ ErrorString errorString;
+ RefPtr<NamedFlow> protector(namedFlow);
+
+ m_frontend->regionLayoutUpdated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
+}
+
+void InspectorCSSAgent::activeStyleSheetsUpdated(const Vector<RefPtr<StyleSheet> >& newSheets)
+{
+ HashSet<CSSStyleSheet*> removedSheets;
+ for (CSSStyleSheetToInspectorStyleSheet::iterator it = m_cssStyleSheetToInspectorStyleSheet.begin(); it != m_cssStyleSheetToInspectorStyleSheet.end(); ++it) {
+ if (it->value->canBind())
+ removedSheets.add(it->key);
+ }
+
+ Vector<CSSStyleSheet*> newSheetsVector;
+ for (size_t i = 0, size = newSheets.size(); i < size; ++i) {
+ StyleSheet* newSheet = newSheets.at(i).get();
+ if (newSheet->isCSSStyleSheet()) {
+ StyleSheetAppender appender(m_cssStyleSheetToInspectorStyleSheet, newSheetsVector);
+ appender.run(static_cast<CSSStyleSheet*>(newSheet));
+ }
+ }
+
+ HashSet<CSSStyleSheet*> addedSheets;
+ for (size_t i = 0; i < newSheetsVector.size(); ++i) {
+ CSSStyleSheet* newCSSSheet = newSheetsVector.at(i);
+ if (removedSheets.contains(newCSSSheet))
+ removedSheets.remove(newCSSSheet);
+ else
+ addedSheets.add(newCSSSheet);
+ }
+
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::StyleSheetId> > removedIds = TypeBuilder::Array<TypeBuilder::CSS::StyleSheetId>::create();
+ for (HashSet<CSSStyleSheet*>::iterator it = removedSheets.begin(); it != removedSheets.end(); ++it) {
+ RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(*it);
+ ASSERT(inspectorStyleSheet);
+ if (m_idToInspectorStyleSheet.contains(inspectorStyleSheet->id())) {
+ String id = unbindStyleSheet(inspectorStyleSheet.get());
+ if (m_frontend)
+ m_frontend->styleSheetRemoved(id);
+ }
+ }
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader> > addedHeaders = TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>::create();
+ for (HashSet<CSSStyleSheet*>::iterator it = addedSheets.begin(); it != addedSheets.end(); ++it) {
+ if (!m_cssStyleSheetToInspectorStyleSheet.contains(*it)) {
+ InspectorStyleSheet* newStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(*it));
+ if (m_frontend)
+ m_frontend->styleSheetAdded(newStyleSheet->buildObjectForStyleSheetInfo());
+ }
+ }
+}
+
+bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType)
+{
+ if (m_nodeIdToForcedPseudoState.isEmpty())
+ return false;
+
+ int nodeId = m_domAgent->boundNodeId(element);
+ if (!nodeId)
+ return false;
+
+ NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
+ if (it == m_nodeIdToForcedPseudoState.end())
+ return false;
+
+ unsigned forcedPseudoState = it->value;
+ switch (pseudoType) {
+ case CSSSelector::PseudoActive:
+ return forcedPseudoState & PseudoActive;
+ case CSSSelector::PseudoFocus:
+ return forcedPseudoState & PseudoFocus;
+ case CSSSelector::PseudoHover:
+ return forcedPseudoState & PseudoHover;
+ case CSSSelector::PseudoVisited:
+ return forcedPseudoState & PseudoVisited;
+ default:
+ return false;
+ }
+}
+
+void InspectorCSSAgent::getMatchedStylesForNode(ErrorString* errorString, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> >& matchedCSSRules, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> >& pseudoIdMatches, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> >& inheritedEntries)
+{
+ Element* element = elementForId(errorString, nodeId);
+ if (!element)
+ return;
+
+ // Matched rules.
+ StyleResolver* styleResolver = element->ownerDocument()->styleResolver();
+ RefPtr<CSSRuleList> matchedRules = styleResolver->styleRulesForElement(element, StyleResolver::AllCSSRules);
+ matchedCSSRules = buildArrayForMatchedRuleList(matchedRules.get(), styleResolver, element);
+
+ // Pseudo elements.
+ if (!includePseudo || *includePseudo) {
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> > pseudoElements = TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches>::create();
+ for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
+ RefPtr<CSSRuleList> matchedRules = styleResolver->pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
+ if (matchedRules && matchedRules->length()) {
+ RefPtr<TypeBuilder::CSS::PseudoIdMatches> matches = TypeBuilder::CSS::PseudoIdMatches::create()
+ .setPseudoId(static_cast<int>(pseudoId))
+ .setMatches(buildArrayForMatchedRuleList(matchedRules.get(), styleResolver, element));
+ pseudoElements->addItem(matches.release());
+ }
+ }
+
+ pseudoIdMatches = pseudoElements.release();
+ }
+
+ // Inherited styles.
+ if (!includeInherited || *includeInherited) {
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> > entries = TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry>::create();
+ Element* parentElement = element->parentElement();
+ while (parentElement) {
+ StyleResolver* parentStyleResolver = parentElement->ownerDocument()->styleResolver();
+ RefPtr<CSSRuleList> parentMatchedRules = parentStyleResolver->styleRulesForElement(parentElement, StyleResolver::AllCSSRules);
+ RefPtr<TypeBuilder::CSS::InheritedStyleEntry> entry = TypeBuilder::CSS::InheritedStyleEntry::create()
+ .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules.get(), styleResolver, parentElement));
+ if (parentElement->style() && parentElement->style()->length()) {
+ InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
+ if (styleSheet)
+ entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
+ }
+
+ entries->addItem(entry.release());
+ parentElement = parentElement->parentElement();
+ }
+
+ inheritedEntries = entries.release();
+ }
+}
+
+void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<TypeBuilder::CSS::CSSStyle>& attributesStyle)
+{
+ Element* element = elementForId(errorString, nodeId);
+ if (!element)
+ return;
+
+ InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
+ if (!styleSheet)
+ return;
+
+ inlineStyle = styleSheet->buildObjectForStyle(element->style());
+ RefPtr<TypeBuilder::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
+ attributesStyle = attributes ? attributes.release() : 0;
+}
+
+void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> >& style)
+{
+ Element* element = elementForId(errorString, nodeId);
+ if (!element)
+ return;
+
+ RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(element, true);
+ RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
+ style = inspectorStyle->buildArrayForComputedStyle();
+}
+
+void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader> >& styleInfos)
+{
+ styleInfos = TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>::create();
+ Vector<InspectorStyleSheet*> styleSheets;
+ collectAllStyleSheets(styleSheets);
+ for (size_t i = 0; i < styleSheets.size(); ++i)
+ styleInfos->addItem(styleSheets.at(i)->buildObjectForStyleSheetInfo());
+}
+
+void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<TypeBuilder::CSS::CSSStyleSheetBody>& styleSheetObject)
+{
+ InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
+ if (!inspectorStyleSheet)
+ return;
+
+ styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
+}
+
+void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
+{
+ InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
+ if (!inspectorStyleSheet)
+ return;
+
+ inspectorStyleSheet->getText(result);
+}
+
+void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
+{
+ InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
+ if (!inspectorStyleSheet)
+ return;
+
+ ExceptionCode ec = 0;
+ m_domAgent->history()->perform(adoptPtr(new SetStyleSheetTextAction(inspectorStyleSheet, text)), ec);
+ *errorString = InspectorDOMAgent::toErrorString(ec);
+}
+
+void InspectorCSSAgent::setStyleText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, const String& text, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
+{
+ InspectorCSSId compoundId(fullStyleId);
+ ASSERT(!compoundId.isEmpty());
+
+ InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
+ if (!inspectorStyleSheet)
+ return;
+
+ ExceptionCode ec = 0;
+ m_domAgent->history()->perform(adoptPtr(new SetStyleTextAction(inspectorStyleSheet, compoundId, text)), ec);
+ if (!ec)
+ result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
+ *errorString = InspectorDOMAgent::toErrorString(ec);
+}
+
+void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
+{
+ InspectorCSSId compoundId(fullStyleId);
+ ASSERT(!compoundId.isEmpty());
+
+ InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
+ if (!inspectorStyleSheet)
+ return;
+
+ ExceptionCode ec = 0;
+ bool success = m_domAgent->history()->perform(adoptPtr(new SetPropertyTextAction(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite)), ec);
+ if (success)
+ result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
+ *errorString = InspectorDOMAgent::toErrorString(ec);
+}
+
+void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
+{
+ InspectorCSSId compoundId(fullStyleId);
+ ASSERT(!compoundId.isEmpty());
+
+ InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
+ if (!inspectorStyleSheet)
+ return;
+
+ ExceptionCode ec = 0;
+ bool success = m_domAgent->history()->perform(adoptPtr(new TogglePropertyAction(inspectorStyleSheet, compoundId, propertyIndex, disable)), ec);
+ if (success)
+ result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
+ *errorString = InspectorDOMAgent::toErrorString(ec);
+}
+
+void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
+{
+ InspectorCSSId compoundId(fullRuleId);
+ ASSERT(!compoundId.isEmpty());
+
+ InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
+ if (!inspectorStyleSheet)
+ return;
+
+ ExceptionCode ec = 0;
+ bool success = m_domAgent->history()->perform(adoptPtr(new SetRuleSelectorAction(inspectorStyleSheet, compoundId, selector)), ec);
+
+ if (success)
+ result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
+ *errorString = InspectorDOMAgent::toErrorString(ec);
+}
+
+void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
+{
+ Node* node = m_domAgent->assertNode(errorString, contextNodeId);
+ if (!node)
+ return;
+
+ InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
+ if (!inspectorStyleSheet) {
+ *errorString = "No target stylesheet found";
+ return;
+ }
+
+ ExceptionCode ec = 0;
+ OwnPtr<AddRuleAction> action = adoptPtr(new AddRuleAction(inspectorStyleSheet, selector));
+ AddRuleAction* rawAction = action.get();
+ bool success = m_domAgent->history()->perform(action.release(), ec);
+ if (!success) {
+ *errorString = InspectorDOMAgent::toErrorString(ec);
+ return;
+ }
+
+ InspectorCSSId ruleId = rawAction->newRuleId();
+ CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
+ result = inspectorStyleSheet->buildObjectForRule(rule);
+}
+
+void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> >& cssProperties)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> > properties = TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo>::create();
+ for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
+ CSSPropertyID id = convertToCSSPropertyID(i);
+ RefPtr<TypeBuilder::CSS::CSSPropertyInfo> property = TypeBuilder::CSS::CSSPropertyInfo::create()
+ .setName(getPropertyNameString(id));
+
+ const StylePropertyShorthand& shorthand = shorthandForProperty(id);
+ if (!shorthand.length()) {
+ properties->addItem(property.release());
+ continue;
+ }
+ RefPtr<TypeBuilder::Array<String> > longhands = TypeBuilder::Array<String>::create();
+ for (unsigned j = 0; j < shorthand.length(); ++j) {
+ CSSPropertyID longhandID = shorthand.properties()[j];
+ longhands->addItem(getPropertyNameString(longhandID));
+ }
+ property->setLonghands(longhands);
+ properties->addItem(property.release());
+ }
+ cssProperties = properties.release();
+}
+
+void InspectorCSSAgent::forcePseudoState(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>& forcedPseudoClasses)
+{
+ Element* element = m_domAgent->assertElement(errorString, nodeId);
+ if (!element)
+ return;
+
+ unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses.get());
+ NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
+ unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value;
+ bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState;
+ if (!needStyleRecalc)
+ return;
+
+ if (forcedPseudoState)
+ m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
+ else
+ m_nodeIdToForcedPseudoState.remove(nodeId);
+ element->ownerDocument()->styleResolverChanged(RecalcStyleImmediately);
+}
+
+void InspectorCSSAgent::getNamedFlowCollection(ErrorString* errorString, int documentNodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> >& result)
+{
+ Document* document = m_domAgent->assertDocument(errorString, documentNodeId);
+ if (!document)
+ return;
+
+ m_namedFlowCollectionsRequested.add(documentNodeId);
+
+ Vector<RefPtr<NamedFlow> > namedFlowsVector = document->namedFlows()->namedFlows();
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> > namedFlows = TypeBuilder::Array<TypeBuilder::CSS::NamedFlow>::create();
+
+ for (Vector<RefPtr<NamedFlow> >::iterator it = namedFlowsVector.begin(); it != namedFlowsVector.end(); ++it)
+ namedFlows->addItem(buildObjectForNamedFlow(errorString, it->get(), documentNodeId));
+
+ result = namedFlows.release();
+}
+
+void InspectorCSSAgent::startSelectorProfiler(ErrorString*)
+{
+ m_currentSelectorProfile = adoptPtr(new SelectorProfile());
+ m_state->setBoolean(CSSAgentState::isSelectorProfiling, true);
+}
+
+void InspectorCSSAgent::stopSelectorProfiler(ErrorString* errorString, RefPtr<TypeBuilder::CSS::SelectorProfile>& result)
+{
+ result = stopSelectorProfilerImpl(errorString, true);
+}
+
+PassRefPtr<TypeBuilder::CSS::SelectorProfile> InspectorCSSAgent::stopSelectorProfilerImpl(ErrorString*, bool needProfile)
+{
+ if (!m_state->getBoolean(CSSAgentState::isSelectorProfiling))
+ return 0;
+ m_state->setBoolean(CSSAgentState::isSelectorProfiling, false);
+ RefPtr<TypeBuilder::CSS::SelectorProfile> result;
+ if (m_frontend && needProfile)
+ result = m_currentSelectorProfile->toInspectorObject();
+ m_currentSelectorProfile.clear();
+ return result.release();
+}
+
+void InspectorCSSAgent::willMatchRule(StyleRule* rule, InspectorCSSOMWrappers& inspectorCSSOMWrappers, DocumentStyleSheetCollection* styleSheetCollection)
+{
+// printf("InspectorCSSAgent::willMatchRule %s\n", rule->selectorList().selectorsText().utf8().data());
+ if (m_currentSelectorProfile)
+ m_currentSelectorProfile->startSelector(inspectorCSSOMWrappers.getWrapperForRuleInSheets(rule, styleSheetCollection));
+}
+
+void InspectorCSSAgent::didMatchRule(bool matched)
+{
+ if (m_currentSelectorProfile)
+ m_currentSelectorProfile->commitSelector(matched);
+}
+
+void InspectorCSSAgent::willProcessRule(StyleRule* rule, StyleResolver* styleResolver)
+{
+ if (m_currentSelectorProfile)
+ m_currentSelectorProfile->startSelector(styleResolver->inspectorCSSOMWrappers().getWrapperForRuleInSheets(rule, styleResolver->document()->styleSheetCollection()));
+}
+
+void InspectorCSSAgent::didProcessRule()
+{
+ if (m_currentSelectorProfile)
+ m_currentSelectorProfile->commitSelectorTime();
+}
+
+InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
+{
+ NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
+ if (it == m_nodeToInspectorStyleSheet.end()) {
+ CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
+ if (!style)
+ return 0;
+
+ String newStyleSheetId = String::number(m_lastStyleSheetId++);
+ RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_domAgent->pageAgent(), newStyleSheetId, element, TypeBuilder::CSS::StyleSheetOrigin::Regular, this);
+ m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
+ m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
+ return inspectorStyleSheet.get();
+ }
+
+ return it->value.get();
+}
+
+Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
+{
+ Node* node = m_domAgent->nodeForId(nodeId);
+ if (!node) {
+ *errorString = "No node with given id found";
+ return 0;
+ }
+ if (node->nodeType() != Node::ELEMENT_NODE) {
+ *errorString = "Not an element node";
+ return 0;
+ }
+ return toElement(node);
+}
+
+int InspectorCSSAgent::documentNodeWithRequestedFlowsId(Document* document)
+{
+ int documentNodeId = m_domAgent->boundNodeId(document);
+ if (!documentNodeId || !m_namedFlowCollectionsRequested.contains(documentNodeId))
+ return 0;
+
+ return documentNodeId;
+}
+
+void InspectorCSSAgent::collectAllStyleSheets(Vector<InspectorStyleSheet*>& result)
+{
+ Vector<Document*> documents = m_domAgent->documents();
+ for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
+ StyleSheetList* list = (*it)->styleSheets();
+ for (unsigned i = 0; i < list->length(); ++i) {
+ StyleSheet* styleSheet = list->item(i);
+ if (styleSheet->isCSSStyleSheet())
+ collectStyleSheets(static_cast<CSSStyleSheet*>(styleSheet), result);
+ }
+ }
+}
+
+void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Vector<InspectorStyleSheet*>& result)
+{
+ InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
+ result.append(inspectorStyleSheet);
+ for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
+ CSSRule* rule = styleSheet->item(i);
+ if (rule->type() == CSSRule::IMPORT_RULE) {
+ CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet();
+ if (importedStyleSheet)
+ collectStyleSheets(importedStyleSheet, result);
+ }
+ }
+}
+
+InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
+{
+ RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
+ if (!inspectorStyleSheet) {
+ String id = String::number(m_lastStyleSheetId++);
+ Document* document = styleSheet->ownerDocument();
+ inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
+ m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
+ m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
+ if (m_creatingViaInspectorStyleSheet)
+ m_documentToInspectorStyleSheet.add(document, inspectorStyleSheet);
+ }
+ return inspectorStyleSheet.get();
+}
+
+String InspectorCSSAgent::unbindStyleSheet(InspectorStyleSheet* inspectorStyleSheet)
+{
+ String id = inspectorStyleSheet->id();
+ m_idToInspectorStyleSheet.remove(id);
+ if (inspectorStyleSheet->pageStyleSheet())
+ m_cssStyleSheetToInspectorStyleSheet.remove(inspectorStyleSheet->pageStyleSheet());
+ return id;
+}
+
+InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
+{
+ if (!document) {
+ ASSERT(!createIfAbsent);
+ return 0;
+ }
+
+ if (!document->isHTMLDocument() && !document->isSVGDocument())
+ return 0;
+
+ RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
+ if (inspectorStyleSheet || !createIfAbsent)
+ return inspectorStyleSheet.get();
+
+ ExceptionCode ec = 0;
+ RefPtr<Element> styleElement = document->createElement("style", ec);
+ if (!ec)
+ styleElement->setAttribute("type", "text/css", ec);
+ if (!ec) {
+ ContainerNode* targetNode;
+ // HEAD is absent in ImageDocuments, for example.
+ if (document->head())
+ targetNode = document->head();
+ else if (document->body())
+ targetNode = document->body();
+ else
+ return 0;
+
+ InlineStyleOverrideScope overrideScope(document);
+ m_creatingViaInspectorStyleSheet = true;
+ targetNode->appendChild(styleElement, ec);
+ // At this point the added stylesheet will get bound through the updateActiveStyleSheets() invocation.
+ // We just need to pick the respective InspectorStyleSheet from m_documentToInspectorStyleSheet.
+ m_creatingViaInspectorStyleSheet = false;
+ }
+ if (ec)
+ return 0;
+
+ return m_documentToInspectorStyleSheet.get(document).get();
+}
+
+InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
+{
+ IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
+ if (it == m_idToInspectorStyleSheet.end()) {
+ *errorString = "No style sheet with given id found";
+ return 0;
+ }
+ return it->value.get();
+}
+
+TypeBuilder::CSS::StyleSheetOrigin::Enum InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
+{
+ if (m_creatingViaInspectorStyleSheet)
+ return TypeBuilder::CSS::StyleSheetOrigin::Inspector;
+
+ TypeBuilder::CSS::StyleSheetOrigin::Enum origin = TypeBuilder::CSS::StyleSheetOrigin::Regular;
+ if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
+ origin = TypeBuilder::CSS::StyleSheetOrigin::User_agent;
+ else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
+ origin = TypeBuilder::CSS::StyleSheetOrigin::User;
+ else {
+ InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
+ if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
+ origin = TypeBuilder::CSS::StyleSheetOrigin::Inspector;
+ }
+ return origin;
+}
+
+PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule, StyleResolver* styleResolver)
+{
+ if (!rule)
+ return 0;
+
+ // CSSRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
+ // Since the inspector wants to walk the parent chain, we construct the full wrappers here.
+ // FIXME: This could be factored better. StyleResolver::styleRulesForElement should return a StyleRule vector, not a CSSRuleList.
+ if (!rule->parentStyleSheet()) {
+ rule = styleResolver->inspectorCSSOMWrappers().getWrapperForRuleInSheets(rule->styleRule(), styleResolver->document()->styleSheetCollection());
+ if (!rule)
+ return 0;
+ }
+ return bindStyleSheet(rule->parentStyleSheet())->buildObjectForRule(rule);
+}
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList, StyleResolver* styleResolver)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSRule>::create();
+ if (!ruleList)
+ return result.release();
+
+ for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
+ CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
+ RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule, styleResolver);
+ if (!ruleObject)
+ continue;
+ result->addItem(ruleObject);
+ }
+ return result.release();
+}
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > InspectorCSSAgent::buildArrayForMatchedRuleList(CSSRuleList* ruleList, StyleResolver* styleResolver, Element* element)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > result = TypeBuilder::Array<TypeBuilder::CSS::RuleMatch>::create();
+ if (!ruleList)
+ return result.release();
+
+ for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
+ CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
+ RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule, styleResolver);
+ if (!ruleObject)
+ continue;
+ RefPtr<TypeBuilder::Array<int> > matchingSelectors = TypeBuilder::Array<int>::create();
+ const CSSSelectorList& selectorList = rule->styleRule()->selectorList();
+ long index = 0;
+ for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
+ bool matched = element->webkitMatchesSelector(selector->selectorText(), IGNORE_EXCEPTION);
+ if (matched)
+ matchingSelectors->addItem(index);
+ ++index;
+ }
+ RefPtr<TypeBuilder::CSS::RuleMatch> match = TypeBuilder::CSS::RuleMatch::create()
+ .setRule(ruleObject)
+ .setMatchingSelectors(matchingSelectors);
+ result->addItem(match);
+ }
+
+ return result;
+}
+
+PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
+{
+ if (!element->isStyledElement())
+ return 0;
+
+ const StylePropertySet* attributeStyle = static_cast<StyledElement*>(element)->presentationAttributeStyle();
+ if (!attributeStyle)
+ return 0;
+
+ RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), const_cast<StylePropertySet*>(attributeStyle)->ensureCSSStyleDeclaration(), 0);
+ return inspectorStyle->buildObjectForStyle();
+}
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > InspectorCSSAgent::buildArrayForRegions(ErrorString* errorString, PassRefPtr<NodeList> regionList, int documentNodeId)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > regions = TypeBuilder::Array<TypeBuilder::CSS::Region>::create();
+
+ for (unsigned i = 0; i < regionList->length(); ++i) {
+ TypeBuilder::CSS::Region::RegionOverset::Enum regionOverset;
+
+ switch (toElement(regionList->item(i))->renderRegion()->regionState()) {
+ case RenderRegion::RegionFit:
+ regionOverset = TypeBuilder::CSS::Region::RegionOverset::Fit;
+ break;
+ case RenderRegion::RegionEmpty:
+ regionOverset = TypeBuilder::CSS::Region::RegionOverset::Empty;
+ break;
+ case RenderRegion::RegionOverset:
+ regionOverset = TypeBuilder::CSS::Region::RegionOverset::Overset;
+ break;
+ case RenderRegion::RegionUndefined:
+ continue;
+ default:
+ ASSERT_NOT_REACHED();
+ continue;
+ }
+
+ RefPtr<TypeBuilder::CSS::Region> region = TypeBuilder::CSS::Region::create()
+ .setRegionOverset(regionOverset)
+ // documentNodeId was previously asserted
+ .setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i)));
+
+ regions->addItem(region);
+ }
+
+ return regions.release();
+}
+
+PassRefPtr<TypeBuilder::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString* errorString, NamedFlow* webkitNamedFlow, int documentNodeId)
+{
+ RefPtr<NodeList> contentList = webkitNamedFlow->getContent();
+ RefPtr<TypeBuilder::Array<int> > content = TypeBuilder::Array<int>::create();
+
+ for (unsigned i = 0; i < contentList->length(); ++i) {
+ // documentNodeId was previously asserted
+ content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i)));
+ }
+
+ RefPtr<TypeBuilder::CSS::NamedFlow> namedFlow = TypeBuilder::CSS::NamedFlow::create()
+ .setDocumentNodeId(documentNodeId)
+ .setName(webkitNamedFlow->name().string())
+ .setOverset(webkitNamedFlow->overset())
+ .setContent(content)
+ .setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId));
+
+ return namedFlow.release();
+}
+
+void InspectorCSSAgent::didRemoveDocument(Document* document)
+{
+ if (document)
+ m_documentToInspectorStyleSheet.remove(document);
+}
+
+void InspectorCSSAgent::didRemoveDOMNode(Node* node)
+{
+ if (!node)
+ return;
+
+ int nodeId = m_domAgent->boundNodeId(node);
+ if (nodeId)
+ m_nodeIdToForcedPseudoState.remove(nodeId);
+
+ NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
+ if (it == m_nodeToInspectorStyleSheet.end())
+ return;
+
+ m_idToInspectorStyleSheet.remove(it->value->id());
+ m_nodeToInspectorStyleSheet.remove(node);
+}
+
+void InspectorCSSAgent::didModifyDOMAttr(Element* element)
+{
+ if (!element)
+ return;
+
+ NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
+ if (it == m_nodeToInspectorStyleSheet.end())
+ return;
+
+ it->value->didModifyElementAttribute();
+}
+
+void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
+{
+ if (m_frontend)
+ m_frontend->styleSheetChanged(styleSheet->id());
+}
+
+void InspectorCSSAgent::resetPseudoStates()
+{
+ HashSet<Document*> documentsToChange;
+ for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) {
+ Element* element = toElement(m_domAgent->nodeForId(it->key));
+ if (element && element->ownerDocument())
+ documentsToChange.add(element->ownerDocument());
+ }
+
+ m_nodeIdToForcedPseudoState.clear();
+ for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
+ (*it)->styleResolverChanged(RecalcStyleImmediately);
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorCSSAgent.h b/Source/core/inspector/InspectorCSSAgent.h
new file mode 100644
index 0000000..e4e2c63
--- /dev/null
+++ b/Source/core/inspector/InspectorCSSAgent.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2010, Google 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 InspectorCSSAgent_h
+#define InspectorCSSAgent_h
+
+#include "core/css/CSSSelector.h"
+#include "core/dom/SecurityContext.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/inspector/InspectorDOMAgent.h"
+#include "core/inspector/InspectorStyleSheet.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/page/ContentSecurityPolicy.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class CSSRule;
+class CSSRuleList;
+class CSSStyleDeclaration;
+class CSSStyleRule;
+class CSSStyleSheet;
+class Document;
+class DocumentStyleSheetCollection;
+class Element;
+class InspectorCSSOMWrappers;
+class InspectorFrontend;
+class InstrumentingAgents;
+class NameNodeMap;
+class Node;
+class NodeList;
+class SelectorProfile;
+class StyleResolver;
+class StyleRule;
+class StyleSheetVisitor;
+class UpdateRegionLayoutTask;
+
+typedef HashMap<CSSStyleSheet*, RefPtr<InspectorStyleSheet> > CSSStyleSheetToInspectorStyleSheet;
+
+class InspectorCSSAgent
+ : public InspectorBaseAgent<InspectorCSSAgent>
+ , public InspectorDOMAgent::DOMListener
+ , public InspectorBackendDispatcher::CSSCommandHandler
+ , public InspectorStyleSheet::Listener {
+ WTF_MAKE_NONCOPYABLE(InspectorCSSAgent);
+public:
+ class InlineStyleOverrideScope {
+ public:
+ InlineStyleOverrideScope(SecurityContext* context)
+ : m_contentSecurityPolicy(context->contentSecurityPolicy())
+ {
+ m_contentSecurityPolicy->setOverrideAllowInlineStyle(true);
+ }
+
+ ~InlineStyleOverrideScope()
+ {
+ m_contentSecurityPolicy->setOverrideAllowInlineStyle(false);
+ }
+
+ private:
+ ContentSecurityPolicy* m_contentSecurityPolicy;
+ };
+
+ static CSSStyleRule* asCSSStyleRule(CSSRule*);
+
+ static PassOwnPtr<InspectorCSSAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorDOMAgent* domAgent)
+ {
+ return adoptPtr(new InspectorCSSAgent(instrumentingAgents, state, domAgent));
+ }
+ ~InspectorCSSAgent();
+
+ bool forcePseudoState(Element*, CSSSelector::PseudoType);
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void discardAgent();
+ virtual void restore();
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ void reset();
+ void mediaQueryResultChanged();
+ void didCreateNamedFlow(Document*, NamedFlow*);
+ void willRemoveNamedFlow(Document*, NamedFlow*);
+ void didUpdateRegionLayout(Document*, NamedFlow*);
+ void regionLayoutUpdated(NamedFlow*, int documentNodeId);
+ void activeStyleSheetsUpdated(const Vector<RefPtr<StyleSheet> >& newSheets);
+
+ virtual void getComputedStyleForNode(ErrorString*, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> >&);
+ virtual void getInlineStylesForNode(ErrorString*, int nodeId, RefPtr<TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<TypeBuilder::CSS::CSSStyle>& attributes);
+ virtual void getMatchedStylesForNode(ErrorString*, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> >& matchedCSSRules, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> >& pseudoIdMatches, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> >& inheritedEntries);
+ virtual void getAllStyleSheets(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader> >& styleSheetInfos);
+ virtual void getStyleSheet(ErrorString*, const String& styleSheetId, RefPtr<TypeBuilder::CSS::CSSStyleSheetBody>& result);
+ virtual void getStyleSheetText(ErrorString*, const String& styleSheetId, String* result);
+ virtual void setStyleSheetText(ErrorString*, const String& styleSheetId, const String& text);
+ virtual void setStyleText(ErrorString*, const RefPtr<InspectorObject>& styleId, const String& text, RefPtr<TypeBuilder::CSS::CSSStyle>& result);
+ virtual void setPropertyText(ErrorString*, const RefPtr<InspectorObject>& styleId, int propertyIndex, const String& text, bool overwrite, RefPtr<TypeBuilder::CSS::CSSStyle>& result);
+ virtual void toggleProperty(ErrorString*, const RefPtr<InspectorObject>& styleId, int propertyIndex, bool disable, RefPtr<TypeBuilder::CSS::CSSStyle>& result);
+ virtual void setRuleSelector(ErrorString*, const RefPtr<InspectorObject>& ruleId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result);
+ virtual void addRule(ErrorString*, int contextNodeId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result);
+ virtual void getSupportedCSSProperties(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> >& result);
+ virtual void forcePseudoState(ErrorString*, int nodeId, const RefPtr<InspectorArray>& forcedPseudoClasses);
+ virtual void getNamedFlowCollection(ErrorString*, int documentNodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> >& result);
+
+ virtual void startSelectorProfiler(ErrorString*);
+ virtual void stopSelectorProfiler(ErrorString*, RefPtr<TypeBuilder::CSS::SelectorProfile>&);
+
+ PassRefPtr<TypeBuilder::CSS::SelectorProfile> stopSelectorProfilerImpl(ErrorString*, bool needProfile);
+ void willMatchRule(StyleRule*, InspectorCSSOMWrappers&, DocumentStyleSheetCollection*);
+ void didMatchRule(bool);
+ void willProcessRule(StyleRule*, StyleResolver*);
+ void didProcessRule();
+
+private:
+ class StyleSheetAction;
+ class SetStyleSheetTextAction;
+ class SetStyleTextAction;
+ class SetPropertyTextAction;
+ class TogglePropertyAction;
+ class SetRuleSelectorAction;
+ class AddRuleAction;
+
+ InspectorCSSAgent(InstrumentingAgents*, InspectorCompositeState*, InspectorDOMAgent*);
+
+ typedef HashMap<String, RefPtr<InspectorStyleSheet> > IdToInspectorStyleSheet;
+ typedef HashMap<Node*, RefPtr<InspectorStyleSheetForInlineStyle> > NodeToInspectorStyleSheet; // bogus "stylesheets" with elements' inline styles
+ typedef HashMap<RefPtr<Document>, RefPtr<InspectorStyleSheet> > DocumentToViaInspectorStyleSheet; // "via inspector" stylesheets
+ typedef HashMap<int, unsigned> NodeIdToForcedPseudoState;
+
+ void resetNonPersistentData();
+ InspectorStyleSheetForInlineStyle* asInspectorStyleSheet(Element* element);
+ Element* elementForId(ErrorString*, int nodeId);
+ int documentNodeWithRequestedFlowsId(Document*);
+ void collectAllStyleSheets(Vector<InspectorStyleSheet*>&);
+ void collectStyleSheets(CSSStyleSheet*, Vector<InspectorStyleSheet*>&);
+
+ InspectorStyleSheet* bindStyleSheet(CSSStyleSheet*);
+ String unbindStyleSheet(InspectorStyleSheet*);
+ InspectorStyleSheet* viaInspectorStyleSheet(Document*, bool createIfAbsent);
+ InspectorStyleSheet* assertStyleSheetForId(ErrorString*, const String&);
+ TypeBuilder::CSS::StyleSheetOrigin::Enum detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument);
+
+ PassRefPtr<TypeBuilder::CSS::CSSRule> buildObjectForRule(CSSStyleRule*, StyleResolver*);
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > buildArrayForRuleList(CSSRuleList*, StyleResolver*);
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > buildArrayForMatchedRuleList(CSSRuleList*, StyleResolver*, Element*);
+ PassRefPtr<TypeBuilder::CSS::CSSStyle> buildObjectForAttributesStyle(Element*);
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > buildArrayForRegions(ErrorString*, PassRefPtr<NodeList>, int documentNodeId);
+ PassRefPtr<TypeBuilder::CSS::NamedFlow> buildObjectForNamedFlow(ErrorString*, NamedFlow*, int documentNodeId);
+
+ // InspectorDOMAgent::DOMListener implementation
+ virtual void didRemoveDocument(Document*);
+ virtual void didRemoveDOMNode(Node*);
+ virtual void didModifyDOMAttr(Element*);
+
+ // InspectorCSSAgent::Listener implementation
+ virtual void styleSheetChanged(InspectorStyleSheet*);
+
+ void resetPseudoStates();
+
+ InspectorFrontend::CSS* m_frontend;
+ InspectorDOMAgent* m_domAgent;
+
+ IdToInspectorStyleSheet m_idToInspectorStyleSheet;
+ CSSStyleSheetToInspectorStyleSheet m_cssStyleSheetToInspectorStyleSheet;
+ NodeToInspectorStyleSheet m_nodeToInspectorStyleSheet;
+ DocumentToViaInspectorStyleSheet m_documentToInspectorStyleSheet;
+ NodeIdToForcedPseudoState m_nodeIdToForcedPseudoState;
+ HashSet<int> m_namedFlowCollectionsRequested;
+ OwnPtr<UpdateRegionLayoutTask> m_updateRegionLayoutTask;
+
+ int m_lastStyleSheetId;
+ bool m_creatingViaInspectorStyleSheet;
+
+ OwnPtr<SelectorProfile> m_currentSelectorProfile;
+
+ friend class StyleSheetBinder;
+};
+
+
+} // namespace WebCore
+
+#endif // !defined(InspectorCSSAgent_h)
diff --git a/Source/core/inspector/InspectorCanvasAgent.cpp b/Source/core/inspector/InspectorCanvasAgent.cpp
new file mode 100644
index 0000000..e31ee35
--- /dev/null
+++ b/Source/core/inspector/InspectorCanvasAgent.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorCanvasAgent.h"
+
+#include "HTMLNames.h"
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptObject.h"
+#include "bindings/v8/ScriptProfiler.h"
+#include "bindings/v8/ScriptState.h"
+#include "core/html/HTMLCanvasElement.h"
+#include "core/inspector/BindingVisitors.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptCanvasModule.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+
+using WebCore::TypeBuilder::Array;
+using WebCore::TypeBuilder::Canvas::ResourceId;
+using WebCore::TypeBuilder::Canvas::ResourceInfo;
+using WebCore::TypeBuilder::Canvas::ResourceState;
+using WebCore::TypeBuilder::Canvas::TraceLog;
+using WebCore::TypeBuilder::Canvas::TraceLogId;
+using WebCore::TypeBuilder::Network::FrameId;
+
+namespace WebCore {
+
+namespace CanvasAgentState {
+static const char canvasAgentEnabled[] = "canvasAgentEnabled";
+};
+
+InspectorCanvasAgent::InspectorCanvasAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorPageAgent* pageAgent, InjectedScriptManager* injectedScriptManager)
+ : InspectorBaseAgent<InspectorCanvasAgent>("Canvas", instrumentingAgents, state)
+ , m_pageAgent(pageAgent)
+ , m_injectedScriptManager(injectedScriptManager)
+ , m_frontend(0)
+ , m_enabled(false)
+{
+}
+
+InspectorCanvasAgent::~InspectorCanvasAgent()
+{
+}
+
+void InspectorCanvasAgent::setFrontend(InspectorFrontend* frontend)
+{
+ ASSERT(frontend);
+ m_frontend = frontend->canvas();
+}
+
+void InspectorCanvasAgent::clearFrontend()
+{
+ m_frontend = 0;
+ disable(0);
+}
+
+void InspectorCanvasAgent::restore()
+{
+ if (m_state->getBoolean(CanvasAgentState::canvasAgentEnabled)) {
+ ErrorString error;
+ enable(&error);
+ }
+}
+
+void InspectorCanvasAgent::enable(ErrorString*)
+{
+ if (m_enabled)
+ return;
+ m_enabled = true;
+ m_state->setBoolean(CanvasAgentState::canvasAgentEnabled, m_enabled);
+ m_instrumentingAgents->setInspectorCanvasAgent(this);
+ findFramesWithUninstrumentedCanvases();
+}
+
+void InspectorCanvasAgent::disable(ErrorString*)
+{
+ m_enabled = false;
+ m_state->setBoolean(CanvasAgentState::canvasAgentEnabled, m_enabled);
+ m_instrumentingAgents->setInspectorCanvasAgent(0);
+ m_framesWithUninstrumentedCanvases.clear();
+}
+
+void InspectorCanvasAgent::dropTraceLog(ErrorString* errorString, const TraceLogId& traceLogId)
+{
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
+ if (!module.hasNoValue())
+ module.dropTraceLog(errorString, traceLogId);
+}
+
+void InspectorCanvasAgent::hasUninstrumentedCanvases(ErrorString* errorString, bool* result)
+{
+ if (!checkIsEnabled(errorString))
+ return;
+ for (FramesWithUninstrumentedCanvases::iterator it = m_framesWithUninstrumentedCanvases.begin(); it != m_framesWithUninstrumentedCanvases.end(); ++it) {
+ if (it->value) {
+ *result = true;
+ return;
+ }
+ }
+ *result = false;
+}
+
+void InspectorCanvasAgent::captureFrame(ErrorString* errorString, const FrameId* frameId, TraceLogId* traceLogId)
+{
+ Frame* frame = frameId ? m_pageAgent->assertFrame(errorString, *frameId) : m_pageAgent->mainFrame();
+ if (!frame)
+ return;
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, mainWorldScriptState(frame));
+ if (!module.hasNoValue())
+ module.captureFrame(errorString, traceLogId);
+}
+
+void InspectorCanvasAgent::startCapturing(ErrorString* errorString, const FrameId* frameId, TraceLogId* traceLogId)
+{
+ Frame* frame = frameId ? m_pageAgent->assertFrame(errorString, *frameId) : m_pageAgent->mainFrame();
+ if (!frame)
+ return;
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, mainWorldScriptState(frame));
+ if (!module.hasNoValue())
+ module.startCapturing(errorString, traceLogId);
+}
+
+void InspectorCanvasAgent::stopCapturing(ErrorString* errorString, const TraceLogId& traceLogId)
+{
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
+ if (!module.hasNoValue())
+ module.stopCapturing(errorString, traceLogId);
+}
+
+void InspectorCanvasAgent::getTraceLog(ErrorString* errorString, const TraceLogId& traceLogId, const int* startOffset, const int* maxLength, RefPtr<TraceLog>& traceLog)
+{
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
+ if (!module.hasNoValue())
+ module.traceLog(errorString, traceLogId, startOffset, maxLength, &traceLog);
+}
+
+void InspectorCanvasAgent::replayTraceLog(ErrorString* errorString, const TraceLogId& traceLogId, int stepNo, RefPtr<ResourceState>& result)
+{
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
+ if (!module.hasNoValue())
+ module.replayTraceLog(errorString, traceLogId, stepNo, &result);
+}
+
+void InspectorCanvasAgent::getResourceInfo(ErrorString* errorString, const ResourceId& resourceId, RefPtr<ResourceInfo>& result)
+{
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, resourceId);
+ if (!module.hasNoValue())
+ module.resourceInfo(errorString, resourceId, &result);
+}
+
+void InspectorCanvasAgent::getResourceState(ErrorString* errorString, const TraceLogId& traceLogId, const ResourceId& resourceId, RefPtr<ResourceState>& result)
+{
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
+ if (!module.hasNoValue())
+ module.resourceState(errorString, traceLogId, resourceId, &result);
+}
+
+ScriptObject InspectorCanvasAgent::wrapCanvas2DRenderingContextForInstrumentation(const ScriptObject& context)
+{
+ ErrorString error;
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(&error, context);
+ if (module.hasNoValue())
+ return ScriptObject();
+ return notifyRenderingContextWasWrapped(module.wrapCanvas2DContext(context));
+}
+
+ScriptObject InspectorCanvasAgent::wrapWebGLRenderingContextForInstrumentation(const ScriptObject& glContext)
+{
+ ErrorString error;
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(&error, glContext);
+ if (module.hasNoValue())
+ return ScriptObject();
+ return notifyRenderingContextWasWrapped(module.wrapWebGLContext(glContext));
+}
+
+ScriptObject InspectorCanvasAgent::notifyRenderingContextWasWrapped(const ScriptObject& wrappedContext)
+{
+ ASSERT(m_frontend);
+ ScriptState* scriptState = wrappedContext.scriptState();
+ DOMWindow* domWindow = scriptState ? domWindowFromScriptState(scriptState) : 0;
+ Frame* frame = domWindow ? domWindow->frame() : 0;
+ if (frame && !m_framesWithUninstrumentedCanvases.contains(frame))
+ m_framesWithUninstrumentedCanvases.set(frame, false);
+ String frameId = m_pageAgent->frameId(frame);
+ if (!frameId.isEmpty())
+ m_frontend->contextCreated(frameId);
+ return wrappedContext;
+}
+
+InjectedScriptCanvasModule InspectorCanvasAgent::injectedScriptCanvasModule(ErrorString* errorString, ScriptState* scriptState)
+{
+ if (!checkIsEnabled(errorString))
+ return InjectedScriptCanvasModule();
+ InjectedScriptCanvasModule module = InjectedScriptCanvasModule::moduleForState(m_injectedScriptManager, scriptState);
+ if (module.hasNoValue()) {
+ ASSERT_NOT_REACHED();
+ *errorString = "Internal error: no Canvas module";
+ }
+ return module;
+}
+
+InjectedScriptCanvasModule InspectorCanvasAgent::injectedScriptCanvasModule(ErrorString* errorString, const ScriptObject& scriptObject)
+{
+ if (!checkIsEnabled(errorString))
+ return InjectedScriptCanvasModule();
+ if (scriptObject.hasNoValue()) {
+ ASSERT_NOT_REACHED();
+ *errorString = "Internal error: original ScriptObject has no value";
+ return InjectedScriptCanvasModule();
+ }
+ return injectedScriptCanvasModule(errorString, scriptObject.scriptState());
+}
+
+InjectedScriptCanvasModule InspectorCanvasAgent::injectedScriptCanvasModule(ErrorString* errorString, const String& objectId)
+{
+ if (!checkIsEnabled(errorString))
+ return InjectedScriptCanvasModule();
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected frame has gone";
+ return InjectedScriptCanvasModule();
+ }
+ return injectedScriptCanvasModule(errorString, injectedScript.scriptState());
+}
+
+void InspectorCanvasAgent::findFramesWithUninstrumentedCanvases()
+{
+ class NodeVisitor : public WrappedNodeVisitor {
+ public:
+ NodeVisitor(Page* page, FramesWithUninstrumentedCanvases& result)
+ : m_page(page)
+ , m_framesWithUninstrumentedCanvases(result)
+ {
+ }
+
+ virtual void visitNode(Node* node) OVERRIDE
+ {
+ if (!node->hasTagName(HTMLNames::canvasTag) || !node->document() || !node->document()->frame())
+ return;
+
+ Frame* frame = node->document()->frame();
+ if (frame->page() != m_page)
+ return;
+
+ HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(node);
+ if (canvas->renderingContext())
+ m_framesWithUninstrumentedCanvases.set(frame, true);
+ }
+
+ private:
+ Page* m_page;
+ FramesWithUninstrumentedCanvases& m_framesWithUninstrumentedCanvases;
+ } nodeVisitor(m_pageAgent->page(), m_framesWithUninstrumentedCanvases);
+
+ m_framesWithUninstrumentedCanvases.clear();
+ ScriptProfiler::visitNodeWrappers(&nodeVisitor);
+
+ for (FramesWithUninstrumentedCanvases::iterator it = m_framesWithUninstrumentedCanvases.begin(); it != m_framesWithUninstrumentedCanvases.end(); ++it) {
+ String frameId = m_pageAgent->frameId(it->key);
+ if (!frameId.isEmpty())
+ m_frontend->contextCreated(frameId);
+ }
+}
+
+bool InspectorCanvasAgent::checkIsEnabled(ErrorString* errorString) const
+{
+ if (m_enabled)
+ return true;
+ *errorString = "Canvas agent is not enabled";
+ return false;
+}
+
+void InspectorCanvasAgent::frameNavigated(Frame* frame)
+{
+ if (!m_enabled)
+ return;
+ if (frame == m_pageAgent->mainFrame()) {
+ for (FramesWithUninstrumentedCanvases::iterator it = m_framesWithUninstrumentedCanvases.begin(); it != m_framesWithUninstrumentedCanvases.end(); ++it)
+ m_framesWithUninstrumentedCanvases.set(it->key, false);
+ m_frontend->traceLogsRemoved(0, 0);
+ } else {
+ while (frame) {
+ if (m_framesWithUninstrumentedCanvases.contains(frame))
+ m_framesWithUninstrumentedCanvases.set(frame, false);
+ if (m_pageAgent->hasIdForFrame(frame)) {
+ String frameId = m_pageAgent->frameId(frame);
+ m_frontend->traceLogsRemoved(&frameId, 0);
+ }
+ frame = frame->tree()->traverseNext();
+ }
+ }
+}
+
+void InspectorCanvasAgent::frameDetachedFromParent(Frame* frame)
+{
+ if (m_enabled)
+ m_framesWithUninstrumentedCanvases.remove(frame);
+}
+
+void InspectorCanvasAgent::didBeginFrame()
+{
+ if (!m_enabled)
+ return;
+ ErrorString error;
+ for (FramesWithUninstrumentedCanvases::iterator it = m_framesWithUninstrumentedCanvases.begin(); it != m_framesWithUninstrumentedCanvases.end(); ++it) {
+ InjectedScriptCanvasModule module = injectedScriptCanvasModule(&error, mainWorldScriptState(it->key));
+ if (!module.hasNoValue())
+ module.markFrameEnd();
+ }
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorCanvasAgent.h b/Source/core/inspector/InspectorCanvasAgent.h
new file mode 100644
index 0000000..b672cd0
--- /dev/null
+++ b/Source/core/inspector/InspectorCanvasAgent.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorCanvasAgent_h
+#define InspectorCanvasAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "InspectorTypeBuilder.h"
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Frame;
+class InjectedScriptCanvasModule;
+class InjectedScriptManager;
+class InspectorPageAgent;
+class InspectorState;
+class InstrumentingAgents;
+class ScriptObject;
+
+typedef String ErrorString;
+
+class InspectorCanvasAgent : public InspectorBaseAgent<InspectorCanvasAgent>, public InspectorBackendDispatcher::CanvasCommandHandler {
+public:
+ static PassOwnPtr<InspectorCanvasAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorPageAgent* pageAgent, InjectedScriptManager* injectedScriptManager)
+ {
+ return adoptPtr(new InspectorCanvasAgent(instrumentingAgents, state, pageAgent, injectedScriptManager));
+ }
+ ~InspectorCanvasAgent();
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ void frameNavigated(Frame*);
+ void frameDetachedFromParent(Frame*);
+ void didBeginFrame();
+
+ // Called from InspectorCanvasInstrumentation.
+ ScriptObject wrapCanvas2DRenderingContextForInstrumentation(const ScriptObject&);
+ ScriptObject wrapWebGLRenderingContextForInstrumentation(const ScriptObject&);
+
+ // Called from the front-end.
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void dropTraceLog(ErrorString*, const TypeBuilder::Canvas::TraceLogId&);
+ virtual void hasUninstrumentedCanvases(ErrorString*, bool*);
+ virtual void captureFrame(ErrorString*, const TypeBuilder::Network::FrameId*, TypeBuilder::Canvas::TraceLogId*);
+ virtual void startCapturing(ErrorString*, const TypeBuilder::Network::FrameId*, TypeBuilder::Canvas::TraceLogId*);
+ virtual void stopCapturing(ErrorString*, const TypeBuilder::Canvas::TraceLogId&);
+ virtual void getTraceLog(ErrorString*, const TypeBuilder::Canvas::TraceLogId&, const int*, const int*, RefPtr<TypeBuilder::Canvas::TraceLog>&);
+ virtual void replayTraceLog(ErrorString*, const TypeBuilder::Canvas::TraceLogId&, int, RefPtr<TypeBuilder::Canvas::ResourceState>&);
+ virtual void getResourceInfo(ErrorString*, const TypeBuilder::Canvas::ResourceId&, RefPtr<TypeBuilder::Canvas::ResourceInfo>&);
+ virtual void getResourceState(ErrorString*, const TypeBuilder::Canvas::TraceLogId&, const TypeBuilder::Canvas::ResourceId&, RefPtr<TypeBuilder::Canvas::ResourceState>&);
+
+private:
+ InspectorCanvasAgent(InstrumentingAgents*, InspectorCompositeState*, InspectorPageAgent*, InjectedScriptManager*);
+
+ InjectedScriptCanvasModule injectedScriptCanvasModule(ErrorString*, ScriptState*);
+ InjectedScriptCanvasModule injectedScriptCanvasModule(ErrorString*, const ScriptObject&);
+ InjectedScriptCanvasModule injectedScriptCanvasModule(ErrorString*, const String&);
+
+ void findFramesWithUninstrumentedCanvases();
+ bool checkIsEnabled(ErrorString*) const;
+ ScriptObject notifyRenderingContextWasWrapped(const ScriptObject&);
+
+ InspectorPageAgent* m_pageAgent;
+ InjectedScriptManager* m_injectedScriptManager;
+ InspectorFrontend::Canvas* m_frontend;
+ bool m_enabled;
+ // Contains all frames with canvases, value is true only for frames that have an uninstrumented canvas.
+ typedef HashMap<Frame*, bool> FramesWithUninstrumentedCanvases;
+ FramesWithUninstrumentedCanvases m_framesWithUninstrumentedCanvases;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorCanvasAgent_h)
diff --git a/Source/core/inspector/InspectorCanvasInstrumentation.h b/Source/core/inspector/InspectorCanvasInstrumentation.h
new file mode 100644
index 0000000..efdf7ec
--- /dev/null
+++ b/Source/core/inspector/InspectorCanvasInstrumentation.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorCanvasInstrumentation_h
+#define InspectorCanvasInstrumentation_h
+
+#include "bindings/v8/ScriptObject.h"
+#include "core/inspector/InspectorCanvasAgent.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+namespace InspectorInstrumentation {
+
+inline ScriptObject wrapCanvas2DRenderingContextForInstrumentation(Document* document, const ScriptObject& context)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document)) {
+ if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+ return canvasAgent->wrapCanvas2DRenderingContextForInstrumentation(context);
+ }
+ return ScriptObject();
+}
+
+inline ScriptObject wrapWebGLRenderingContextForInstrumentation(Document* document, const ScriptObject& glContext)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document)) {
+ if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+ return canvasAgent->wrapWebGLRenderingContextForInstrumentation(glContext);
+ }
+ return ScriptObject();
+}
+
+} // namespace InspectorInstrumentation
+
+} // namespace WebCore
+
+#endif // !defined(InspectorCanvasInstrumentation_h)
diff --git a/Source/core/inspector/InspectorClient.cpp b/Source/core/inspector/InspectorClient.cpp
new file mode 100644
index 0000000..3bb1c62
--- /dev/null
+++ b/Source/core/inspector/InspectorClient.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorClient.h"
+
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/ScriptSourceCode.h"
+#include "bindings/v8/ScriptValue.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+
+namespace WebCore {
+
+bool InspectorClient::doDispatchMessageOnFrontendPage(Page* frontendPage, const String& message)
+{
+ if (!frontendPage)
+ return false;
+
+ Frame* frame = frontendPage->mainFrame();
+ if (!frame)
+ return false;
+
+ ScriptController* scriptController = frame->script();
+ if (!scriptController)
+ return false;
+
+ String dispatchToFrontend = "InspectorFrontendAPI.dispatchMessageAsync(" + message + ");";
+
+ // FIXME: This should execute the script in the appropriate world.
+ scriptController->evaluate(ScriptSourceCode(dispatchToFrontend));
+ return true;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorClient.h b/Source/core/inspector/InspectorClient.h
new file mode 100644
index 0000000..2b95404
--- /dev/null
+++ b/Source/core/inspector/InspectorClient.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google 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 COMPUTER, INC. ``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 COMPUTER, INC. OR
+ * 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 InspectorClient_h
+#define InspectorClient_h
+
+#include "core/inspector/InspectorStateClient.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+
+namespace WebCore {
+
+class InspectorController;
+class InspectorFrontendChannel;
+class Frame;
+class Page;
+
+class InspectorClient : public InspectorStateClient {
+public:
+ virtual void highlight() = 0;
+ virtual void hideHighlight() = 0;
+
+ virtual void clearBrowserCache() { }
+ virtual void clearBrowserCookies() { }
+
+ typedef void (*TraceEventCallback)(char phase, const unsigned char*, const char* name, unsigned long long id,
+ int numArgs, const char* const* argNames, const unsigned char* argTypes, const unsigned long long* argValues,
+ unsigned char flags);
+ virtual void setTraceEventCallback(TraceEventCallback) { }
+
+ virtual void overrideDeviceMetrics(int /*width*/, int /*height*/, float /*fontScaleFactor*/, bool /*fitWindow*/) { }
+ virtual void autoZoomPageToFitWidth() { }
+
+ virtual bool overridesShowPaintRects() { return false; }
+ virtual void setShowPaintRects(bool) { }
+
+ virtual void setShowDebugBorders(bool) { }
+
+ virtual bool canShowFPSCounter() { return false; }
+ virtual void setShowFPSCounter(bool) { }
+
+ virtual bool canContinuouslyPaint() { return false; }
+ virtual void setContinuousPaintingEnabled(bool) { }
+
+ virtual void getAllocatedObjects(HashSet<const void*>&) { }
+ virtual void dumpUncountedAllocatedObjects(const HashMap<const void*, size_t>&) { }
+
+ static bool doDispatchMessageOnFrontendPage(Page* frontendPage, const String& message);
+
+protected:
+ virtual ~InspectorClient() { }
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorClient_h)
diff --git a/Source/core/inspector/InspectorConsoleAgent.cpp b/Source/core/inspector/InspectorConsoleAgent.cpp
new file mode 100644
index 0000000..1aff9ac
--- /dev/null
+++ b/Source/core/inspector/InspectorConsoleAgent.cpp
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2011 Google 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 "core/inspector/InspectorConsoleAgent.h"
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptCallStackFactory.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/ScriptObject.h"
+#include "bindings/v8/ScriptProfiler.h"
+#include "core/inspector/ConsoleMessage.h"
+#include "core/inspector/InjectedScriptHost.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/inspector/ScriptArguments.h"
+#include "core/inspector/ScriptCallFrame.h"
+#include "core/inspector/ScriptCallStack.h"
+#include "core/page/Console.h"
+#include "core/page/DOMWindow.h"
+#include "core/platform/network/ResourceError.h"
+#include "core/platform/network/ResourceResponse.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+static const unsigned maximumConsoleMessages = 1000;
+static const int expireConsoleMessagesStep = 100;
+
+namespace ConsoleAgentState {
+static const char monitoringXHR[] = "monitoringXHR";
+static const char consoleMessagesEnabled[] = "consoleMessagesEnabled";
+}
+
+int InspectorConsoleAgent::s_enabledAgentCount = 0;
+
+InspectorConsoleAgent::InspectorConsoleAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager)
+ : InspectorBaseAgent<InspectorConsoleAgent>("Console", instrumentingAgents, state)
+ , m_injectedScriptManager(injectedScriptManager)
+ , m_frontend(0)
+ , m_previousMessage(0)
+ , m_expiredConsoleMessageCount(0)
+ , m_enabled(false)
+{
+ m_instrumentingAgents->setInspectorConsoleAgent(this);
+}
+
+InspectorConsoleAgent::~InspectorConsoleAgent()
+{
+ m_instrumentingAgents->setInspectorConsoleAgent(0);
+ m_instrumentingAgents = 0;
+ m_state = 0;
+ m_injectedScriptManager = 0;
+}
+
+void InspectorConsoleAgent::enable(ErrorString*)
+{
+ if (m_enabled)
+ return;
+ m_enabled = true;
+ if (!s_enabledAgentCount)
+ ScriptController::setCaptureCallStackForUncaughtExceptions(true);
+ ++s_enabledAgentCount;
+
+ m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, true);
+
+ if (m_expiredConsoleMessageCount) {
+ ConsoleMessage expiredMessage(!isWorkerAgent(), OtherMessageSource, LogMessageType, WarningMessageLevel, String::format("%d console messages are not shown.", m_expiredConsoleMessageCount));
+ expiredMessage.addToFrontend(m_frontend, m_injectedScriptManager, false);
+ }
+
+ size_t messageCount = m_consoleMessages.size();
+ for (size_t i = 0; i < messageCount; ++i)
+ m_consoleMessages[i]->addToFrontend(m_frontend, m_injectedScriptManager, false);
+}
+
+void InspectorConsoleAgent::disable(ErrorString*)
+{
+ if (!m_enabled)
+ return;
+ m_enabled = false;
+ if (!(--s_enabledAgentCount))
+ ScriptController::setCaptureCallStackForUncaughtExceptions(false);
+ m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, false);
+}
+
+void InspectorConsoleAgent::clearMessages(ErrorString*)
+{
+ m_consoleMessages.clear();
+ m_expiredConsoleMessageCount = 0;
+ m_previousMessage = 0;
+ m_injectedScriptManager->releaseObjectGroup("console");
+ if (m_frontend && m_enabled)
+ m_frontend->messagesCleared();
+}
+
+void InspectorConsoleAgent::reset()
+{
+ ErrorString error;
+ clearMessages(&error);
+ m_times.clear();
+ m_counts.clear();
+}
+
+void InspectorConsoleAgent::restore()
+{
+ if (m_state->getBoolean(ConsoleAgentState::consoleMessagesEnabled)) {
+ m_frontend->messagesCleared();
+ ErrorString error;
+ enable(&error);
+ }
+}
+
+void InspectorConsoleAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->console();
+}
+
+void InspectorConsoleAgent::clearFrontend()
+{
+ m_frontend = 0;
+ String errorString;
+ disable(&errorString);
+}
+
+void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier)
+{
+ if (type == ClearMessageType) {
+ ErrorString error;
+ clearMessages(&error);
+ }
+
+ addConsoleMessage(adoptPtr(new ConsoleMessage(!isWorkerAgent(), source, type, level, message, callStack, requestIdentifier)));
+}
+
+void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, ScriptState* state, PassRefPtr<ScriptArguments> arguments, unsigned long requestIdentifier)
+{
+ if (type == ClearMessageType) {
+ ErrorString error;
+ clearMessages(&error);
+ }
+
+ addConsoleMessage(adoptPtr(new ConsoleMessage(!isWorkerAgent(), source, type, level, message, arguments, state, requestIdentifier)));
+}
+
+void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& scriptId, unsigned lineNumber, ScriptState* state, unsigned long requestIdentifier)
+{
+ if (type == ClearMessageType) {
+ ErrorString error;
+ clearMessages(&error);
+ }
+
+ // Ignore errors like "*property=value". This trick is used for IE7: http://stackoverflow.com/questions/4563651/what-does-an-asterisk-do-in-a-css-property-name
+ if (source == CSSMessageSource && message.contains(": *"))
+ return;
+
+ bool canGenerateCallStack = !isWorkerAgent() && m_frontend;
+ addConsoleMessage(adoptPtr(new ConsoleMessage(canGenerateCallStack, source, type, level, message, scriptId, lineNumber, state, requestIdentifier)));
+}
+
+Vector<unsigned> InspectorConsoleAgent::consoleMessageArgumentCounts()
+{
+ Vector<unsigned> result(m_consoleMessages.size());
+ for (size_t i = 0; i < m_consoleMessages.size(); i++)
+ result[i] = m_consoleMessages[i]->argumentCount();
+ return result;
+}
+
+void InspectorConsoleAgent::startTiming(const String& title)
+{
+ // Follow Firebug's behavior of requiring a title that is not null or
+ // undefined for timing functions
+ if (title.isNull())
+ return;
+
+ m_times.add(title, monotonicallyIncreasingTime());
+}
+
+void InspectorConsoleAgent::stopTiming(const String& title, PassRefPtr<ScriptCallStack> callStack)
+{
+ // Follow Firebug's behavior of requiring a title that is not null or
+ // undefined for timing functions
+ if (title.isNull())
+ return;
+
+ HashMap<String, double>::iterator it = m_times.find(title);
+ if (it == m_times.end())
+ return;
+
+ double startTime = it->value;
+ m_times.remove(it);
+
+ double elapsed = monotonicallyIncreasingTime() - startTime;
+ String message = title + String::format(": %.3fms", elapsed * 1000);
+ const ScriptCallFrame& lastCaller = callStack->at(0);
+ addMessageToConsole(ConsoleAPIMessageSource, TimingMessageType, DebugMessageLevel, message, lastCaller.sourceURL(), lastCaller.lineNumber());
+}
+
+void InspectorConsoleAgent::count(ScriptState* state, PassRefPtr<ScriptArguments> arguments)
+{
+ RefPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(state));
+ const ScriptCallFrame& lastCaller = callStack->at(0);
+ // Follow Firebug's behavior of counting with null and undefined title in
+ // the same bucket as no argument
+ String title;
+ arguments->getFirstArgumentAsString(title);
+ String identifier = title.isEmpty() ? String(lastCaller.sourceURL() + ':' + String::number(lastCaller.lineNumber()))
+ : String(title + '@');
+
+ HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
+ int count;
+ if (it == m_counts.end())
+ count = 1;
+ else {
+ count = it->value + 1;
+ m_counts.remove(it);
+ }
+
+ m_counts.add(identifier, count);
+
+ String message = title + ": " + String::number(count);
+ addMessageToConsole(ConsoleAPIMessageSource, LogMessageType, DebugMessageLevel, message, callStack);
+}
+
+void InspectorConsoleAgent::frameWindowDiscarded(DOMWindow* window)
+{
+ size_t messageCount = m_consoleMessages.size();
+ for (size_t i = 0; i < messageCount; ++i)
+ m_consoleMessages[i]->windowCleared(window);
+ m_injectedScriptManager->discardInjectedScriptsFor(window);
+}
+
+void InspectorConsoleAgent::didFinishXHRLoading(ThreadableLoaderClient*, unsigned long requestIdentifier, const String&, const String& url, const String& sendURL, unsigned sendLineNumber)
+{
+ if (m_frontend && m_state->getBoolean(ConsoleAgentState::monitoringXHR)) {
+ String message = "XHR finished loading: \"" + url + "\".";
+ addMessageToConsole(NetworkMessageSource, LogMessageType, DebugMessageLevel, message, sendURL, sendLineNumber, 0, requestIdentifier);
+ }
+
+
+}
+
+void InspectorConsoleAgent::didReceiveResourceResponse(unsigned long requestIdentifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader*)
+{
+ if (!loader)
+ return;
+ if (response.httpStatusCode() >= 400) {
+ String message = "Failed to load resource: the server responded with a status of " + String::number(response.httpStatusCode()) + " (" + response.httpStatusText() + ')';
+ addMessageToConsole(NetworkMessageSource, LogMessageType, ErrorMessageLevel, message, response.url().string(), 0, 0, requestIdentifier);
+ }
+}
+
+void InspectorConsoleAgent::didFailLoading(unsigned long requestIdentifier, DocumentLoader*, const ResourceError& error)
+{
+ if (error.isCancellation()) // Report failures only.
+ return;
+ StringBuilder message;
+ message.appendLiteral("Failed to load resource");
+ if (!error.localizedDescription().isEmpty()) {
+ message.appendLiteral(": ");
+ message.append(error.localizedDescription());
+ }
+ addMessageToConsole(NetworkMessageSource, LogMessageType, ErrorMessageLevel, message.toString(), error.failingURL(), 0, 0, requestIdentifier);
+}
+
+void InspectorConsoleAgent::setMonitoringXHREnabled(ErrorString*, bool enabled)
+{
+ m_state->setBoolean(ConsoleAgentState::monitoringXHR, enabled);
+}
+
+static bool isGroupMessage(MessageType type)
+{
+ return type == StartGroupMessageType
+ || type == StartGroupCollapsedMessageType
+ || type == EndGroupMessageType;
+}
+
+void InspectorConsoleAgent::addConsoleMessage(PassOwnPtr<ConsoleMessage> consoleMessage)
+{
+ ASSERT_ARG(consoleMessage, consoleMessage);
+
+ if (m_previousMessage && !isGroupMessage(m_previousMessage->type()) && m_previousMessage->isEqual(consoleMessage.get())) {
+ m_previousMessage->incrementCount();
+ if (m_frontend && m_enabled)
+ m_previousMessage->updateRepeatCountInConsole(m_frontend);
+ } else {
+ m_previousMessage = consoleMessage.get();
+ m_consoleMessages.append(consoleMessage);
+ if (m_frontend && m_enabled)
+ m_previousMessage->addToFrontend(m_frontend, m_injectedScriptManager, true);
+ }
+
+ if (!m_frontend && m_consoleMessages.size() >= maximumConsoleMessages) {
+ m_expiredConsoleMessageCount += expireConsoleMessagesStep;
+ m_consoleMessages.remove(0, expireConsoleMessagesStep);
+ }
+}
+
+class InspectableHeapObject : public InjectedScriptHost::InspectableObject {
+public:
+ explicit InspectableHeapObject(int heapObjectId) : m_heapObjectId(heapObjectId) { }
+ virtual ScriptValue get(ScriptState*)
+ {
+ return ScriptProfiler::objectByHeapObjectId(m_heapObjectId);
+ }
+private:
+ int m_heapObjectId;
+};
+
+void InspectorConsoleAgent::addInspectedHeapObject(ErrorString*, int inspectedHeapObjectId)
+{
+ m_injectedScriptManager->injectedScriptHost()->addInspectedObject(adoptPtr(new InspectableHeapObject(inspectedHeapObjectId)));
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorConsoleAgent.h b/Source/core/inspector/InspectorConsoleAgent.h
new file mode 100644
index 0000000..23c7df1
--- /dev/null
+++ b/Source/core/inspector/InspectorConsoleAgent.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 Google 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 InspectorConsoleAgent_h
+#define InspectorConsoleAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/ConsoleAPITypes.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/page/ConsoleTypes.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ConsoleMessage;
+class DocumentLoader;
+class DOMWindow;
+class InspectorFrontend;
+class InspectorState;
+class InjectedScriptManager;
+class InstrumentingAgents;
+class ResourceError;
+class ResourceLoader;
+class ResourceResponse;
+class ScriptArguments;
+class ScriptCallStack;
+class ScriptProfile;
+class ThreadableLoaderClient;
+
+typedef String ErrorString;
+
+class InspectorConsoleAgent : public InspectorBaseAgent<InspectorConsoleAgent>, public InspectorBackendDispatcher::ConsoleCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorConsoleAgent);
+public:
+ InspectorConsoleAgent(InstrumentingAgents*, InspectorCompositeState*, InjectedScriptManager*);
+ virtual ~InspectorConsoleAgent();
+
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void clearMessages(ErrorString*);
+ bool enabled() { return m_enabled; }
+ void reset();
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, ScriptState*, PassRefPtr<ScriptArguments>, unsigned long requestIdentifier = 0);
+ void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, const String& scriptId, unsigned lineNumber, ScriptState* = 0, unsigned long requestIdentifier = 0);
+
+ // FIXME: Remove once we no longer generate stacks outside of Inspector.
+ void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, PassRefPtr<ScriptCallStack>, unsigned long requestIdentifier = 0);
+
+ Vector<unsigned> consoleMessageArgumentCounts();
+
+ void startTiming(const String& title);
+ void stopTiming(const String& title, PassRefPtr<ScriptCallStack>);
+ void count(ScriptState*, PassRefPtr<ScriptArguments>);
+
+ void frameWindowDiscarded(DOMWindow*);
+
+ void didFinishXHRLoading(ThreadableLoaderClient*, unsigned long requestIdentifier, const String&, const String& url, const String& sendURL, unsigned sendLineNumber);
+ void didReceiveResourceResponse(unsigned long requestIdentifier, DocumentLoader*, const ResourceResponse& response, ResourceLoader*);
+ void didFailLoading(unsigned long requestIdentifier, DocumentLoader*, const ResourceError&);
+ void addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL);
+ void addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL);
+ virtual void setMonitoringXHREnabled(ErrorString*, bool enabled);
+ virtual void addInspectedNode(ErrorString*, int nodeId) = 0;
+ virtual void addInspectedHeapObject(ErrorString*, int inspectedHeapObjectId);
+
+ virtual bool isWorkerAgent() = 0;
+
+protected:
+ void addConsoleMessage(PassOwnPtr<ConsoleMessage>);
+
+ InjectedScriptManager* m_injectedScriptManager;
+ InspectorFrontend::Console* m_frontend;
+ ConsoleMessage* m_previousMessage;
+ Vector<OwnPtr<ConsoleMessage> > m_consoleMessages;
+ int m_expiredConsoleMessageCount;
+ HashMap<String, unsigned> m_counts;
+ HashMap<String, double> m_times;
+ bool m_enabled;
+private:
+ static int s_enabledAgentCount;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorConsoleAgent_h)
diff --git a/Source/core/inspector/InspectorConsoleInstrumentation.h b/Source/core/inspector/InspectorConsoleInstrumentation.h
new file mode 100644
index 0000000..150400b
--- /dev/null
+++ b/Source/core/inspector/InspectorConsoleInstrumentation.h
@@ -0,0 +1,128 @@
+/*
+* Copyright (C) 2011 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 InspectorConsoleInstrumentation_h
+#define InspectorConsoleInstrumentation_h
+
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/ScriptArguments.h"
+#include "core/inspector/ScriptCallStack.h"
+#include "core/inspector/ScriptProfile.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+namespace InspectorInstrumentation {
+
+void addMessageToConsoleImpl(InstrumentingAgents*, MessageSource, MessageType, MessageLevel, const String& message, ScriptState*, PassRefPtr<ScriptArguments>, unsigned long requestIdentifier);
+void addMessageToConsoleImpl(InstrumentingAgents*, MessageSource, MessageType, MessageLevel, const String& message, const String& scriptId, unsigned lineNumber, ScriptState*, unsigned long requestIdentifier);
+// FIXME: Remove once we no longer generate stacks outside of Inspector.
+void addMessageToConsoleImpl(InstrumentingAgents*, MessageSource, MessageType, MessageLevel, const String& message, PassRefPtr<ScriptCallStack>, unsigned long requestIdentifier);
+void consoleCountImpl(InstrumentingAgents*, ScriptState*, PassRefPtr<ScriptArguments>);
+void startConsoleTimingImpl(InstrumentingAgents*, Frame*, const String& title);
+void stopConsoleTimingImpl(InstrumentingAgents*, Frame*, const String& title, PassRefPtr<ScriptCallStack>);
+void consoleTimeStampImpl(InstrumentingAgents*, Frame*, PassRefPtr<ScriptArguments>);
+void addStartProfilingMessageToConsoleImpl(InstrumentingAgents*, const String& title, unsigned lineNumber, const String& sourceURL);
+void addProfileImpl(InstrumentingAgents*, RefPtr<ScriptProfile>, PassRefPtr<ScriptCallStack>);
+
+inline void addMessageToConsole(Page* page, MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier = 0)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ addMessageToConsoleImpl(instrumentingAgents, source, type, level, message, callStack, requestIdentifier);
+}
+
+inline void addMessageToConsole(Page* page, MessageSource source, MessageType type, MessageLevel level, const String& message, ScriptState* state, PassRefPtr<ScriptArguments> arguments, unsigned long requestIdentifier = 0)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ addMessageToConsoleImpl(instrumentingAgents, source, type, level, message, state, arguments, requestIdentifier);
+}
+
+inline void addMessageToConsole(Page* page, MessageSource source, MessageType type, MessageLevel level, const String& message, const String& scriptId, unsigned lineNumber, ScriptState* state = 0, unsigned long requestIdentifier = 0)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ addMessageToConsoleImpl(instrumentingAgents, source, type, level, message, scriptId, lineNumber, state, requestIdentifier);
+}
+
+// FIXME: Convert to ScriptArguments to match non-worker context.
+inline void addMessageToConsole(WorkerContext* workerContext, MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier = 0)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForWorkerContext(workerContext))
+ addMessageToConsoleImpl(instrumentingAgents, source, type, level, message, callStack, requestIdentifier);
+}
+
+inline void addMessageToConsole(WorkerContext* workerContext, MessageSource source, MessageType type, MessageLevel level, const String& message, const String& scriptId, unsigned lineNumber, ScriptState* state, unsigned long requestIdentifier = 0)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForWorkerContext(workerContext))
+ addMessageToConsoleImpl(instrumentingAgents, source, type, level, message, scriptId, lineNumber, state, requestIdentifier);
+}
+
+inline void consoleCount(Page* page, ScriptState* state, PassRefPtr<ScriptArguments> arguments)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ consoleCountImpl(instrumentingAgents, state, arguments);
+}
+
+inline void startConsoleTiming(Frame* frame, const String& title)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ startConsoleTimingImpl(instrumentingAgents, frame, title);
+}
+
+inline void stopConsoleTiming(Frame* frame, const String& title, PassRefPtr<ScriptCallStack> stack)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ stopConsoleTimingImpl(instrumentingAgents, frame, title, stack);
+}
+
+inline void consoleTimeStamp(Frame* frame, PassRefPtr<ScriptArguments> arguments)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ consoleTimeStampImpl(instrumentingAgents, frame, arguments);
+}
+
+inline void addStartProfilingMessageToConsole(Page* page, const String& title, unsigned lineNumber, const String& sourceURL)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ addStartProfilingMessageToConsoleImpl(instrumentingAgents, title, lineNumber, sourceURL);
+}
+
+inline void addProfile(Page* page, RefPtr<ScriptProfile> profile, PassRefPtr<ScriptCallStack> callStack)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ addProfileImpl(instrumentingAgents, profile, callStack);
+}
+
+} // namespace InspectorInstrumentation
+
+} // namespace WebCore
+
+#endif // !defined(InspectorConsoleInstrumentation_h)
diff --git a/Source/core/inspector/InspectorController.cpp b/Source/core/inspector/InspectorController.cpp
new file mode 100644
index 0000000..f4de398
--- /dev/null
+++ b/Source/core/inspector/InspectorController.cpp
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorController.h"
+
+#include "InspectorBackendDispatcher.h"
+#include "InspectorFrontend.h"
+#include "bindings/v8/DOMWrapperWorld.h"
+#include "bindings/v8/ScriptObject.h"
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include "core/inspector/IdentifiersFactory.h"
+#include "core/inspector/InjectedScriptHost.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorAgent.h"
+#include "core/inspector/InspectorApplicationCacheAgent.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/inspector/InspectorCSSAgent.h"
+#include "core/inspector/InspectorCanvasAgent.h"
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorDOMAgent.h"
+#include "core/inspector/InspectorDOMDebuggerAgent.h"
+#include "core/inspector/InspectorDOMStorageAgent.h"
+#include "core/inspector/InspectorDatabaseAgent.h"
+#include "core/inspector/InspectorDebuggerAgent.h"
+#include "core/inspector/InspectorFileSystemAgent.h"
+#include "core/inspector/InspectorFrontendClient.h"
+#include "core/inspector/InspectorHeapProfilerAgent.h"
+#include "core/inspector/InspectorIndexedDBAgent.h"
+#include "core/inspector/InspectorInputAgent.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/InspectorLayerTreeAgent.h"
+#include "core/inspector/InspectorMemoryAgent.h"
+#include "core/inspector/InspectorOverlay.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorProfilerAgent.h"
+#include "core/inspector/InspectorResourceAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorTimelineAgent.h"
+#include "core/inspector/InspectorWorkerAgent.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/inspector/PageConsoleAgent.h"
+#include "core/inspector/PageDebuggerAgent.h"
+#include "core/inspector/PageRuntimeAgent.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/platform/PlatformMouseEvent.h"
+#include "core/platform/PlatformTouchEvent.h"
+#include "core/platform/graphics/GraphicsContext.h"
+#include <wtf/MemoryInstrumentationVector.h>
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+InspectorController::InspectorController(Page* page, InspectorClient* inspectorClient)
+ : m_instrumentingAgents(InstrumentingAgents::create())
+ , m_injectedScriptManager(InjectedScriptManager::createForPage())
+ , m_state(adoptPtr(new InspectorCompositeState(inspectorClient)))
+ , m_overlay(InspectorOverlay::create(page, inspectorClient))
+ , m_page(page)
+ , m_inspectorClient(inspectorClient)
+ , m_isUnderTest(false)
+{
+ OwnPtr<InspectorAgent> inspectorAgentPtr(InspectorAgent::create(page, m_injectedScriptManager.get(), m_instrumentingAgents.get(), m_state.get()));
+ m_inspectorAgent = inspectorAgentPtr.get();
+ m_agents.append(inspectorAgentPtr.release());
+
+ OwnPtr<InspectorPageAgent> pageAgentPtr(InspectorPageAgent::create(m_instrumentingAgents.get(), page, m_inspectorAgent, m_state.get(), m_injectedScriptManager.get(), inspectorClient, m_overlay.get()));
+ InspectorPageAgent* pageAgent = pageAgentPtr.get();
+ m_pageAgent = pageAgentPtr.get();
+ m_agents.append(pageAgentPtr.release());
+
+ OwnPtr<InspectorDOMAgent> domAgentPtr(InspectorDOMAgent::create(m_instrumentingAgents.get(), pageAgent, m_state.get(), m_injectedScriptManager.get(), m_overlay.get(), inspectorClient));
+ m_domAgent = domAgentPtr.get();
+ m_agents.append(domAgentPtr.release());
+
+ m_agents.append(InspectorCSSAgent::create(m_instrumentingAgents.get(), m_state.get(), m_domAgent));
+
+ OwnPtr<InspectorDatabaseAgent> databaseAgentPtr(InspectorDatabaseAgent::create(m_instrumentingAgents.get(), m_state.get()));
+ InspectorDatabaseAgent* databaseAgent = databaseAgentPtr.get();
+ m_agents.append(databaseAgentPtr.release());
+
+ m_agents.append(InspectorIndexedDBAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get(), pageAgent));
+
+ m_agents.append(InspectorFileSystemAgent::create(m_instrumentingAgents.get(), pageAgent, m_state.get()));
+
+ OwnPtr<InspectorDOMStorageAgent> domStorageAgentPtr(InspectorDOMStorageAgent::create(m_instrumentingAgents.get(), m_pageAgent, m_state.get()));
+ InspectorDOMStorageAgent* domStorageAgent = domStorageAgentPtr.get();
+ m_agents.append(domStorageAgentPtr.release());
+
+ OwnPtr<InspectorMemoryAgent> memoryAgentPtr(InspectorMemoryAgent::create(m_instrumentingAgents.get(), inspectorClient, m_state.get(), m_page));
+ m_memoryAgent = memoryAgentPtr.get();
+ m_agents.append(memoryAgentPtr.release());
+
+ m_agents.append(InspectorTimelineAgent::create(m_instrumentingAgents.get(), pageAgent, m_memoryAgent, m_state.get(), InspectorTimelineAgent::PageInspector,
+ inspectorClient));
+ m_agents.append(InspectorApplicationCacheAgent::create(m_instrumentingAgents.get(), m_state.get(), pageAgent));
+
+ OwnPtr<InspectorResourceAgent> resourceAgentPtr(InspectorResourceAgent::create(m_instrumentingAgents.get(), pageAgent, inspectorClient, m_state.get()));
+ m_resourceAgent = resourceAgentPtr.get();
+ m_agents.append(resourceAgentPtr.release());
+
+ OwnPtr<InspectorRuntimeAgent> runtimeAgentPtr(PageRuntimeAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get(), page, pageAgent));
+ InspectorRuntimeAgent* runtimeAgent = runtimeAgentPtr.get();
+ m_agents.append(runtimeAgentPtr.release());
+
+ OwnPtr<InspectorConsoleAgent> consoleAgentPtr(PageConsoleAgent::create(m_instrumentingAgents.get(), m_inspectorAgent, m_state.get(), m_injectedScriptManager.get(), m_domAgent));
+ InspectorConsoleAgent* consoleAgent = consoleAgentPtr.get();
+ m_agents.append(consoleAgentPtr.release());
+
+ OwnPtr<InspectorDebuggerAgent> debuggerAgentPtr(PageDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), pageAgent, m_injectedScriptManager.get(), m_overlay.get()));
+ m_debuggerAgent = debuggerAgentPtr.get();
+ m_agents.append(debuggerAgentPtr.release());
+
+ OwnPtr<InspectorDOMDebuggerAgent> domDebuggerAgentPtr(InspectorDOMDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_domAgent, m_debuggerAgent, m_inspectorAgent));
+ m_domDebuggerAgent = domDebuggerAgentPtr.get();
+ m_agents.append(domDebuggerAgentPtr.release());
+
+ OwnPtr<InspectorProfilerAgent> profilerAgentPtr(InspectorProfilerAgent::create(m_instrumentingAgents.get(), consoleAgent, page, m_state.get(), m_injectedScriptManager.get()));
+ m_profilerAgent = profilerAgentPtr.get();
+ m_agents.append(profilerAgentPtr.release());
+
+ m_agents.append(InspectorHeapProfilerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get()));
+
+
+ m_agents.append(InspectorWorkerAgent::create(m_instrumentingAgents.get(), m_state.get()));
+
+ m_agents.append(InspectorCanvasAgent::create(m_instrumentingAgents.get(), m_state.get(), pageAgent, m_injectedScriptManager.get()));
+
+ m_agents.append(InspectorInputAgent::create(m_instrumentingAgents.get(), m_state.get(), page));
+
+ m_agents.append(InspectorLayerTreeAgent::create(m_instrumentingAgents.get(), m_state.get()));
+
+ ASSERT_ARG(inspectorClient, inspectorClient);
+ m_injectedScriptManager->injectedScriptHost()->init(m_inspectorAgent
+ , consoleAgent
+ , databaseAgent
+ , domStorageAgent
+ , m_domAgent
+ , m_debuggerAgent
+ );
+
+ runtimeAgent->setScriptDebugServer(&m_debuggerAgent->scriptDebugServer());
+}
+
+InspectorController::~InspectorController()
+{
+ m_instrumentingAgents->reset();
+ m_agents.discardAgents();
+ ASSERT(!m_inspectorClient);
+}
+
+PassOwnPtr<InspectorController> InspectorController::create(Page* page, InspectorClient* client)
+{
+ return adoptPtr(new InspectorController(page, client));
+}
+
+void InspectorController::inspectedPageDestroyed()
+{
+ disconnectFrontend();
+ m_injectedScriptManager->disconnect();
+ m_inspectorClient = 0;
+ m_page = 0;
+}
+
+void InspectorController::setInspectorFrontendClient(PassOwnPtr<InspectorFrontendClient> inspectorFrontendClient)
+{
+ m_inspectorFrontendClient = inspectorFrontendClient;
+}
+
+bool InspectorController::hasInspectorFrontendClient() const
+{
+ return m_inspectorFrontendClient;
+}
+
+void InspectorController::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld* world)
+{
+ if (world != mainThreadNormalWorld())
+ return;
+
+ // If the page is supposed to serve as InspectorFrontend notify inspector frontend
+ // client that it's cleared so that the client can expose inspector bindings.
+ if (m_inspectorFrontendClient && frame == m_page->mainFrame())
+ m_inspectorFrontendClient->windowObjectCleared();
+}
+
+void InspectorController::connectFrontend(InspectorFrontendChannel* frontendChannel)
+{
+ ASSERT(frontendChannel);
+
+ m_inspectorFrontend = adoptPtr(new InspectorFrontend(frontendChannel));
+ // We can reconnect to existing front-end -> unmute state.
+ m_state->unmute();
+
+ m_agents.setFrontend(m_inspectorFrontend.get());
+
+ InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
+ InspectorInstrumentation::frontendCreated();
+
+ ASSERT(m_inspectorClient);
+ m_inspectorBackendDispatcher = InspectorBackendDispatcher::create(frontendChannel);
+
+ m_agents.registerInDispatcher(m_inspectorBackendDispatcher.get());
+}
+
+void InspectorController::disconnectFrontend()
+{
+ if (!m_inspectorFrontend)
+ return;
+ m_inspectorBackendDispatcher->clearFrontend();
+ m_inspectorBackendDispatcher.clear();
+
+ // Destroying agents would change the state, but we don't want that.
+ // Pre-disconnect state will be used to restore inspector agents.
+ m_state->mute();
+
+ m_agents.clearFrontend();
+
+ m_inspectorFrontend.clear();
+
+ // relese overlay page resources
+ m_overlay->freePage();
+ InspectorInstrumentation::frontendDeleted();
+ InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
+}
+
+void InspectorController::reconnectFrontend(InspectorFrontendChannel* frontendChannel, const String& inspectorStateCookie)
+{
+ ASSERT(!m_inspectorFrontend);
+ connectFrontend(frontendChannel);
+ m_state->loadFromCookie(inspectorStateCookie);
+ m_agents.restore();
+}
+
+void InspectorController::setProcessId(long processId)
+{
+ IdentifiersFactory::setProcessId(processId);
+}
+
+void InspectorController::webViewResized(const IntSize& size)
+{
+ m_pageAgent->webViewResized(size);
+}
+
+bool InspectorController::isUnderTest()
+{
+ return m_isUnderTest;
+}
+
+void InspectorController::evaluateForTestInFrontend(long callId, const String& script)
+{
+ m_isUnderTest = true;
+ m_inspectorAgent->evaluateForTestInFrontend(callId, script);
+}
+
+void InspectorController::drawHighlight(GraphicsContext& context) const
+{
+ m_overlay->paint(context);
+}
+
+void InspectorController::getHighlight(Highlight* highlight) const
+{
+ m_overlay->getHighlight(highlight);
+}
+
+void InspectorController::inspect(Node* node)
+{
+ Document* document = node->ownerDocument();
+ if (!document)
+ return;
+ Frame* frame = document->frame();
+ if (!frame)
+ return;
+
+ if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
+ node = node->parentNode();
+
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
+ if (injectedScript.hasNoValue())
+ return;
+ injectedScript.inspectNode(node);
+}
+
+Page* InspectorController::inspectedPage() const
+{
+ return m_page;
+}
+
+void InspectorController::setInjectedScriptForOrigin(const String& origin, const String& source)
+{
+ m_inspectorAgent->setInjectedScriptForOrigin(origin, source);
+}
+
+void InspectorController::dispatchMessageFromFrontend(const String& message)
+{
+ if (m_inspectorBackendDispatcher)
+ m_inspectorBackendDispatcher->dispatch(message);
+}
+
+void InspectorController::hideHighlight()
+{
+ ErrorString error;
+ m_domAgent->hideHighlight(&error);
+}
+
+Node* InspectorController::highlightedNode() const
+{
+ return m_overlay->highlightedNode();
+}
+
+bool InspectorController::handleMouseEvent(Frame* frame, const PlatformMouseEvent& event)
+{
+ if (event.type() == PlatformEvent::MouseMoved) {
+ m_domAgent->handleMouseMove(frame, event);
+ return false;
+ }
+ if (event.type() == PlatformEvent::MousePressed)
+ return m_domAgent->handleMousePress();
+ return false;
+}
+
+bool InspectorController::handleTouchEvent(Frame* frame, const PlatformTouchEvent& event)
+{
+ return m_domAgent->handleTouchEvent(frame, event);
+}
+
+bool InspectorController::profilerEnabled()
+{
+ return m_profilerAgent->enabled();
+}
+
+void InspectorController::setProfilerEnabled(bool enable)
+{
+ ErrorString error;
+ if (enable)
+ m_profilerAgent->enable(&error);
+ else
+ m_profilerAgent->disable(&error);
+}
+
+void InspectorController::resume()
+{
+ if (m_debuggerAgent) {
+ ErrorString error;
+ m_debuggerAgent->resume(&error);
+ }
+}
+
+void InspectorController::setResourcesDataSizeLimitsFromInternals(int maximumResourcesContentSize, int maximumSingleResourceContentSize)
+{
+ m_resourceAgent->setResourcesDataSizeLimitsFromInternals(maximumResourcesContentSize, maximumSingleResourceContentSize);
+}
+
+void InspectorController::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorController);
+ info.addMember(m_inspectorAgent, "inspectorAgent");
+ info.addMember(m_instrumentingAgents, "instrumentingAgents");
+ info.addMember(m_injectedScriptManager, "injectedScriptManager");
+ info.addMember(m_state, "state");
+ info.addMember(m_overlay, "overlay");
+
+ info.addMember(m_inspectorAgent, "inspectorAgent");
+ info.addMember(m_domAgent, "domAgent");
+ info.addMember(m_resourceAgent, "resourceAgent");
+ info.addMember(m_pageAgent, "pageAgent");
+ info.addMember(m_debuggerAgent, "debuggerAgent");
+ info.addMember(m_domDebuggerAgent, "domDebuggerAgent");
+ info.addMember(m_profilerAgent, "profilerAgent");
+
+ info.addMember(m_inspectorBackendDispatcher, "inspectorBackendDispatcher");
+ info.addMember(m_inspectorFrontendClient, "inspectorFrontendClient");
+ info.addMember(m_inspectorFrontend, "inspectorFrontend");
+ info.addMember(m_page, "page");
+ info.addWeakPointer(m_inspectorClient);
+ info.addMember(m_agents, "agents");
+}
+
+void InspectorController::willProcessTask()
+{
+ if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->willProcessTask();
+ m_profilerAgent->willProcessTask();
+}
+
+void InspectorController::didProcessTask()
+{
+ if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didProcessTask();
+ m_profilerAgent->didProcessTask();
+ m_domDebuggerAgent->didProcessTask();
+}
+
+void InspectorController::didBeginFrame()
+{
+ if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didBeginFrame();
+ if (InspectorCanvasAgent* canvasAgent = m_instrumentingAgents->inspectorCanvasAgent())
+ canvasAgent->didBeginFrame();
+}
+
+void InspectorController::didCancelFrame()
+{
+ if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didCancelFrame();
+}
+
+void InspectorController::willComposite()
+{
+ if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->willComposite();
+}
+
+void InspectorController::didComposite()
+{
+ if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didComposite();
+}
+
+HashMap<String, size_t> InspectorController::processMemoryDistribution() const
+{
+ HashMap<String, size_t> memoryInfo;
+ m_memoryAgent->getProcessMemoryDistributionMap(&memoryInfo);
+ return memoryInfo;
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InspectorController.h b/Source/core/inspector/InspectorController.h
new file mode 100644
index 0000000..4e55403
--- /dev/null
+++ b/Source/core/inspector/InspectorController.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorController_h
+#define InspectorController_h
+
+
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class DOMWrapperWorld;
+class Frame;
+class GraphicsContext;
+class InjectedScriptManager;
+class InspectorAgent;
+class InspectorApplicationCacheAgent;
+class InspectorBackendDispatcher;
+class InspectorBaseAgentInterface;
+class InspectorClient;
+class InspectorDOMAgent;
+class InspectorDOMDebuggerAgent;
+class InspectorDebuggerAgent;
+class InspectorFrontend;
+class InspectorFrontendChannel;
+class InspectorFrontendClient;
+class InspectorMemoryAgent;
+class InspectorOverlay;
+class InspectorPageAgent;
+class InspectorProfilerAgent;
+class InspectorResourceAgent;
+class InspectorState;
+class InstrumentingAgents;
+class IntSize;
+class Page;
+class PlatformMouseEvent;
+class PlatformTouchEvent;
+class PostWorkerNotificationToFrontendTask;
+class Node;
+
+struct Highlight;
+
+class InspectorController {
+ WTF_MAKE_NONCOPYABLE(InspectorController);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ~InspectorController();
+
+ static PassOwnPtr<InspectorController> create(Page*, InspectorClient*);
+ void inspectedPageDestroyed();
+
+ Page* inspectedPage() const;
+
+ void setInspectorFrontendClient(PassOwnPtr<InspectorFrontendClient>);
+ bool hasInspectorFrontendClient() const;
+ void didClearWindowObjectInWorld(Frame*, DOMWrapperWorld*);
+ void setInjectedScriptForOrigin(const String& origin, const String& source);
+
+ void dispatchMessageFromFrontend(const String& message);
+
+ bool hasFrontend() const { return m_inspectorFrontend; }
+ void connectFrontend(InspectorFrontendChannel*);
+ void disconnectFrontend();
+ void reconnectFrontend(InspectorFrontendChannel*, const String& inspectorStateCookie);
+ void setProcessId(long);
+ void webViewResized(const IntSize&);
+
+ void inspect(Node*);
+ void drawHighlight(GraphicsContext&) const;
+ void getHighlight(Highlight*) const;
+ void hideHighlight();
+ Node* highlightedNode() const;
+
+ bool handleMouseEvent(Frame*, const PlatformMouseEvent&);
+ bool handleTouchEvent(Frame*, const PlatformTouchEvent&);
+
+ bool isUnderTest();
+ void evaluateForTestInFrontend(long callId, const String& script);
+
+ bool profilerEnabled();
+ void setProfilerEnabled(bool);
+
+ void resume();
+
+ void setResourcesDataSizeLimitsFromInternals(int maximumResourcesContentSize, int maximumSingleResourceContentSize);
+
+ InspectorClient* inspectorClient() const { return m_inspectorClient; }
+ InspectorPageAgent* pageAgent() const { return m_pageAgent; }
+
+ void reportMemoryUsage(MemoryObjectInfo*) const;
+
+ void willProcessTask();
+ void didProcessTask();
+
+ void didBeginFrame();
+ void didCancelFrame();
+ void willComposite();
+ void didComposite();
+
+ HashMap<String, size_t> processMemoryDistribution() const;
+
+private:
+ InspectorController(Page*, InspectorClient*);
+
+ friend class PostWorkerNotificationToFrontendTask;
+ friend InstrumentingAgents* instrumentationForPage(Page*);
+
+ RefPtr<InstrumentingAgents> m_instrumentingAgents;
+ OwnPtr<InjectedScriptManager> m_injectedScriptManager;
+ OwnPtr<InspectorCompositeState> m_state;
+ OwnPtr<InspectorOverlay> m_overlay;
+
+ InspectorAgent* m_inspectorAgent;
+ InspectorDOMAgent* m_domAgent;
+ InspectorResourceAgent* m_resourceAgent;
+ InspectorPageAgent* m_pageAgent;
+ InspectorMemoryAgent* m_memoryAgent;
+ InspectorDebuggerAgent* m_debuggerAgent;
+ InspectorDOMDebuggerAgent* m_domDebuggerAgent;
+ InspectorProfilerAgent* m_profilerAgent;
+
+ RefPtr<InspectorBackendDispatcher> m_inspectorBackendDispatcher;
+ OwnPtr<InspectorFrontendClient> m_inspectorFrontendClient;
+ OwnPtr<InspectorFrontend> m_inspectorFrontend;
+ Page* m_page;
+ InspectorClient* m_inspectorClient;
+ InspectorAgentRegistry m_agents;
+ bool m_isUnderTest;
+};
+
+}
+
+
+#endif // !defined(InspectorController_h)
diff --git a/Source/core/inspector/InspectorCounters.cpp b/Source/core/inspector/InspectorCounters.cpp
new file mode 100644
index 0000000..5082e09
--- /dev/null
+++ b/Source/core/inspector/InspectorCounters.cpp
@@ -0,0 +1,62 @@
+/*
+* Copyright (C) 2012 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 "core/inspector/InspectorCounters.h"
+
+#include "core/platform/ThreadGlobalData.h"
+
+namespace WebCore {
+
+int InspectorCounters::s_counters[CounterTypeLength];
+
+int InspectorCounters::counterValue(CounterType type)
+{
+ return s_counters[type];
+}
+
+ThreadLocalInspectorCounters::ThreadLocalInspectorCounters()
+{
+ for (size_t i = 0; i < CounterTypeLength; i++)
+ m_counters[i] = 0;
+}
+
+int ThreadLocalInspectorCounters::counterValue(CounterType type)
+{
+ return m_counters[type];
+}
+
+ThreadLocalInspectorCounters& ThreadLocalInspectorCounters::current()
+{
+ return threadGlobalData().inspectorCounters();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorCounters.h b/Source/core/inspector/InspectorCounters.h
new file mode 100644
index 0000000..d619d16
--- /dev/null
+++ b/Source/core/inspector/InspectorCounters.h
@@ -0,0 +1,102 @@
+/*
+* Copyright (C) 2012 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 InspectorCounters_h
+#define InspectorCounters_h
+
+#include <wtf/FastAllocBase.h>
+#include <wtf/UnusedParam.h>
+
+#if !ASSERT_DISABLED
+#include <wtf/MainThread.h>
+#endif
+
+namespace WebCore {
+
+class InspectorCounters {
+public:
+ enum CounterType {
+ DocumentCounter,
+ NodeCounter,
+ JSEventListenerCounter,
+ CounterTypeLength
+ };
+
+ static inline void incrementCounter(CounterType type)
+ {
+ ASSERT(isMainThread());
+ ++s_counters[type];
+ }
+
+ static inline void decrementCounter(CounterType type)
+ {
+ ASSERT(isMainThread());
+ --s_counters[type];
+ }
+
+ static int counterValue(CounterType);
+
+private:
+ InspectorCounters();
+
+ static int s_counters[CounterTypeLength];
+};
+
+
+class ThreadLocalInspectorCounters {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ enum CounterType {
+ JSEventListenerCounter,
+ CounterTypeLength
+ };
+ ThreadLocalInspectorCounters();
+
+ inline void incrementCounter(CounterType type)
+ {
+ ++m_counters[type];
+ }
+
+ inline void decrementCounter(CounterType type)
+ {
+ --m_counters[type];
+ }
+
+ int counterValue(CounterType);
+
+ static ThreadLocalInspectorCounters& current();
+
+private:
+ int m_counters[CounterTypeLength];
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorCounters_h)
diff --git a/Source/core/inspector/InspectorDOMAgent.cpp b/Source/core/inspector/InspectorDOMAgent.cpp
new file mode 100644
index 0000000..7f1c772
--- /dev/null
+++ b/Source/core/inspector/InspectorDOMAgent.cpp
@@ -0,0 +1,1839 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InspectorDOMAgent.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptEventListener.h"
+#include "core/css/CSSComputedStyleDeclaration.h"
+#include "core/css/CSSPropertySourceData.h"
+#include "core/css/CSSRule.h"
+#include "core/css/CSSRuleList.h"
+#include "core/css/CSSStyleRule.h"
+#include "core/css/CSSStyleSheet.h"
+#include "core/css/StylePropertySet.h"
+#include "core/css/StyleResolver.h"
+#include "core/css/StyleSheetList.h"
+#include "core/dom/Attr.h"
+#include "core/dom/CharacterData.h"
+#include "core/dom/ContainerNode.h"
+#include "core/dom/Document.h"
+#include "core/dom/DocumentFragment.h"
+#include "core/dom/DocumentType.h"
+#include "core/dom/Element.h"
+#include "core/dom/ElementShadow.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventContext.h"
+#include "core/dom/EventListener.h"
+#include "core/dom/EventNames.h"
+#include "core/dom/EventTarget.h"
+#include "core/dom/MutationEvent.h"
+#include "core/dom/Node.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/ShadowRoot.h"
+#include "core/dom/Text.h"
+#include "core/fileapi/File.h"
+#include "core/fileapi/FileList.h"
+#include "core/html/HTMLElement.h"
+#include "core/html/HTMLFrameOwnerElement.h"
+#include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLTemplateElement.h"
+#include "core/inspector/DOMEditor.h"
+#include "core/inspector/DOMPatchSupport.h"
+#include "core/inspector/IdentifiersFactory.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorHistory.h"
+#include "core/inspector/InspectorOverlay.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/loader/CookieJar.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameTree.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/platform/Cookie.h"
+#include "core/platform/Pasteboard.h"
+#include "core/platform/PlatformMouseEvent.h"
+#include "core/platform/PlatformTouchEvent.h"
+#include "core/platform/graphics/IntRect.h"
+#include "core/rendering/HitTestResult.h"
+#include "core/rendering/RenderView.h"
+#include "core/rendering/style/RenderStyle.h"
+#include "core/rendering/style/RenderStyleConstants.h"
+#include "core/xml/XPathResult.h"
+
+#include "core/editing/htmlediting.h"
+#include "core/editing/markup.h"
+
+#include <wtf/HashSet.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+namespace DOMAgentState {
+static const char documentRequested[] = "documentRequested";
+};
+
+static const size_t maxTextSize = 10000;
+static const UChar ellipsisUChar[] = { 0x2026, 0 };
+
+static Color parseColor(const RefPtr<InspectorObject>* colorObject)
+{
+ if (!colorObject || !(*colorObject))
+ return Color::transparent;
+
+ int r;
+ int g;
+ int b;
+ bool success = (*colorObject)->getNumber("r", &r);
+ success |= (*colorObject)->getNumber("g", &g);
+ success |= (*colorObject)->getNumber("b", &b);
+ if (!success)
+ return Color::transparent;
+
+ double a;
+ success = (*colorObject)->getNumber("a", &a);
+ if (!success)
+ return Color(r, g, b);
+
+ // Clamp alpha to the [0..1] range.
+ if (a < 0)
+ a = 0;
+ else if (a > 1)
+ a = 1;
+
+ return Color(r, g, b, static_cast<int>(a * 255));
+}
+
+static Color parseConfigColor(const String& fieldName, InspectorObject* configObject)
+{
+ const RefPtr<InspectorObject> colorObject = configObject->getObject(fieldName);
+ return parseColor(&colorObject);
+}
+
+static bool parseQuad(const RefPtr<InspectorArray>& quadArray, FloatQuad* quad)
+{
+ if (!quadArray)
+ return false;
+ const size_t coordinatesInQuad = 8;
+ double coordinates[coordinatesInQuad];
+ if (quadArray->length() != coordinatesInQuad)
+ return false;
+ for (size_t i = 0; i < coordinatesInQuad; ++i) {
+ if (!quadArray->get(i)->asNumber(coordinates + i))
+ return false;
+ }
+ quad->setP1(FloatPoint(coordinates[0], coordinates[1]));
+ quad->setP2(FloatPoint(coordinates[2], coordinates[3]));
+ quad->setP3(FloatPoint(coordinates[4], coordinates[5]));
+ quad->setP4(FloatPoint(coordinates[6], coordinates[7]));
+
+ return true;
+}
+
+static Node* hoveredNodeForPoint(Frame* frame, const IntPoint& point, bool ignorePointerEventsNone)
+{
+ HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::AllowChildFrameContent;
+ if (ignorePointerEventsNone)
+ hitType |= HitTestRequest::IgnorePointerEventsNone;
+ HitTestRequest request(hitType);
+ HitTestResult result(frame->view()->windowToContents(point));
+ frame->contentRenderer()->hitTest(request, result);
+ result.setToNonShadowAncestor();
+ Node* node = result.innerNode();
+ while (node && node->nodeType() == Node::TEXT_NODE)
+ node = node->parentNode();
+ return node;
+}
+
+static Node* hoveredNodeForEvent(Frame* frame, const PlatformMouseEvent& event, bool ignorePointerEventsNone)
+{
+ return hoveredNodeForPoint(frame, event.position(), ignorePointerEventsNone);
+}
+
+static Node* hoveredNodeForEvent(Frame* frame, const PlatformTouchEvent& event, bool ignorePointerEventsNone)
+{
+ const Vector<PlatformTouchPoint>& points = event.touchPoints();
+ if (!points.size())
+ return 0;
+ return hoveredNodeForPoint(frame, points[0].pos(), ignorePointerEventsNone);
+}
+
+class RevalidateStyleAttributeTask {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ RevalidateStyleAttributeTask(InspectorDOMAgent*);
+ void scheduleFor(Element*);
+ void reset() { m_timer.stop(); }
+ void onTimer(Timer<RevalidateStyleAttributeTask>*);
+
+private:
+ InspectorDOMAgent* m_domAgent;
+ Timer<RevalidateStyleAttributeTask> m_timer;
+ HashSet<RefPtr<Element> > m_elements;
+};
+
+RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent)
+ : m_domAgent(domAgent)
+ , m_timer(this, &RevalidateStyleAttributeTask::onTimer)
+{
+}
+
+void RevalidateStyleAttributeTask::scheduleFor(Element* element)
+{
+ m_elements.add(element);
+ if (!m_timer.isActive())
+ m_timer.startOneShot(0);
+}
+
+void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
+{
+ // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed.
+ Vector<Element*> elements;
+ for (HashSet<RefPtr<Element> >::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it)
+ elements.append(it->get());
+ m_domAgent->styleAttributeInvalidated(elements);
+
+ m_elements.clear();
+}
+
+String InspectorDOMAgent::toErrorString(const ExceptionCode& ec)
+{
+ if (ec) {
+ ExceptionCodeDescription description(ec);
+ return description.name;
+ }
+ return "";
+}
+
+InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager, InspectorOverlay* overlay, InspectorClient* client)
+ : InspectorBaseAgent<InspectorDOMAgent>("DOM", instrumentingAgents, inspectorState)
+ , m_pageAgent(pageAgent)
+ , m_injectedScriptManager(injectedScriptManager)
+ , m_overlay(overlay)
+ , m_client(client)
+ , m_frontend(0)
+ , m_domListener(0)
+ , m_lastNodeId(1)
+ , m_lastBackendNodeId(-1)
+ , m_searchingForNode(false)
+ , m_suppressAttributeModifiedEvent(false)
+{
+}
+
+InspectorDOMAgent::~InspectorDOMAgent()
+{
+ reset();
+ ASSERT(!m_searchingForNode);
+}
+
+void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend)
+{
+ ASSERT(!m_frontend);
+ m_history = adoptPtr(new InspectorHistory());
+ m_domEditor = adoptPtr(new DOMEditor(m_history.get()));
+
+ m_frontend = frontend->dom();
+ m_instrumentingAgents->setInspectorDOMAgent(this);
+ m_document = m_pageAgent->mainFrame()->document();
+}
+
+void InspectorDOMAgent::clearFrontend()
+{
+ ASSERT(m_frontend);
+
+ m_history.clear();
+ m_domEditor.clear();
+
+ ErrorString error;
+ setSearchingForNode(&error, false, 0);
+ hideHighlight(&error);
+
+ m_frontend = 0;
+ m_instrumentingAgents->setInspectorDOMAgent(0);
+ m_state->setBoolean(DOMAgentState::documentRequested, false);
+ reset();
+}
+
+void InspectorDOMAgent::restore()
+{
+ // Reset document to avoid early return from setDocument.
+ m_document = 0;
+ setDocument(m_pageAgent->mainFrame()->document());
+}
+
+Vector<Document*> InspectorDOMAgent::documents()
+{
+ Vector<Document*> result;
+ for (Frame* frame = m_document->frame(); frame; frame = frame->tree()->traverseNext()) {
+ Document* document = frame->document();
+ if (!document)
+ continue;
+ result.append(document);
+ }
+ return result;
+}
+
+void InspectorDOMAgent::reset()
+{
+ if (m_history)
+ m_history->reset();
+ m_searchResults.clear();
+ discardBindings();
+ if (m_revalidateStyleAttrTask)
+ m_revalidateStyleAttrTask->reset();
+ m_document = 0;
+}
+
+void InspectorDOMAgent::setDOMListener(DOMListener* listener)
+{
+ m_domListener = listener;
+}
+
+void InspectorDOMAgent::setDocument(Document* doc)
+{
+ if (doc == m_document.get())
+ return;
+
+ reset();
+
+ m_document = doc;
+
+ if (!m_state->getBoolean(DOMAgentState::documentRequested))
+ return;
+
+ // Immediately communicate 0 document or document that has finished loading.
+ if (!doc || !doc->parsing())
+ m_frontend->documentUpdated();
+}
+
+void InspectorDOMAgent::releaseDanglingNodes()
+{
+ m_danglingNodeToIdMaps.clear();
+}
+
+int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap)
+{
+ int id = nodesMap->get(node);
+ if (id)
+ return id;
+ id = m_lastNodeId++;
+ nodesMap->set(node, id);
+ m_idToNode.set(id, node);
+ m_idToNodesMap.set(id, nodesMap);
+ return id;
+}
+
+void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
+{
+ int id = nodesMap->get(node);
+ if (!id)
+ return;
+
+ m_idToNode.remove(id);
+
+ if (node->isFrameOwnerElement()) {
+ const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node);
+ Document* contentDocument = frameOwner->contentDocument();
+ if (m_domListener)
+ m_domListener->didRemoveDocument(contentDocument);
+ if (contentDocument)
+ unbind(contentDocument, nodesMap);
+ }
+
+ if (node->isElementNode()) {
+ if (ElementShadow* shadow = toElement(node)->shadow()) {
+ for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot())
+ unbind(root, nodesMap);
+ }
+ }
+
+ nodesMap->remove(node);
+ if (m_domListener)
+ m_domListener->didRemoveDOMNode(node);
+
+ bool childrenRequested = m_childrenRequested.contains(id);
+ if (childrenRequested) {
+ // Unbind subtree known to client recursively.
+ m_childrenRequested.remove(id);
+ Node* child = innerFirstChild(node);
+ while (child) {
+ unbind(child, nodesMap);
+ child = innerNextSibling(child);
+ }
+ }
+}
+
+Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId)
+{
+ Node* node = nodeForId(nodeId);
+ if (!node) {
+ *errorString = "Could not find node with given id";
+ return 0;
+ }
+ return node;
+}
+
+Document* InspectorDOMAgent::assertDocument(ErrorString* errorString, int nodeId)
+{
+ Node* node = assertNode(errorString, nodeId);
+ if (!node)
+ return 0;
+
+ if (!(node->isDocumentNode())) {
+ *errorString = "Document is not available";
+ return 0;
+ }
+ return toDocument(node);
+}
+
+Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId)
+{
+ Node* node = assertNode(errorString, nodeId);
+ if (!node)
+ return 0;
+
+ if (node->nodeType() != Node::ELEMENT_NODE) {
+ *errorString = "Node is not an Element";
+ return 0;
+ }
+ return toElement(node);
+}
+
+Node* InspectorDOMAgent::assertEditableNode(ErrorString* errorString, int nodeId)
+{
+ Node* node = assertNode(errorString, nodeId);
+ if (!node)
+ return 0;
+
+ if (node->isInShadowTree()) {
+ *errorString = "Can not edit nodes from shadow trees";
+ return 0;
+ }
+
+ return node;
+}
+
+Element* InspectorDOMAgent::assertEditableElement(ErrorString* errorString, int nodeId)
+{
+ Element* element = assertElement(errorString, nodeId);
+ if (!element)
+ return 0;
+
+ if (element->isInShadowTree()) {
+ *errorString = "Can not edit elements from shadow trees";
+ return 0;
+ }
+ return element;
+}
+
+void InspectorDOMAgent::getDocument(ErrorString* errorString, RefPtr<TypeBuilder::DOM::Node>& root)
+{
+ m_state->setBoolean(DOMAgentState::documentRequested, true);
+
+ if (!m_document) {
+ *errorString = "Document is not available";
+ return;
+ }
+
+ // Reset backend state.
+ RefPtr<Document> doc = m_document;
+ reset();
+ m_document = doc;
+
+ root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap);
+}
+
+void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, int depth)
+{
+ Node* node = nodeForId(nodeId);
+ if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE))
+ return;
+
+ NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);
+
+ if (m_childrenRequested.contains(nodeId)) {
+ if (depth <= 1)
+ return;
+
+ depth--;
+
+ for (node = innerFirstChild(node); node; node = innerNextSibling(node)) {
+ int childNodeId = nodeMap->get(node);
+ ASSERT(childNodeId);
+ pushChildNodesToFrontend(childNodeId, depth);
+ }
+
+ return;
+ }
+
+ RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodeMap);
+ m_frontend->setChildNodes(nodeId, children.release());
+}
+
+void InspectorDOMAgent::discardBindings()
+{
+ m_documentNodeToIdMap.clear();
+ m_idToNode.clear();
+ releaseDanglingNodes();
+ m_childrenRequested.clear();
+ m_backendIdToNode.clear();
+ m_nodeGroupToBackendIdMap.clear();
+}
+
+int InspectorDOMAgent::pushNodeToFrontend(ErrorString* errorString, int documentNodeId, Node* nodeToPush)
+{
+ Document* document = assertDocument(errorString, documentNodeId);
+ if (!document)
+ return 0;
+ if (nodeToPush->document() != document) {
+ *errorString = "Node is not part of the document with given id";
+ return 0;
+ }
+
+ return pushNodePathToFrontend(nodeToPush);
+}
+
+Node* InspectorDOMAgent::nodeForId(int id)
+{
+ if (!id)
+ return 0;
+
+ HashMap<int, Node*>::iterator it = m_idToNode.find(id);
+ if (it != m_idToNode.end())
+ return it->value;
+ return 0;
+}
+
+void InspectorDOMAgent::requestChildNodes(ErrorString* errorString, int nodeId, const int* depth)
+{
+ int sanitizedDepth;
+
+ if (!depth)
+ sanitizedDepth = 1;
+ else if (*depth == -1)
+ sanitizedDepth = INT_MAX;
+ else if (*depth > 0)
+ sanitizedDepth = *depth;
+ else {
+ *errorString = "Please provide a positive integer as a depth or -1 for entire subtree";
+ return;
+ }
+
+ pushChildNodesToFrontend(nodeId, sanitizedDepth);
+}
+
+void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, int* elementId)
+{
+ *elementId = 0;
+ Node* node = assertNode(errorString, nodeId);
+ if (!node)
+ return;
+
+ ExceptionCode ec = 0;
+ RefPtr<Element> element = node->querySelector(selectors, ec);
+ if (ec) {
+ *errorString = "DOM Error while querying";
+ return;
+ }
+
+ if (element)
+ *elementId = pushNodePathToFrontend(element.get());
+}
+
+void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, RefPtr<TypeBuilder::Array<int> >& result)
+{
+ Node* node = assertNode(errorString, nodeId);
+ if (!node)
+ return;
+
+ ExceptionCode ec = 0;
+ RefPtr<NodeList> nodes = node->querySelectorAll(selectors, ec);
+ if (ec) {
+ *errorString = "DOM Error while querying";
+ return;
+ }
+
+ result = TypeBuilder::Array<int>::create();
+
+ for (unsigned i = 0; i < nodes->length(); ++i)
+ result->addItem(pushNodePathToFrontend(nodes->item(i)));
+}
+
+int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
+{
+ ASSERT(nodeToPush); // Invalid input
+
+ if (!m_document)
+ return 0;
+ if (!m_documentNodeToIdMap.contains(m_document))
+ return 0;
+
+ // Return id in case the node is known.
+ int result = m_documentNodeToIdMap.get(nodeToPush);
+ if (result)
+ return result;
+
+ Node* node = nodeToPush;
+ Vector<Node*> path;
+ NodeToIdMap* danglingMap = 0;
+
+ while (true) {
+ Node* parent = innerParentNode(node);
+ if (!parent) {
+ // Node being pushed is detached -> push subtree root.
+ OwnPtr<NodeToIdMap> newMap = adoptPtr(new NodeToIdMap);
+ danglingMap = newMap.get();
+ m_danglingNodeToIdMaps.append(newMap.release());
+ RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
+ children->addItem(buildObjectForNode(node, 0, danglingMap));
+ m_frontend->setChildNodes(0, children);
+ break;
+ } else {
+ path.append(parent);
+ if (m_documentNodeToIdMap.get(parent))
+ break;
+ else
+ node = parent;
+ }
+ }
+
+ NodeToIdMap* map = danglingMap ? danglingMap : &m_documentNodeToIdMap;
+ for (int i = path.size() - 1; i >= 0; --i) {
+ int nodeId = map->get(path.at(i));
+ ASSERT(nodeId);
+ pushChildNodesToFrontend(nodeId);
+ }
+ return map->get(nodeToPush);
+}
+
+int InspectorDOMAgent::boundNodeId(Node* node)
+{
+ return m_documentNodeToIdMap.get(node);
+}
+
+BackendNodeId InspectorDOMAgent::backendNodeIdForNode(Node* node, const String& nodeGroup)
+{
+ if (!node)
+ return 0;
+
+ if (!m_nodeGroupToBackendIdMap.contains(nodeGroup))
+ m_nodeGroupToBackendIdMap.set(nodeGroup, NodeToBackendIdMap());
+
+ NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value;
+ BackendNodeId id = map.get(node);
+ if (!id) {
+ id = --m_lastBackendNodeId;
+ map.set(node, id);
+ m_backendIdToNode.set(id, std::make_pair(node, nodeGroup));
+ }
+
+ return id;
+}
+
+void InspectorDOMAgent::releaseBackendNodeIds(ErrorString* errorString, const String& nodeGroup)
+{
+ if (m_nodeGroupToBackendIdMap.contains(nodeGroup)) {
+ NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value;
+ for (NodeToBackendIdMap::iterator it = map.begin(); it != map.end(); ++it)
+ m_backendIdToNode.remove(it->value);
+ m_nodeGroupToBackendIdMap.remove(nodeGroup);
+ return;
+ }
+ *errorString = "Group name not found";
+}
+
+void InspectorDOMAgent::setAttributeValue(ErrorString* errorString, int elementId, const String& name, const String& value)
+{
+ Element* element = assertEditableElement(errorString, elementId);
+ if (!element)
+ return;
+
+ m_domEditor->setAttribute(element, name, value, errorString);
+}
+
+void InspectorDOMAgent::setAttributesAsText(ErrorString* errorString, int elementId, const String& text, const String* const name)
+{
+ Element* element = assertEditableElement(errorString, elementId);
+ if (!element)
+ return;
+
+ RefPtr<HTMLElement> parsedElement = createHTMLElement(element->document(), spanTag);
+ ExceptionCode ec = 0;
+ parsedElement.get()->setInnerHTML("<span " + text + "></span>", ec);
+ if (ec) {
+ *errorString = InspectorDOMAgent::toErrorString(ec);
+ return;
+ }
+
+ Node* child = parsedElement->firstChild();
+ if (!child) {
+ *errorString = "Could not parse value as attributes";
+ return;
+ }
+
+ Element* childElement = toElement(child);
+ if (!childElement->hasAttributes() && name) {
+ m_domEditor->removeAttribute(element, *name, errorString);
+ return;
+ }
+
+ bool foundOriginalAttribute = false;
+ unsigned numAttrs = childElement->attributeCount();
+ for (unsigned i = 0; i < numAttrs; ++i) {
+ // Add attribute pair
+ const Attribute* attribute = childElement->attributeItem(i);
+ foundOriginalAttribute = foundOriginalAttribute || (name && attribute->name().toString() == *name);
+ if (!m_domEditor->setAttribute(element, attribute->name().toString(), attribute->value(), errorString))
+ return;
+ }
+
+ if (!foundOriginalAttribute && name && !name->stripWhiteSpace().isEmpty())
+ m_domEditor->removeAttribute(element, *name, errorString);
+}
+
+void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name)
+{
+ Element* element = assertEditableElement(errorString, elementId);
+ if (!element)
+ return;
+
+ m_domEditor->removeAttribute(element, name, errorString);
+}
+
+void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId)
+{
+ Node* node = assertEditableNode(errorString, nodeId);
+ if (!node)
+ return;
+
+ ContainerNode* parentNode = node->parentNode();
+ if (!parentNode) {
+ *errorString = "Can not remove detached node";
+ return;
+ }
+
+ m_domEditor->removeChild(parentNode, node, errorString);
+}
+
+void InspectorDOMAgent::setNodeName(ErrorString* errorString, int nodeId, const String& tagName, int* newId)
+{
+ *newId = 0;
+
+ Node* oldNode = nodeForId(nodeId);
+ if (!oldNode || !oldNode->isElementNode())
+ return;
+
+ ExceptionCode ec = 0;
+ RefPtr<Element> newElem = oldNode->document()->createElement(tagName, ec);
+ if (ec)
+ return;
+
+ // Copy over the original node's attributes.
+ newElem->cloneAttributesFromElement(*toElement(oldNode));
+
+ // Copy over the original node's children.
+ Node* child;
+ while ((child = oldNode->firstChild())) {
+ if (!m_domEditor->insertBefore(newElem.get(), child, 0, errorString))
+ return;
+ }
+
+ // Replace the old node with the new node
+ ContainerNode* parent = oldNode->parentNode();
+ if (!m_domEditor->insertBefore(parent, newElem.get(), oldNode->nextSibling(), errorString))
+ return;
+ if (!m_domEditor->removeChild(parent, oldNode, errorString))
+ return;
+
+ *newId = pushNodePathToFrontend(newElem.get());
+ if (m_childrenRequested.contains(nodeId))
+ pushChildNodesToFrontend(*newId);
+}
+
+void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML)
+{
+ Node* node = assertNode(errorString, nodeId);
+ if (!node)
+ return;
+
+ *outerHTML = createMarkup(node);
+}
+
+void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML)
+{
+ if (!nodeId) {
+ DOMPatchSupport domPatchSupport(m_domEditor.get(), m_document.get());
+ domPatchSupport.patchDocument(outerHTML);
+ return;
+ }
+
+ Node* node = assertEditableNode(errorString, nodeId);
+ if (!node)
+ return;
+
+ Document* document = node->isDocumentNode() ? toDocument(node) : node->ownerDocument();
+ if (!document || (!document->isHTMLDocument() && !document->isXHTMLDocument()
+#if ENABLE(SVG)
+ && !document->isSVGDocument()
+#endif
+ )) {
+ *errorString = "Not an HTML/XML document";
+ return;
+ }
+
+ Node* newNode = 0;
+ if (!m_domEditor->setOuterHTML(node, outerHTML, &newNode, errorString))
+ return;
+
+ if (!newNode) {
+ // The only child node has been deleted.
+ return;
+ }
+
+ int newId = pushNodePathToFrontend(newNode);
+
+ bool childrenRequested = m_childrenRequested.contains(nodeId);
+ if (childrenRequested)
+ pushChildNodesToFrontend(newId);
+}
+
+void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value)
+{
+ Node* node = assertEditableNode(errorString, nodeId);
+ if (!node)
+ return;
+
+ if (node->nodeType() != Node::TEXT_NODE) {
+ *errorString = "Can only set value of text nodes";
+ return;
+ }
+
+ m_domEditor->replaceWholeText(toText(node), value, errorString);
+}
+
+void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int nodeId, const String* objectGroup, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray)
+{
+ listenersArray = TypeBuilder::Array<TypeBuilder::DOM::EventListener>::create();
+ Node* node = assertNode(errorString, nodeId);
+ if (!node)
+ return;
+ Vector<EventListenerInfo> eventInformation;
+ getEventListeners(node, eventInformation, true);
+
+ // Get Capturing Listeners (in this order)
+ size_t eventInformationLength = eventInformation.size();
+ for (size_t i = 0; i < eventInformationLength; ++i) {
+ const EventListenerInfo& info = eventInformation[i];
+ const EventListenerVector& vector = info.eventListenerVector;
+ for (size_t j = 0; j < vector.size(); ++j) {
+ const RegisteredEventListener& listener = vector[j];
+ if (listener.useCapture)
+ listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup));
+ }
+ }
+
+ // Get Bubbling Listeners (reverse order)
+ for (size_t i = eventInformationLength; i; --i) {
+ const EventListenerInfo& info = eventInformation[i - 1];
+ const EventListenerVector& vector = info.eventListenerVector;
+ for (size_t j = 0; j < vector.size(); ++j) {
+ const RegisteredEventListener& listener = vector[j];
+ if (!listener.useCapture)
+ listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup));
+ }
+ }
+}
+
+void InspectorDOMAgent::getEventListeners(Node* node, Vector<EventListenerInfo>& eventInformation, bool includeAncestors)
+{
+ // The Node's Ancestors including self.
+ Vector<Node*> ancestors;
+ // Push this node as the firs element.
+ ancestors.append(node);
+ if (includeAncestors) {
+ for (ContainerNode* ancestor = node->parentOrShadowHostNode(); ancestor; ancestor = ancestor->parentOrShadowHostNode())
+ ancestors.append(ancestor);
+ }
+
+ // Nodes and their Listeners for the concerned event types (order is top to bottom)
+ for (size_t i = ancestors.size(); i; --i) {
+ Node* ancestor = ancestors[i - 1];
+ EventTargetData* d = ancestor->eventTargetData();
+ if (!d)
+ continue;
+ // Get the list of event types this Node is concerned with
+ Vector<AtomicString> eventTypes = d->eventListenerMap.eventTypes();
+ for (size_t j = 0; j < eventTypes.size(); ++j) {
+ AtomicString& type = eventTypes[j];
+ const EventListenerVector& listeners = ancestor->getEventListeners(type);
+ EventListenerVector filteredListeners;
+ filteredListeners.reserveCapacity(listeners.size());
+ for (size_t k = 0; k < listeners.size(); ++k) {
+ if (listeners[k].listener->type() == EventListener::JSEventListenerType)
+ filteredListeners.append(listeners[k]);
+ }
+ if (!filteredListeners.isEmpty())
+ eventInformation.append(EventListenerInfo(ancestor, type, filteredListeners));
+ }
+ }
+}
+
+void InspectorDOMAgent::performSearch(ErrorString*, const String& whitespaceTrimmedQuery, String* searchId, int* resultCount)
+{
+ // FIXME: Few things are missing here:
+ // 1) Search works with node granularity - number of matches within node is not calculated.
+ // 2) There is no need to push all search results to the front-end at a time, pushing next / previous result
+ // is sufficient.
+
+ unsigned queryLength = whitespaceTrimmedQuery.length();
+ bool startTagFound = !whitespaceTrimmedQuery.find('<');
+ bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength;
+ bool startQuoteFound = !whitespaceTrimmedQuery.find('"');
+ bool endQuoteFound = whitespaceTrimmedQuery.reverseFind('"') + 1 == queryLength;
+ bool exactAttributeMatch = startQuoteFound && endQuoteFound;
+
+ String tagNameQuery = whitespaceTrimmedQuery;
+ String attributeQuery = whitespaceTrimmedQuery;
+ if (startTagFound)
+ tagNameQuery = tagNameQuery.right(tagNameQuery.length() - 1);
+ if (endTagFound)
+ tagNameQuery = tagNameQuery.left(tagNameQuery.length() - 1);
+ if (startQuoteFound)
+ attributeQuery = attributeQuery.right(attributeQuery.length() - 1);
+ if (endQuoteFound)
+ attributeQuery = attributeQuery.left(attributeQuery.length() - 1);
+
+ Vector<Document*> docs = documents();
+ ListHashSet<Node*> resultCollector;
+
+ for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
+ Document* document = *it;
+ Node* node = document->documentElement();
+ if (!node)
+ continue;
+
+ // Manual plain text search.
+ while ((node = NodeTraversal::next(node, document->documentElement()))) {
+ switch (node->nodeType()) {
+ case Node::TEXT_NODE:
+ case Node::COMMENT_NODE:
+ case Node::CDATA_SECTION_NODE: {
+ String text = node->nodeValue();
+ if (text.findIgnoringCase(whitespaceTrimmedQuery) != notFound)
+ resultCollector.add(node);
+ break;
+ }
+ case Node::ELEMENT_NODE: {
+ if ((!startTagFound && !endTagFound && (node->nodeName().findIgnoringCase(tagNameQuery) != notFound))
+ || (startTagFound && endTagFound && equalIgnoringCase(node->nodeName(), tagNameQuery))
+ || (startTagFound && !endTagFound && node->nodeName().startsWith(tagNameQuery, false))
+ || (!startTagFound && endTagFound && node->nodeName().endsWith(tagNameQuery, false))) {
+ resultCollector.add(node);
+ break;
+ }
+ // Go through all attributes and serialize them.
+ const Element* element = toElement(node);
+ if (!element->hasAttributes())
+ break;
+
+ unsigned numAttrs = element->attributeCount();
+ for (unsigned i = 0; i < numAttrs; ++i) {
+ // Add attribute pair
+ const Attribute* attribute = element->attributeItem(i);
+ if (attribute->localName().find(whitespaceTrimmedQuery) != notFound) {
+ resultCollector.add(node);
+ break;
+ }
+ size_t foundPosition = attribute->value().find(attributeQuery);
+ if (foundPosition != notFound) {
+ if (!exactAttributeMatch || (!foundPosition && attribute->value().length() == attributeQuery.length())) {
+ resultCollector.add(node);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // XPath evaluation
+ for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
+ Document* document = *it;
+ ExceptionCode ec = 0;
+ RefPtr<XPathResult> result = document->evaluate(whitespaceTrimmedQuery, document, 0, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, ec);
+ if (ec || !result)
+ continue;
+
+ unsigned long size = result->snapshotLength(ec);
+ for (unsigned long i = 0; !ec && i < size; ++i) {
+ Node* node = result->snapshotItem(i, ec);
+ if (ec)
+ break;
+
+ if (node->nodeType() == Node::ATTRIBUTE_NODE)
+ node = static_cast<Attr*>(node)->ownerElement();
+ resultCollector.add(node);
+ }
+ }
+
+ // Selector evaluation
+ for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
+ Document* document = *it;
+ ExceptionCode ec = 0;
+ RefPtr<NodeList> nodeList = document->querySelectorAll(whitespaceTrimmedQuery, ec);
+ if (ec || !nodeList)
+ continue;
+
+ unsigned size = nodeList->length();
+ for (unsigned i = 0; i < size; ++i)
+ resultCollector.add(nodeList->item(i));
+ }
+ }
+
+ *searchId = IdentifiersFactory::createIdentifier();
+ SearchResults::iterator resultsIt = m_searchResults.add(*searchId, Vector<RefPtr<Node> >()).iterator;
+
+ for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it)
+ resultsIt->value.append(*it);
+
+ *resultCount = resultsIt->value.size();
+}
+
+void InspectorDOMAgent::getSearchResults(ErrorString* errorString, const String& searchId, int fromIndex, int toIndex, RefPtr<TypeBuilder::Array<int> >& nodeIds)
+{
+ SearchResults::iterator it = m_searchResults.find(searchId);
+ if (it == m_searchResults.end()) {
+ *errorString = "No search session with given id found";
+ return;
+ }
+
+ int size = it->value.size();
+ if (fromIndex < 0 || toIndex > size || fromIndex >= toIndex) {
+ *errorString = "Invalid search result range";
+ return;
+ }
+
+ nodeIds = TypeBuilder::Array<int>::create();
+ for (int i = fromIndex; i < toIndex; ++i)
+ nodeIds->addItem(pushNodePathToFrontend((it->value)[i].get()));
+}
+
+void InspectorDOMAgent::discardSearchResults(ErrorString*, const String& searchId)
+{
+ m_searchResults.remove(searchId);
+}
+
+bool InspectorDOMAgent::handleMousePress()
+{
+ if (!m_searchingForNode)
+ return false;
+
+ if (Node* node = m_overlay->highlightedNode()) {
+ inspect(node);
+ return true;
+ }
+ return false;
+}
+
+bool InspectorDOMAgent::handleTouchEvent(Frame* frame, const PlatformTouchEvent& event)
+{
+ if (!m_searchingForNode)
+ return false;
+ Node* node = hoveredNodeForEvent(frame, event, false);
+ if (node && m_inspectModeHighlightConfig) {
+ m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig);
+ inspect(node);
+ return true;
+ }
+ return false;
+}
+
+void InspectorDOMAgent::inspect(Node* inspectedNode)
+{
+ if (!m_frontend)
+ return;
+
+ Node* node = inspectedNode;
+ if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
+ node = node->parentNode();
+
+ int nodeId = pushNodePathToFrontend(node);
+ if (nodeId)
+ m_frontend->inspectNodeRequested(nodeId);
+
+ ErrorString error;
+ setSearchingForNode(&error, false, 0);
+}
+
+void InspectorDOMAgent::handleMouseMove(Frame* frame, const PlatformMouseEvent& event)
+{
+ if (!m_searchingForNode)
+ return;
+
+ if (!frame->view() || !frame->contentRenderer())
+ return;
+ Node* node = hoveredNodeForEvent(frame, event, event.shiftKey());
+ Node* eventTarget = event.shiftKey() ? hoveredNodeForEvent(frame, event, false) : 0;
+ if (eventTarget == node)
+ eventTarget = 0;
+
+ if (node && m_inspectModeHighlightConfig)
+ m_overlay->highlightNode(node, eventTarget, *m_inspectModeHighlightConfig);
+}
+
+void InspectorDOMAgent::setSearchingForNode(ErrorString* errorString, bool enabled, InspectorObject* highlightInspectorObject)
+{
+ if (m_searchingForNode == enabled)
+ return;
+ m_searchingForNode = enabled;
+ if (enabled) {
+ m_inspectModeHighlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject);
+ if (!m_inspectModeHighlightConfig)
+ return;
+ } else
+ hideHighlight(errorString);
+}
+
+PassOwnPtr<HighlightConfig> InspectorDOMAgent::highlightConfigFromInspectorObject(ErrorString* errorString, InspectorObject* highlightInspectorObject)
+{
+ if (!highlightInspectorObject) {
+ *errorString = "Internal error: highlight configuration parameter is missing";
+ return nullptr;
+ }
+
+ OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
+ bool showInfo = false; // Default: false (do not show a tooltip).
+ highlightInspectorObject->getBoolean("showInfo", &showInfo);
+ highlightConfig->showInfo = showInfo;
+ bool showRulers = false; // Default: false (do not show rulers).
+ highlightInspectorObject->getBoolean("showRulers", &showRulers);
+ highlightConfig->showRulers = showRulers;
+ highlightConfig->content = parseConfigColor("contentColor", highlightInspectorObject);
+ highlightConfig->contentOutline = parseConfigColor("contentOutlineColor", highlightInspectorObject);
+ highlightConfig->padding = parseConfigColor("paddingColor", highlightInspectorObject);
+ highlightConfig->border = parseConfigColor("borderColor", highlightInspectorObject);
+ highlightConfig->margin = parseConfigColor("marginColor", highlightInspectorObject);
+ highlightConfig->eventTarget = parseConfigColor("eventTargetColor", highlightInspectorObject);
+ return highlightConfig.release();
+}
+
+void InspectorDOMAgent::setInspectModeEnabled(ErrorString* errorString, bool enabled, const RefPtr<InspectorObject>* highlightConfig)
+{
+ setSearchingForNode(errorString, enabled, highlightConfig ? highlightConfig->get() : 0);
+}
+
+void InspectorDOMAgent::highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor)
+{
+ OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad(FloatRect(x, y, width, height)));
+ innerHighlightQuad(quad.release(), color, outlineColor);
+}
+
+void InspectorDOMAgent::highlightQuad(ErrorString* errorString, const RefPtr<InspectorArray>& quadArray, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor)
+{
+ OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad());
+ if (!parseQuad(quadArray, quad.get())) {
+ *errorString = "Invalid Quad format";
+ return;
+ }
+ innerHighlightQuad(quad.release(), color, outlineColor);
+}
+
+void InspectorDOMAgent::innerHighlightQuad(PassOwnPtr<FloatQuad> quad, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor)
+{
+ OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
+ highlightConfig->content = parseColor(color);
+ highlightConfig->contentOutline = parseColor(outlineColor);
+ m_overlay->highlightQuad(quad, *highlightConfig);
+}
+
+void InspectorDOMAgent::highlightNode(ErrorString* errorString, const RefPtr<InspectorObject>& highlightInspectorObject, const int* nodeId, const String* objectId)
+{
+ Node* node = 0;
+ if (nodeId) {
+ node = assertNode(errorString, *nodeId);
+ } else if (objectId) {
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*objectId);
+ node = injectedScript.nodeForObjectId(*objectId);
+ if (!node)
+ *errorString = "Node for given objectId not found";
+ } else
+ *errorString = "Either nodeId or objectId must be specified";
+
+ if (!node)
+ return;
+
+ OwnPtr<HighlightConfig> highlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject.get());
+ if (!highlightConfig)
+ return;
+
+ m_overlay->highlightNode(node, 0 /* eventTarget */, *highlightConfig);
+}
+
+void InspectorDOMAgent::highlightFrame(
+ ErrorString*,
+ const String& frameId,
+ const RefPtr<InspectorObject>* color,
+ const RefPtr<InspectorObject>* outlineColor)
+{
+ Frame* frame = m_pageAgent->frameForId(frameId);
+ if (frame && frame->ownerElement()) {
+ OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
+ highlightConfig->showInfo = true; // Always show tooltips for frames.
+ highlightConfig->content = parseColor(color);
+ highlightConfig->contentOutline = parseColor(outlineColor);
+ m_overlay->highlightNode(frame->ownerElement(), 0 /* eventTarget */, *highlightConfig);
+ }
+}
+
+void InspectorDOMAgent::hideHighlight(ErrorString*)
+{
+ m_overlay->hideHighlight();
+}
+
+void InspectorDOMAgent::moveTo(ErrorString* errorString, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId)
+{
+ Node* node = assertEditableNode(errorString, nodeId);
+ if (!node)
+ return;
+
+ Element* targetElement = assertEditableElement(errorString, targetElementId);
+ if (!targetElement)
+ return;
+
+ Node* anchorNode = 0;
+ if (anchorNodeId && *anchorNodeId) {
+ anchorNode = assertEditableNode(errorString, *anchorNodeId);
+ if (!anchorNode)
+ return;
+ if (anchorNode->parentNode() != targetElement) {
+ *errorString = "Anchor node must be child of the target element";
+ return;
+ }
+ }
+
+ if (!m_domEditor->insertBefore(targetElement, node, anchorNode, errorString))
+ return;
+
+ *newNodeId = pushNodePathToFrontend(node);
+}
+
+void InspectorDOMAgent::undo(ErrorString* errorString)
+{
+ ExceptionCode ec = 0;
+ m_history->undo(ec);
+ *errorString = InspectorDOMAgent::toErrorString(ec);
+}
+
+void InspectorDOMAgent::redo(ErrorString* errorString)
+{
+ ExceptionCode ec = 0;
+ m_history->redo(ec);
+ *errorString = InspectorDOMAgent::toErrorString(ec);
+}
+
+void InspectorDOMAgent::markUndoableState(ErrorString*)
+{
+ m_history->markUndoableState();
+}
+
+void InspectorDOMAgent::focus(ErrorString* errorString, int nodeId)
+{
+ Element* element = assertElement(errorString, nodeId);
+ if (!element)
+ return;
+ if (!element->isFocusable()) {
+ *errorString = "Element is not focusable";
+ return;
+ }
+ element->focus();
+}
+
+void InspectorDOMAgent::setFileInputFiles(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>& files)
+{
+ Node* node = assertNode(errorString, nodeId);
+ if (!node)
+ return;
+ HTMLInputElement* element = node->toInputElement();
+ if (!element || !element->isFileUpload()) {
+ *errorString = "Node is not a file input element";
+ return;
+ }
+
+ RefPtr<FileList> fileList = FileList::create();
+ for (InspectorArray::const_iterator iter = files->begin(); iter != files->end(); ++iter) {
+ String path;
+ if (!(*iter)->asString(&path)) {
+ *errorString = "Files must be strings";
+ return;
+ }
+ fileList->append(File::create(path));
+ }
+ element->setFiles(fileList);
+}
+
+void InspectorDOMAgent::resolveNode(ErrorString* errorString, int nodeId, const String* const objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result)
+{
+ String objectGroupName = objectGroup ? *objectGroup : "";
+ Node* node = nodeForId(nodeId);
+ if (!node) {
+ *errorString = "No node with given id found";
+ return;
+ }
+ RefPtr<TypeBuilder::Runtime::RemoteObject> object = resolveNode(node, objectGroupName);
+ if (!object) {
+ *errorString = "Node with given id does not belong to the document";
+ return;
+ }
+ result = object;
+}
+
+void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<String> >& result)
+{
+ Element* element = assertElement(errorString, nodeId);
+ if (!element)
+ return;
+
+ result = buildArrayForElementAttributes(element);
+}
+
+void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* nodeId)
+{
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
+ Node* node = injectedScript.nodeForObjectId(objectId);
+ if (node)
+ *nodeId = pushNodePathToFrontend(node);
+ else
+ *nodeId = 0;
+}
+
+// static
+String InspectorDOMAgent::documentURLString(Document* document)
+{
+ if (!document || document->url().isNull())
+ return "";
+ return document->url().string();
+}
+
+static String documentBaseURLString(Document* document)
+{
+ return document->completeURL("").string();
+}
+
+PassRefPtr<TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
+{
+ int id = bind(node, nodesMap);
+ String nodeName;
+ String localName;
+ String nodeValue;
+
+ switch (node->nodeType()) {
+ case Node::TEXT_NODE:
+ case Node::COMMENT_NODE:
+ case Node::CDATA_SECTION_NODE:
+ nodeValue = node->nodeValue();
+ if (nodeValue.length() > maxTextSize) {
+ nodeValue = nodeValue.left(maxTextSize);
+ nodeValue.append(ellipsisUChar);
+ }
+ break;
+ case Node::ATTRIBUTE_NODE:
+ localName = node->localName();
+ break;
+ case Node::DOCUMENT_FRAGMENT_NODE:
+ case Node::DOCUMENT_NODE:
+ case Node::ELEMENT_NODE:
+ default:
+ nodeName = node->nodeName();
+ localName = node->localName();
+ break;
+ }
+
+ RefPtr<TypeBuilder::DOM::Node> value = TypeBuilder::DOM::Node::create()
+ .setNodeId(id)
+ .setNodeType(static_cast<int>(node->nodeType()))
+ .setNodeName(nodeName)
+ .setLocalName(localName)
+ .setNodeValue(nodeValue);
+
+ if (node->isContainerNode()) {
+ int nodeCount = innerChildNodeCount(node);
+ value->setChildNodeCount(nodeCount);
+ RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodesMap);
+ if (children->length() > 0)
+ value->setChildren(children.release());
+ }
+
+ if (node->isElementNode()) {
+ Element* element = toElement(node);
+ value->setAttributes(buildArrayForElementAttributes(element));
+ if (node->isFrameOwnerElement()) {
+ HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
+ Frame* frame = frameOwner->contentFrame();
+ if (frame)
+ value->setFrameId(m_pageAgent->frameId(frame));
+ Document* doc = frameOwner->contentDocument();
+ if (doc)
+ value->setContentDocument(buildObjectForNode(doc, 0, nodesMap));
+ }
+
+ ElementShadow* shadow = element->shadow();
+ if (shadow) {
+ RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > shadowRoots = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
+ for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot())
+ shadowRoots->addItem(buildObjectForNode(root, 0, nodesMap));
+ value->setShadowRoots(shadowRoots);
+ }
+
+ if (element->hasTagName(templateTag))
+ value->setTemplateContent(buildObjectForNode(static_cast<HTMLTemplateElement*>(element)->content(), 0, nodesMap));
+ } else if (node->isDocumentNode()) {
+ Document* document = toDocument(node);
+ value->setDocumentURL(documentURLString(document));
+ value->setBaseURL(documentBaseURLString(document));
+ value->setXmlVersion(document->xmlVersion());
+ } else if (node->nodeType() == Node::DOCUMENT_TYPE_NODE) {
+ DocumentType* docType = static_cast<DocumentType*>(node);
+ value->setPublicId(docType->publicId());
+ value->setSystemId(docType->systemId());
+ value->setInternalSubset(docType->internalSubset());
+ } else if (node->isAttributeNode()) {
+ Attr* attribute = static_cast<Attr*>(node);
+ value->setName(attribute->name());
+ value->setValue(attribute->value());
+ }
+ return value.release();
+}
+
+PassRefPtr<TypeBuilder::Array<String> > InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
+{
+ RefPtr<TypeBuilder::Array<String> > attributesValue = TypeBuilder::Array<String>::create();
+ // Go through all attributes and serialize them.
+ if (!element->hasAttributes())
+ return attributesValue.release();
+ unsigned numAttrs = element->attributeCount();
+ for (unsigned i = 0; i < numAttrs; ++i) {
+ // Add attribute pair
+ const Attribute* attribute = element->attributeItem(i);
+ attributesValue->addItem(attribute->name().toString());
+ attributesValue->addItem(attribute->value());
+ }
+ return attributesValue.release();
+}
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
+ if (depth == 0) {
+ // Special-case the only text child - pretend that container's children have been requested.
+ Node* firstChild = container->firstChild();
+ if (firstChild && firstChild->nodeType() == Node::TEXT_NODE && !firstChild->nextSibling()) {
+ children->addItem(buildObjectForNode(firstChild, 0, nodesMap));
+ m_childrenRequested.add(bind(container, nodesMap));
+ }
+ return children.release();
+ }
+
+ Node* child = innerFirstChild(container);
+ depth--;
+ m_childrenRequested.add(bind(container, nodesMap));
+
+ while (child) {
+ children->addItem(buildObjectForNode(child, depth, nodesMap));
+ child = innerNextSibling(child);
+ }
+ return children.release();
+}
+
+PassRefPtr<TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId)
+{
+ RefPtr<EventListener> eventListener = registeredEventListener.listener;
+ Document* document = node->document();
+ RefPtr<TypeBuilder::DOM::EventListener> value = TypeBuilder::DOM::EventListener::create()
+ .setType(eventType)
+ .setUseCapture(registeredEventListener.useCapture)
+ .setIsAttribute(eventListener->isAttribute())
+ .setNodeId(pushNodePathToFrontend(node))
+ .setHandlerBody(eventListenerHandlerBody(document, eventListener.get()));
+ if (objectGroupId) {
+ ScriptValue functionValue = eventListenerHandler(document, eventListener.get());
+ if (!functionValue.hasNoValue()) {
+ Frame* frame = document->frame();
+ if (frame) {
+ ScriptState* scriptState = eventListenerHandlerScriptState(frame, eventListener.get());
+ if (scriptState) {
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
+ if (!injectedScript.hasNoValue()) {
+ RefPtr<TypeBuilder::Runtime::RemoteObject> valueJson = injectedScript.wrapObject(functionValue, *objectGroupId);
+ value->setHandler(valueJson);
+ }
+ }
+ }
+ }
+ }
+ String sourceName;
+ String scriptId;
+ int lineNumber;
+ if (eventListenerHandlerLocation(node->document(), eventListener.get(), sourceName, scriptId, lineNumber)) {
+ RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
+ .setScriptId(scriptId)
+ .setLineNumber(lineNumber);
+ value->setLocation(location);
+ if (!sourceName.isEmpty())
+ value->setSourceName(sourceName);
+ }
+ return value.release();
+}
+
+Node* InspectorDOMAgent::innerFirstChild(Node* node)
+{
+ node = node->firstChild();
+ while (isWhitespace(node))
+ node = node->nextSibling();
+ return node;
+}
+
+Node* InspectorDOMAgent::innerNextSibling(Node* node)
+{
+ do {
+ node = node->nextSibling();
+ } while (isWhitespace(node));
+ return node;
+}
+
+Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
+{
+ do {
+ node = node->previousSibling();
+ } while (isWhitespace(node));
+ return node;
+}
+
+unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
+{
+ unsigned count = 0;
+ Node* child = innerFirstChild(node);
+ while (child) {
+ count++;
+ child = innerNextSibling(child);
+ }
+ return count;
+}
+
+Node* InspectorDOMAgent::innerParentNode(Node* node)
+{
+ if (node->isDocumentNode()) {
+ Document* document = toDocument(node);
+ return document->ownerElement();
+ }
+ return node->parentNode();
+}
+
+bool InspectorDOMAgent::isWhitespace(Node* node)
+{
+ //TODO: pull ignoreWhitespace setting from the frontend and use here.
+ return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
+}
+
+void InspectorDOMAgent::mainFrameDOMContentLoaded()
+{
+ // Re-push document once it is loaded.
+ discardBindings();
+ if (m_state->getBoolean(DOMAgentState::documentRequested))
+ m_frontend->documentUpdated();
+}
+
+void InspectorDOMAgent::loadEventFired(Document* document)
+{
+ Element* frameOwner = document->ownerElement();
+ if (!frameOwner)
+ return;
+
+ int frameOwnerId = m_documentNodeToIdMap.get(frameOwner);
+ if (!frameOwnerId)
+ return;
+
+ // Re-add frame owner element together with its new children.
+ int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner));
+ m_frontend->childNodeRemoved(parentId, frameOwnerId);
+ unbind(frameOwner, &m_documentNodeToIdMap);
+
+ RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(frameOwner, 0, &m_documentNodeToIdMap);
+ Node* previousSibling = innerPreviousSibling(frameOwner);
+ int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0;
+ m_frontend->childNodeInserted(parentId, prevId, value.release());
+}
+
+void InspectorDOMAgent::didInsertDOMNode(Node* node)
+{
+ if (isWhitespace(node))
+ return;
+
+ // We could be attaching existing subtree. Forget the bindings.
+ unbind(node, &m_documentNodeToIdMap);
+
+ ContainerNode* parent = node->parentNode();
+ if (!parent)
+ return;
+
+ int parentId = m_documentNodeToIdMap.get(parent);
+ // Return if parent is not mapped yet.
+ if (!parentId)
+ return;
+
+ if (!m_childrenRequested.contains(parentId)) {
+ // No children are mapped yet -> only notify on changes of hasChildren.
+ m_frontend->childNodeCountUpdated(parentId, innerChildNodeCount(parent));
+ } else {
+ // Children have been requested -> return value of a new child.
+ Node* prevSibling = innerPreviousSibling(node);
+ int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0;
+ RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(node, 0, &m_documentNodeToIdMap);
+ m_frontend->childNodeInserted(parentId, prevId, value.release());
+ }
+}
+
+void InspectorDOMAgent::didRemoveDOMNode(Node* node)
+{
+ if (isWhitespace(node))
+ return;
+
+ ContainerNode* parent = node->parentNode();
+
+ // If parent is not mapped yet -> ignore the event.
+ if (!m_documentNodeToIdMap.contains(parent))
+ return;
+
+ int parentId = m_documentNodeToIdMap.get(parent);
+
+ if (!m_childrenRequested.contains(parentId)) {
+ // No children are mapped yet -> only notify on changes of hasChildren.
+ if (innerChildNodeCount(parent) == 1)
+ m_frontend->childNodeCountUpdated(parentId, 0);
+ } else
+ m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node));
+ unbind(node, &m_documentNodeToIdMap);
+}
+
+void InspectorDOMAgent::willModifyDOMAttr(Element*, const AtomicString& oldValue, const AtomicString& newValue)
+{
+ m_suppressAttributeModifiedEvent = (oldValue == newValue);
+}
+
+void InspectorDOMAgent::didModifyDOMAttr(Element* element, const AtomicString& name, const AtomicString& value)
+{
+ bool shouldSuppressEvent = m_suppressAttributeModifiedEvent;
+ m_suppressAttributeModifiedEvent = false;
+ if (shouldSuppressEvent)
+ return;
+
+ int id = boundNodeId(element);
+ // If node is not mapped yet -> ignore the event.
+ if (!id)
+ return;
+
+ if (m_domListener)
+ m_domListener->didModifyDOMAttr(element);
+
+ m_frontend->attributeModified(id, name, value);
+}
+
+void InspectorDOMAgent::didRemoveDOMAttr(Element* element, const AtomicString& name)
+{
+ int id = boundNodeId(element);
+ // If node is not mapped yet -> ignore the event.
+ if (!id)
+ return;
+
+ if (m_domListener)
+ m_domListener->didModifyDOMAttr(element);
+
+ m_frontend->attributeRemoved(id, name);
+}
+
+void InspectorDOMAgent::styleAttributeInvalidated(const Vector<Element*>& elements)
+{
+ RefPtr<TypeBuilder::Array<int> > nodeIds = TypeBuilder::Array<int>::create();
+ for (unsigned i = 0, size = elements.size(); i < size; ++i) {
+ Element* element = elements.at(i);
+ int id = boundNodeId(element);
+ // If node is not mapped yet -> ignore the event.
+ if (!id)
+ continue;
+
+ if (m_domListener)
+ m_domListener->didModifyDOMAttr(element);
+ nodeIds->addItem(id);
+ }
+ m_frontend->inlineStyleInvalidated(nodeIds.release());
+}
+
+void InspectorDOMAgent::characterDataModified(CharacterData* characterData)
+{
+ int id = m_documentNodeToIdMap.get(characterData);
+ if (!id) {
+ // Push text node if it is being created.
+ didInsertDOMNode(characterData);
+ return;
+ }
+ m_frontend->characterDataModified(id, characterData->data());
+}
+
+void InspectorDOMAgent::didInvalidateStyleAttr(Node* node)
+{
+ int id = m_documentNodeToIdMap.get(node);
+ // If node is not mapped yet -> ignore the event.
+ if (!id)
+ return;
+
+ if (!m_revalidateStyleAttrTask)
+ m_revalidateStyleAttrTask = adoptPtr(new RevalidateStyleAttributeTask(this));
+ m_revalidateStyleAttrTask->scheduleFor(toElement(node));
+}
+
+void InspectorDOMAgent::didPushShadowRoot(Element* host, ShadowRoot* root)
+{
+ int hostId = m_documentNodeToIdMap.get(host);
+ if (hostId)
+ m_frontend->shadowRootPushed(hostId, buildObjectForNode(root, 0, &m_documentNodeToIdMap));
+}
+
+void InspectorDOMAgent::willPopShadowRoot(Element* host, ShadowRoot* root)
+{
+ int hostId = m_documentNodeToIdMap.get(host);
+ int rootId = m_documentNodeToIdMap.get(root);
+ if (hostId && rootId)
+ m_frontend->shadowRootPopped(hostId, rootId);
+}
+
+void InspectorDOMAgent::frameDocumentUpdated(Frame* frame)
+{
+ Document* document = frame->document();
+ if (!document)
+ return;
+
+ Page* page = frame->page();
+ ASSERT(page);
+ if (frame != page->mainFrame())
+ return;
+
+ // Only update the main frame document, nested frame document updates are not required
+ // (will be handled by loadEventFired()).
+ setDocument(document);
+}
+
+Node* InspectorDOMAgent::nodeForPath(const String& path)
+{
+ // The path is of form "1,HTML,2,BODY,1,DIV"
+ if (!m_document)
+ return 0;
+
+ Node* node = m_document.get();
+ Vector<String> pathTokens;
+ path.split(",", false, pathTokens);
+ if (!pathTokens.size())
+ return 0;
+ for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
+ bool success = true;
+ unsigned childNumber = pathTokens[i].toUInt(&success);
+ if (!success)
+ return 0;
+ if (childNumber >= innerChildNodeCount(node))
+ return 0;
+
+ Node* child = innerFirstChild(node);
+ String childName = pathTokens[i + 1];
+ for (size_t j = 0; child && j < childNumber; ++j)
+ child = innerNextSibling(child);
+
+ if (!child || child->nodeName() != childName)
+ return 0;
+ node = child;
+ }
+ return node;
+}
+
+void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString* errorString, const String& path, int* nodeId)
+{
+ if (Node* node = nodeForPath(path))
+ *nodeId = pushNodePathToFrontend(node);
+ else
+ *errorString = "No node with given path found";
+}
+
+void InspectorDOMAgent::pushNodeByBackendIdToFrontend(ErrorString* errorString, BackendNodeId backendNodeId, int* nodeId)
+{
+ if (!m_backendIdToNode.contains(backendNodeId)) {
+ *errorString = "No node with given backend id found";
+ return;
+ }
+
+ Node* node = m_backendIdToNode.get(backendNodeId).first;
+ String nodeGroup = m_backendIdToNode.get(backendNodeId).second;
+ *nodeId = pushNodePathToFrontend(node);
+
+ if (nodeGroup == "") {
+ m_backendIdToNode.remove(backendNodeId);
+ m_nodeGroupToBackendIdMap.find(nodeGroup)->value.remove(node);
+ }
+}
+
+PassRefPtr<TypeBuilder::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
+{
+ Document* document = node->isDocumentNode() ? node->document() : node->ownerDocument();
+ Frame* frame = document ? document->frame() : 0;
+ if (!frame)
+ return 0;
+
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
+ if (injectedScript.hasNoValue())
+ return 0;
+
+ return injectedScript.wrapNode(node, objectGroup);
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorDOMAgent.h b/Source/core/inspector/InspectorDOMAgent.h
new file mode 100644
index 0000000..219622a
--- /dev/null
+++ b/Source/core/inspector/InspectorDOMAgent.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorDOMAgent_h
+#define InspectorDOMAgent_h
+
+#include "InspectorFrontend.h"
+#include "core/dom/EventTarget.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/inspector/InspectorOverlay.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/platform/Timer.h"
+#include "core/rendering/RenderLayer.h"
+
+#include <wtf/Deque.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+class ContainerNode;
+class CharacterData;
+class DOMEditor;
+class Document;
+class Element;
+class Event;
+class InspectorClient;
+class InspectorFrontend;
+class InspectorHistory;
+class InspectorOverlay;
+class InspectorPageAgent;
+class HTMLElement;
+class InspectorState;
+class InstrumentingAgents;
+class NameNodeMap;
+class Node;
+class PlatformTouchEvent;
+class RevalidateStyleAttributeTask;
+class ScriptValue;
+class ShadowRoot;
+
+struct HighlightConfig;
+
+typedef String ErrorString;
+typedef int BackendNodeId;
+
+
+struct EventListenerInfo {
+ EventListenerInfo(Node* node, const AtomicString& eventType, const EventListenerVector& eventListenerVector)
+ : node(node)
+ , eventType(eventType)
+ , eventListenerVector(eventListenerVector)
+ {
+ }
+
+ Node* node;
+ const AtomicString eventType;
+ const EventListenerVector eventListenerVector;
+};
+
+class InspectorDOMAgent : public InspectorBaseAgent<InspectorDOMAgent>, public InspectorBackendDispatcher::DOMCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorDOMAgent);
+public:
+ struct DOMListener {
+ virtual ~DOMListener()
+ {
+ }
+ virtual void didRemoveDocument(Document*) = 0;
+ virtual void didRemoveDOMNode(Node*) = 0;
+ virtual void didModifyDOMAttr(Element*) = 0;
+ };
+
+ static PassOwnPtr<InspectorDOMAgent> create(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager, InspectorOverlay* overlay, InspectorClient* client)
+ {
+ return adoptPtr(new InspectorDOMAgent(instrumentingAgents, pageAgent, inspectorState, injectedScriptManager, overlay, client));
+ }
+
+ static String toErrorString(const ExceptionCode&);
+
+ ~InspectorDOMAgent();
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ Vector<Document*> documents();
+ void reset();
+
+ // Methods called from the frontend for DOM nodes inspection.
+ virtual void querySelector(ErrorString*, int nodeId, const String& selectors, int* elementId);
+ virtual void querySelectorAll(ErrorString*, int nodeId, const String& selectors, RefPtr<TypeBuilder::Array<int> >& result);
+ virtual void getDocument(ErrorString*, RefPtr<TypeBuilder::DOM::Node>& root);
+ virtual void requestChildNodes(ErrorString*, int nodeId, const int* depth);
+ virtual void setAttributeValue(ErrorString*, int elementId, const String& name, const String& value);
+ virtual void setAttributesAsText(ErrorString*, int elementId, const String& text, const String* name);
+ virtual void removeAttribute(ErrorString*, int elementId, const String& name);
+ virtual void removeNode(ErrorString*, int nodeId);
+ virtual void setNodeName(ErrorString*, int nodeId, const String& name, int* newId);
+ virtual void getOuterHTML(ErrorString*, int nodeId, WTF::String* outerHTML);
+ virtual void setOuterHTML(ErrorString*, int nodeId, const String& outerHTML);
+ virtual void setNodeValue(ErrorString*, int nodeId, const String& value);
+ virtual void getEventListenersForNode(ErrorString*, int nodeId, const WTF::String* objectGroup, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray);
+ virtual void performSearch(ErrorString*, const String& whitespaceTrimmedQuery, String* searchId, int* resultCount);
+ virtual void getSearchResults(ErrorString*, const String& searchId, int fromIndex, int toIndex, RefPtr<TypeBuilder::Array<int> >&);
+ virtual void discardSearchResults(ErrorString*, const String& searchId);
+ virtual void resolveNode(ErrorString*, int nodeId, const String* objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result);
+ virtual void getAttributes(ErrorString*, int nodeId, RefPtr<TypeBuilder::Array<String> >& result);
+ virtual void setInspectModeEnabled(ErrorString*, bool enabled, const RefPtr<InspectorObject>* highlightConfig);
+ virtual void requestNode(ErrorString*, const String& objectId, int* nodeId);
+ virtual void pushNodeByPathToFrontend(ErrorString*, const String& path, int* nodeId);
+ virtual void pushNodeByBackendIdToFrontend(ErrorString*, BackendNodeId, int* nodeId);
+ virtual void releaseBackendNodeIds(ErrorString*, const String& nodeGroup);
+ virtual void hideHighlight(ErrorString*);
+ virtual void highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor);
+ virtual void highlightQuad(ErrorString*, const RefPtr<InspectorArray>& quad, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor);
+ virtual void highlightNode(ErrorString*, const RefPtr<InspectorObject>& highlightConfig, const int* nodeId, const String* objectId);
+ virtual void highlightFrame(ErrorString*, const String& frameId, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor);
+
+ virtual void moveTo(ErrorString*, int nodeId, int targetNodeId, const int* anchorNodeId, int* newNodeId);
+ virtual void undo(ErrorString*);
+ virtual void redo(ErrorString*);
+ virtual void markUndoableState(ErrorString*);
+ virtual void focus(ErrorString*, int nodeId);
+ virtual void setFileInputFiles(ErrorString*, int nodeId, const RefPtr<InspectorArray>& files);
+
+ void getEventListeners(Node*, Vector<EventListenerInfo>& listenersArray, bool includeAncestors);
+
+ // Methods called from the InspectorInstrumentation.
+ void setDocument(Document*);
+ void releaseDanglingNodes();
+
+ void mainFrameDOMContentLoaded();
+ void loadEventFired(Document*);
+
+ void didInsertDOMNode(Node*);
+ void didRemoveDOMNode(Node*);
+ void willModifyDOMAttr(Element*, const AtomicString& oldValue, const AtomicString& newValue);
+ void didModifyDOMAttr(Element*, const AtomicString& name, const AtomicString& value);
+ void didRemoveDOMAttr(Element*, const AtomicString& name);
+ void styleAttributeInvalidated(const Vector<Element*>& elements);
+ void characterDataModified(CharacterData*);
+ void didInvalidateStyleAttr(Node*);
+ void didPushShadowRoot(Element* host, ShadowRoot*);
+ void willPopShadowRoot(Element* host, ShadowRoot*);
+ void frameDocumentUpdated(Frame*);
+
+ int pushNodeToFrontend(ErrorString*, int documentNodeId, Node*);
+ Node* nodeForId(int nodeId);
+ int boundNodeId(Node*);
+ void setDOMListener(DOMListener*);
+ BackendNodeId backendNodeIdForNode(Node*, const String& nodeGroup);
+
+ static String documentURLString(Document*);
+
+ PassRefPtr<TypeBuilder::Runtime::RemoteObject> resolveNode(Node*, const String& objectGroup);
+ bool handleMousePress();
+ bool handleTouchEvent(Frame*, const PlatformTouchEvent&);
+ void handleMouseMove(Frame*, const PlatformMouseEvent&);
+
+ InspectorHistory* history() { return m_history.get(); }
+
+ // We represent embedded doms as a part of the same hierarchy. Hence we treat children of frame owners differently.
+ // We also skip whitespace text nodes conditionally. Following methods encapsulate these specifics.
+ static Node* innerFirstChild(Node*);
+ static Node* innerNextSibling(Node*);
+ static Node* innerPreviousSibling(Node*);
+ static unsigned innerChildNodeCount(Node*);
+ static Node* innerParentNode(Node*);
+ static bool isWhitespace(Node*);
+
+ Node* assertNode(ErrorString*, int nodeId);
+ Element* assertElement(ErrorString*, int nodeId);
+ Document* assertDocument(ErrorString*, int nodeId);
+
+ // Methods called from other agents.
+ InspectorPageAgent* pageAgent() { return m_pageAgent; }
+
+private:
+ InspectorDOMAgent(InstrumentingAgents*, InspectorPageAgent*, InspectorCompositeState*, InjectedScriptManager*, InspectorOverlay*, InspectorClient*);
+
+ void setSearchingForNode(ErrorString*, bool enabled, InspectorObject* highlightConfig);
+ PassOwnPtr<HighlightConfig> highlightConfigFromInspectorObject(ErrorString*, InspectorObject* highlightInspectorObject);
+
+ // Node-related methods.
+ typedef HashMap<RefPtr<Node>, int> NodeToIdMap;
+ int bind(Node*, NodeToIdMap*);
+ void unbind(Node*, NodeToIdMap*);
+
+ Node* assertEditableNode(ErrorString*, int nodeId);
+ Element* assertEditableElement(ErrorString*, int nodeId);
+
+ void inspect(Node*);
+
+ int pushNodePathToFrontend(Node*);
+ void pushChildNodesToFrontend(int nodeId, int depth = 1);
+
+ bool hasBreakpoint(Node*, int type);
+ void updateSubtreeBreakpoints(Node* root, uint32_t rootMask, bool value);
+ void descriptionForDOMEvent(Node* target, int breakpointType, bool insertion, PassRefPtr<InspectorObject> description);
+
+ PassRefPtr<TypeBuilder::DOM::Node> buildObjectForNode(Node*, int depth, NodeToIdMap*);
+ PassRefPtr<TypeBuilder::Array<String> > buildArrayForElementAttributes(Element*);
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap);
+ PassRefPtr<TypeBuilder::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, const AtomicString& eventType, Node*, const String* objectGroupId);
+
+ Node* nodeForPath(const String& path);
+
+ void discardBindings();
+
+ void innerHighlightQuad(PassOwnPtr<FloatQuad>, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor);
+
+ InspectorPageAgent* m_pageAgent;
+ InjectedScriptManager* m_injectedScriptManager;
+ InspectorOverlay* m_overlay;
+ InspectorClient* m_client;
+ InspectorFrontend::DOM* m_frontend;
+ DOMListener* m_domListener;
+ NodeToIdMap m_documentNodeToIdMap;
+ typedef HashMap<RefPtr<Node>, BackendNodeId> NodeToBackendIdMap;
+ HashMap<String, NodeToBackendIdMap> m_nodeGroupToBackendIdMap;
+ // Owns node mappings for dangling nodes.
+ Vector<OwnPtr<NodeToIdMap> > m_danglingNodeToIdMaps;
+ HashMap<int, Node*> m_idToNode;
+ HashMap<int, NodeToIdMap*> m_idToNodesMap;
+ HashSet<int> m_childrenRequested;
+ HashMap<BackendNodeId, std::pair<Node*, String> > m_backendIdToNode;
+ int m_lastNodeId;
+ BackendNodeId m_lastBackendNodeId;
+ RefPtr<Document> m_document;
+ typedef HashMap<String, Vector<RefPtr<Node> > > SearchResults;
+ SearchResults m_searchResults;
+ OwnPtr<RevalidateStyleAttributeTask> m_revalidateStyleAttrTask;
+ bool m_searchingForNode;
+ OwnPtr<HighlightConfig> m_inspectModeHighlightConfig;
+ OwnPtr<InspectorHistory> m_history;
+ OwnPtr<DOMEditor> m_domEditor;
+ bool m_suppressAttributeModifiedEvent;
+};
+
+
+} // namespace WebCore
+
+#endif // !defined(InspectorDOMAgent_h)
diff --git a/Source/core/inspector/InspectorDOMDebuggerAgent.cpp b/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
new file mode 100644
index 0000000..7dbd67b
--- /dev/null
+++ b/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorDOMDebuggerAgent.h"
+
+#include "InspectorFrontend.h"
+#include "core/html/HTMLElement.h"
+#include "core/inspector/InspectorAgent.h"
+#include "core/inspector/InspectorDOMAgent.h"
+#include "core/inspector/InspectorDebuggerAgent.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include <wtf/text/WTFString.h>
+
+namespace {
+
+enum DOMBreakpointType {
+ SubtreeModified = 0,
+ AttributeModified,
+ NodeRemoved,
+ DOMBreakpointTypesCount
+};
+
+static const char* const listenerEventCategoryType = "listener:";
+static const char* const instrumentationEventCategoryType = "instrumentation:";
+
+const uint32_t inheritableDOMBreakpointTypesMask = (1 << SubtreeModified);
+const int domBreakpointDerivedTypeShift = 16;
+
+}
+
+namespace WebCore {
+
+namespace DOMDebuggerAgentState {
+static const char eventListenerBreakpoints[] = "eventListenerBreakpoints";
+static const char pauseOnAllXHRs[] = "pauseOnAllXHRs";
+static const char xhrBreakpoints[] = "xhrBreakpoints";
+}
+
+PassOwnPtr<InspectorDOMDebuggerAgent> InspectorDOMDebuggerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent, InspectorAgent* inspectorAgent)
+{
+ return adoptPtr(new InspectorDOMDebuggerAgent(instrumentingAgents, inspectorState, domAgent, debuggerAgent, inspectorAgent));
+}
+
+InspectorDOMDebuggerAgent::InspectorDOMDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent, InspectorAgent*)
+ : InspectorBaseAgent<InspectorDOMDebuggerAgent>("DOMDebugger", instrumentingAgents, inspectorState)
+ , m_domAgent(domAgent)
+ , m_debuggerAgent(debuggerAgent)
+ , m_pauseInNextEventListener(false)
+{
+ m_debuggerAgent->setListener(this);
+}
+
+InspectorDOMDebuggerAgent::~InspectorDOMDebuggerAgent()
+{
+ ASSERT(!m_debuggerAgent);
+ ASSERT(!m_instrumentingAgents->inspectorDOMDebuggerAgent());
+}
+
+// Browser debugger agent enabled only when JS debugger is enabled.
+void InspectorDOMDebuggerAgent::debuggerWasEnabled()
+{
+ m_instrumentingAgents->setInspectorDOMDebuggerAgent(this);
+}
+
+void InspectorDOMDebuggerAgent::debuggerWasDisabled()
+{
+ disable();
+}
+
+void InspectorDOMDebuggerAgent::stepInto()
+{
+ m_pauseInNextEventListener = true;
+}
+
+void InspectorDOMDebuggerAgent::didPause()
+{
+ m_pauseInNextEventListener = false;
+}
+
+void InspectorDOMDebuggerAgent::didProcessTask()
+{
+ if (!m_pauseInNextEventListener)
+ return;
+ if (m_debuggerAgent && m_debuggerAgent->runningNestedMessageLoop())
+ return;
+ m_pauseInNextEventListener = false;
+}
+
+void InspectorDOMDebuggerAgent::disable()
+{
+ m_instrumentingAgents->setInspectorDOMDebuggerAgent(0);
+ clear();
+}
+
+void InspectorDOMDebuggerAgent::clearFrontend()
+{
+ disable();
+}
+
+void InspectorDOMDebuggerAgent::discardAgent()
+{
+ m_debuggerAgent->setListener(0);
+ m_debuggerAgent = 0;
+}
+
+void InspectorDOMDebuggerAgent::discardBindings()
+{
+ m_domBreakpoints.clear();
+}
+
+void InspectorDOMDebuggerAgent::setEventListenerBreakpoint(ErrorString* error, const String& eventName)
+{
+ setBreakpoint(error, String(listenerEventCategoryType) + eventName);
+}
+
+void InspectorDOMDebuggerAgent::setInstrumentationBreakpoint(ErrorString* error, const String& eventName)
+{
+ setBreakpoint(error, String(instrumentationEventCategoryType) + eventName);
+}
+
+void InspectorDOMDebuggerAgent::setBreakpoint(ErrorString* error, const String& eventName)
+{
+ if (eventName.isEmpty()) {
+ *error = "Event name is empty";
+ return;
+ }
+
+ RefPtr<InspectorObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
+ eventListenerBreakpoints->setBoolean(eventName, true);
+ m_state->setObject(DOMDebuggerAgentState::eventListenerBreakpoints, eventListenerBreakpoints);
+}
+
+void InspectorDOMDebuggerAgent::removeEventListenerBreakpoint(ErrorString* error, const String& eventName)
+{
+ removeBreakpoint(error, String(listenerEventCategoryType) + eventName);
+}
+
+void InspectorDOMDebuggerAgent::removeInstrumentationBreakpoint(ErrorString* error, const String& eventName)
+{
+ removeBreakpoint(error, String(instrumentationEventCategoryType) + eventName);
+}
+
+void InspectorDOMDebuggerAgent::removeBreakpoint(ErrorString* error, const String& eventName)
+{
+ if (eventName.isEmpty()) {
+ *error = "Event name is empty";
+ return;
+ }
+
+ RefPtr<InspectorObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
+ eventListenerBreakpoints->remove(eventName);
+ m_state->setObject(DOMDebuggerAgentState::eventListenerBreakpoints, eventListenerBreakpoints);
+}
+
+void InspectorDOMDebuggerAgent::didInvalidateStyleAttr(Node* node)
+{
+ if (hasBreakpoint(node, AttributeModified)) {
+ RefPtr<InspectorObject> eventData = InspectorObject::create();
+ descriptionForDOMEvent(node, AttributeModified, false, eventData.get());
+ m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
+ }
+}
+
+void InspectorDOMDebuggerAgent::didInsertDOMNode(Node* node)
+{
+ if (m_domBreakpoints.size()) {
+ uint32_t mask = m_domBreakpoints.get(InspectorDOMAgent::innerParentNode(node));
+ uint32_t inheritableTypesMask = (mask | (mask >> domBreakpointDerivedTypeShift)) & inheritableDOMBreakpointTypesMask;
+ if (inheritableTypesMask)
+ updateSubtreeBreakpoints(node, inheritableTypesMask, true);
+ }
+}
+
+void InspectorDOMDebuggerAgent::didRemoveDOMNode(Node* node)
+{
+ if (m_domBreakpoints.size()) {
+ // Remove subtree breakpoints.
+ m_domBreakpoints.remove(node);
+ Vector<Node*> stack(1, InspectorDOMAgent::innerFirstChild(node));
+ do {
+ Node* node = stack.last();
+ stack.removeLast();
+ if (!node)
+ continue;
+ m_domBreakpoints.remove(node);
+ stack.append(InspectorDOMAgent::innerFirstChild(node));
+ stack.append(InspectorDOMAgent::innerNextSibling(node));
+ } while (!stack.isEmpty());
+ }
+}
+
+static int domTypeForName(ErrorString* errorString, const String& typeString)
+{
+ if (typeString == "subtree-modified")
+ return SubtreeModified;
+ if (typeString == "attribute-modified")
+ return AttributeModified;
+ if (typeString == "node-removed")
+ return NodeRemoved;
+ *errorString = makeString("Unknown DOM breakpoint type: ", typeString);
+ return -1;
+}
+
+static String domTypeName(int type)
+{
+ switch (type) {
+ case SubtreeModified: return "subtree-modified";
+ case AttributeModified: return "attribute-modified";
+ case NodeRemoved: return "node-removed";
+ default: break;
+ }
+ return "";
+}
+
+void InspectorDOMDebuggerAgent::setDOMBreakpoint(ErrorString* errorString, int nodeId, const String& typeString)
+{
+ Node* node = m_domAgent->assertNode(errorString, nodeId);
+ if (!node)
+ return;
+
+ int type = domTypeForName(errorString, typeString);
+ if (type == -1)
+ return;
+
+ uint32_t rootBit = 1 << type;
+ m_domBreakpoints.set(node, m_domBreakpoints.get(node) | rootBit);
+ if (rootBit & inheritableDOMBreakpointTypesMask) {
+ for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
+ updateSubtreeBreakpoints(child, rootBit, true);
+ }
+}
+
+void InspectorDOMDebuggerAgent::removeDOMBreakpoint(ErrorString* errorString, int nodeId, const String& typeString)
+{
+ Node* node = m_domAgent->assertNode(errorString, nodeId);
+ if (!node)
+ return;
+ int type = domTypeForName(errorString, typeString);
+ if (type == -1)
+ return;
+
+ uint32_t rootBit = 1 << type;
+ uint32_t mask = m_domBreakpoints.get(node) & ~rootBit;
+ if (mask)
+ m_domBreakpoints.set(node, mask);
+ else
+ m_domBreakpoints.remove(node);
+
+ if ((rootBit & inheritableDOMBreakpointTypesMask) && !(mask & (rootBit << domBreakpointDerivedTypeShift))) {
+ for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
+ updateSubtreeBreakpoints(child, rootBit, false);
+ }
+}
+
+void InspectorDOMDebuggerAgent::willInsertDOMNode(Node* parent)
+{
+ if (hasBreakpoint(parent, SubtreeModified)) {
+ RefPtr<InspectorObject> eventData = InspectorObject::create();
+ descriptionForDOMEvent(parent, SubtreeModified, true, eventData.get());
+ m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
+ }
+}
+
+void InspectorDOMDebuggerAgent::willRemoveDOMNode(Node* node)
+{
+ Node* parentNode = InspectorDOMAgent::innerParentNode(node);
+ if (hasBreakpoint(node, NodeRemoved)) {
+ RefPtr<InspectorObject> eventData = InspectorObject::create();
+ descriptionForDOMEvent(node, NodeRemoved, false, eventData.get());
+ m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
+ } else if (parentNode && hasBreakpoint(parentNode, SubtreeModified)) {
+ RefPtr<InspectorObject> eventData = InspectorObject::create();
+ descriptionForDOMEvent(node, SubtreeModified, false, eventData.get());
+ m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
+ }
+}
+
+void InspectorDOMDebuggerAgent::willModifyDOMAttr(Element* element, const AtomicString&, const AtomicString&)
+{
+ if (hasBreakpoint(element, AttributeModified)) {
+ RefPtr<InspectorObject> eventData = InspectorObject::create();
+ descriptionForDOMEvent(element, AttributeModified, false, eventData.get());
+ m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
+ }
+}
+
+void InspectorDOMDebuggerAgent::descriptionForDOMEvent(Node* target, int breakpointType, bool insertion, InspectorObject* description)
+{
+ ASSERT(hasBreakpoint(target, breakpointType));
+
+ Node* breakpointOwner = target;
+ if ((1 << breakpointType) & inheritableDOMBreakpointTypesMask) {
+ // For inheritable breakpoint types, target node isn't always the same as the node that owns a breakpoint.
+ // Target node may be unknown to frontend, so we need to push it first.
+ RefPtr<TypeBuilder::Runtime::RemoteObject> targetNodeObject = m_domAgent->resolveNode(target, InspectorDebuggerAgent::backtraceObjectGroup);
+ description->setValue("targetNode", targetNodeObject);
+
+ // Find breakpoint owner node.
+ if (!insertion)
+ breakpointOwner = InspectorDOMAgent::innerParentNode(target);
+ ASSERT(breakpointOwner);
+ while (!(m_domBreakpoints.get(breakpointOwner) & (1 << breakpointType))) {
+ Node* parentNode = InspectorDOMAgent::innerParentNode(breakpointOwner);
+ if (!parentNode)
+ break;
+ breakpointOwner = parentNode;
+ }
+
+ if (breakpointType == SubtreeModified)
+ description->setBoolean("insertion", insertion);
+ }
+
+ int breakpointOwnerNodeId = m_domAgent->boundNodeId(breakpointOwner);
+ ASSERT(breakpointOwnerNodeId);
+ description->setNumber("nodeId", breakpointOwnerNodeId);
+ description->setString("type", domTypeName(breakpointType));
+}
+
+bool InspectorDOMDebuggerAgent::hasBreakpoint(Node* node, int type)
+{
+ uint32_t rootBit = 1 << type;
+ uint32_t derivedBit = rootBit << domBreakpointDerivedTypeShift;
+ return m_domBreakpoints.get(node) & (rootBit | derivedBit);
+}
+
+void InspectorDOMDebuggerAgent::updateSubtreeBreakpoints(Node* node, uint32_t rootMask, bool set)
+{
+ uint32_t oldMask = m_domBreakpoints.get(node);
+ uint32_t derivedMask = rootMask << domBreakpointDerivedTypeShift;
+ uint32_t newMask = set ? oldMask | derivedMask : oldMask & ~derivedMask;
+ if (newMask)
+ m_domBreakpoints.set(node, newMask);
+ else
+ m_domBreakpoints.remove(node);
+
+ uint32_t newRootMask = rootMask & ~newMask;
+ if (!newRootMask)
+ return;
+
+ for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
+ updateSubtreeBreakpoints(child, newRootMask, set);
+}
+
+void InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded(bool isDOMEvent, const String& eventName, bool synchronous)
+{
+ String fullEventName = (isDOMEvent ? listenerEventCategoryType : instrumentationEventCategoryType) + eventName;
+ if (m_pauseInNextEventListener)
+ m_pauseInNextEventListener = false;
+ else {
+ RefPtr<InspectorObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
+ if (eventListenerBreakpoints->find(fullEventName) == eventListenerBreakpoints->end())
+ return;
+ }
+
+ RefPtr<InspectorObject> eventData = InspectorObject::create();
+ eventData->setString("eventName", fullEventName);
+ if (synchronous)
+ m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::EventListener, eventData.release());
+ else
+ m_debuggerAgent->schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::EventListener, eventData.release());
+}
+
+void InspectorDOMDebuggerAgent::setXHRBreakpoint(ErrorString*, const String& url)
+{
+ if (url.isEmpty()) {
+ m_state->setBoolean(DOMDebuggerAgentState::pauseOnAllXHRs, true);
+ return;
+ }
+
+ RefPtr<InspectorObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
+ xhrBreakpoints->setBoolean(url, true);
+ m_state->setObject(DOMDebuggerAgentState::xhrBreakpoints, xhrBreakpoints);
+}
+
+void InspectorDOMDebuggerAgent::removeXHRBreakpoint(ErrorString*, const String& url)
+{
+ if (url.isEmpty()) {
+ m_state->setBoolean(DOMDebuggerAgentState::pauseOnAllXHRs, false);
+ return;
+ }
+
+ RefPtr<InspectorObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
+ xhrBreakpoints->remove(url);
+ m_state->setObject(DOMDebuggerAgentState::xhrBreakpoints, xhrBreakpoints);
+}
+
+void InspectorDOMDebuggerAgent::willSendXMLHttpRequest(const String& url)
+{
+ String breakpointURL;
+ if (m_state->getBoolean(DOMDebuggerAgentState::pauseOnAllXHRs))
+ breakpointURL = "";
+ else {
+ RefPtr<InspectorObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
+ for (InspectorObject::iterator it = xhrBreakpoints->begin(); it != xhrBreakpoints->end(); ++it) {
+ if (url.contains(it->key)) {
+ breakpointURL = it->key;
+ break;
+ }
+ }
+ }
+
+ if (breakpointURL.isNull())
+ return;
+
+ RefPtr<InspectorObject> eventData = InspectorObject::create();
+ eventData->setString("breakpointURL", breakpointURL);
+ eventData->setString("url", url);
+ m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::XHR, eventData.release());
+}
+
+void InspectorDOMDebuggerAgent::clear()
+{
+ m_domBreakpoints.clear();
+ m_pauseInNextEventListener = false;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorDOMDebuggerAgent.h b/Source/core/inspector/InspectorDOMDebuggerAgent.h
new file mode 100644
index 0000000..a5fb24a
--- /dev/null
+++ b/Source/core/inspector/InspectorDOMDebuggerAgent.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorDOMDebuggerAgent_h
+#define InspectorDOMDebuggerAgent_h
+
+
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/inspector/InspectorDebuggerAgent.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Element;
+class InspectorAgent;
+class InspectorDOMAgent;
+class InspectorDebuggerAgent;
+class InspectorFrontend;
+class InspectorObject;
+class InspectorState;
+class InstrumentingAgents;
+class Node;
+
+typedef String ErrorString;
+
+class InspectorDOMDebuggerAgent : public InspectorBaseAgent<InspectorDOMDebuggerAgent>, public InspectorDebuggerAgent::Listener, public InspectorBackendDispatcher::DOMDebuggerCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorDOMDebuggerAgent);
+public:
+ static PassOwnPtr<InspectorDOMDebuggerAgent> create(InstrumentingAgents*, InspectorCompositeState*, InspectorDOMAgent*, InspectorDebuggerAgent*, InspectorAgent*);
+
+ virtual ~InspectorDOMDebuggerAgent();
+
+ // DOMDebugger API for InspectorFrontend
+ virtual void setXHRBreakpoint(ErrorString*, const String& url);
+ virtual void removeXHRBreakpoint(ErrorString*, const String& url);
+ virtual void setEventListenerBreakpoint(ErrorString*, const String& eventName);
+ virtual void removeEventListenerBreakpoint(ErrorString*, const String& eventName);
+ virtual void setInstrumentationBreakpoint(ErrorString*, const String& eventName);
+ virtual void removeInstrumentationBreakpoint(ErrorString*, const String& eventName);
+ virtual void setDOMBreakpoint(ErrorString*, int nodeId, const String& type);
+ virtual void removeDOMBreakpoint(ErrorString*, int nodeId, const String& type);
+
+ // InspectorInstrumentation API
+ void willInsertDOMNode(Node* parent);
+ void didInvalidateStyleAttr(Node*);
+ void didInsertDOMNode(Node*);
+ void willRemoveDOMNode(Node*);
+ void didRemoveDOMNode(Node*);
+ void willModifyDOMAttr(Element*, const AtomicString&, const AtomicString&);
+ void willSendXMLHttpRequest(const String& url);
+ void pauseOnNativeEventIfNeeded(bool isDOMEvent, const String& eventName, bool synchronous);
+
+ void didProcessTask();
+
+ virtual void clearFrontend();
+ virtual void discardAgent();
+
+private:
+ InspectorDOMDebuggerAgent(InstrumentingAgents*, InspectorCompositeState*, InspectorDOMAgent*, InspectorDebuggerAgent*, InspectorAgent*);
+
+ // InspectorDebuggerAgent::Listener implementation.
+ virtual void debuggerWasEnabled();
+ virtual void debuggerWasDisabled();
+ virtual void stepInto();
+ virtual void didPause();
+ void disable();
+
+ void descriptionForDOMEvent(Node* target, int breakpointType, bool insertion, InspectorObject* description);
+ void updateSubtreeBreakpoints(Node*, uint32_t rootMask, bool set);
+ bool hasBreakpoint(Node*, int type);
+ void discardBindings();
+ void setBreakpoint(ErrorString*, const String& eventName);
+ void removeBreakpoint(ErrorString*, const String& eventName);
+
+ void clear();
+
+ InspectorDOMAgent* m_domAgent;
+ InspectorDebuggerAgent* m_debuggerAgent;
+ HashMap<Node*, uint32_t> m_domBreakpoints;
+ bool m_pauseInNextEventListener;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorDOMDebuggerAgent_h)
diff --git a/Source/core/inspector/InspectorDOMStorageAgent.cpp b/Source/core/inspector/InspectorDOMStorageAgent.cpp
new file mode 100644
index 0000000..39ee87a
--- /dev/null
+++ b/Source/core/inspector/InspectorDOMStorageAgent.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2013 Samsung Electronics. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InspectorDOMStorageAgent.h"
+
+#include "ExceptionCodeDescription.h"
+#include "InspectorFrontend.h"
+#include "core/dom/Document.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include "core/html/VoidCallback.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/page/PageGroup.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/storage/Storage.h"
+#include "core/storage/StorageArea.h"
+#include "core/storage/StorageNamespace.h"
+#include "modules/webdatabase/Database.h"
+
+#include <wtf/MemoryInstrumentationHashMap.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+namespace DOMStorageAgentState {
+static const char domStorageAgentEnabled[] = "domStorageAgentEnabled";
+};
+
+static bool hadException(ExceptionCode ec, ErrorString* errorString)
+{
+ switch (ec) {
+ case 0:
+ return false;
+ case SECURITY_ERR:
+ *errorString = "Security error";
+ return true;
+ default:
+ *errorString = "Unknown DOM storage error";
+ return true;
+ }
+}
+
+InspectorDOMStorageAgent::InspectorDOMStorageAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* state)
+ : InspectorBaseAgent<InspectorDOMStorageAgent>("DOMStorage", instrumentingAgents, state)
+ , m_pageAgent(pageAgent)
+ , m_frontend(0)
+{
+ m_instrumentingAgents->setInspectorDOMStorageAgent(this);
+}
+
+InspectorDOMStorageAgent::~InspectorDOMStorageAgent()
+{
+ m_instrumentingAgents->setInspectorDOMStorageAgent(0);
+ m_instrumentingAgents = 0;
+}
+
+void InspectorDOMStorageAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend;
+}
+
+void InspectorDOMStorageAgent::clearFrontend()
+{
+ m_frontend = 0;
+ disable(0);
+}
+
+bool InspectorDOMStorageAgent::isEnabled() const
+{
+ return m_state->getBoolean(DOMStorageAgentState::domStorageAgentEnabled);
+}
+
+void InspectorDOMStorageAgent::enable(ErrorString*)
+{
+ m_state->setBoolean(DOMStorageAgentState::domStorageAgentEnabled, true);
+}
+
+void InspectorDOMStorageAgent::disable(ErrorString*)
+{
+ m_state->setBoolean(DOMStorageAgentState::domStorageAgentEnabled, false);
+}
+
+void InspectorDOMStorageAgent::getDOMStorageItems(ErrorString* errorString, const RefPtr<InspectorObject>& storageId, RefPtr<TypeBuilder::Array<TypeBuilder::Array<String> > >& items)
+{
+ Frame* frame;
+ RefPtr<StorageArea> storageArea = findStorageArea(errorString, storageId, frame);
+ if (!storageArea)
+ return;
+
+ RefPtr<TypeBuilder::Array<TypeBuilder::Array<String> > > storageItems = TypeBuilder::Array<TypeBuilder::Array<String> >::create();
+
+ ExceptionCode ec = 0;
+ for (unsigned i = 0; i < storageArea->length(ec, frame); ++i) {
+ String name(storageArea->key(i, ec, frame));
+ if (hadException(ec, errorString))
+ return;
+ String value(storageArea->getItem(name, ec, frame));
+ if (hadException(ec, errorString))
+ return;
+ RefPtr<TypeBuilder::Array<String> > entry = TypeBuilder::Array<String>::create();
+ entry->addItem(name);
+ entry->addItem(value);
+ storageItems->addItem(entry);
+ }
+ items = storageItems.release();
+}
+
+static String toErrorString(const ExceptionCode& ec)
+{
+ if (ec) {
+ ExceptionCodeDescription description(ec);
+ return description.name;
+ }
+ return "";
+}
+
+void InspectorDOMStorageAgent::setDOMStorageItem(ErrorString* errorString, const RefPtr<InspectorObject>& storageId, const String& key, const String& value)
+{
+ Frame* frame;
+ RefPtr<StorageArea> storageArea = findStorageArea(0, storageId, frame);
+ if (!storageArea) {
+ *errorString = "Storage not found";
+ return;
+ }
+
+ ExceptionCode exception = 0;
+ storageArea->setItem(key, value, exception, frame);
+ *errorString = toErrorString(exception);
+}
+
+void InspectorDOMStorageAgent::removeDOMStorageItem(ErrorString* errorString, const RefPtr<InspectorObject>& storageId, const String& key)
+{
+ Frame* frame;
+ RefPtr<StorageArea> storageArea = findStorageArea(0, storageId, frame);
+ if (!storageArea) {
+ *errorString = "Storage not found";
+ return;
+ }
+
+ ExceptionCode exception = 0;
+ storageArea->removeItem(key, exception, frame);
+ *errorString = toErrorString(exception);
+}
+
+String InspectorDOMStorageAgent::storageId(Storage* storage)
+{
+ ASSERT(storage);
+ Document* document = storage->frame()->document();
+ ASSERT(document);
+ DOMWindow* window = document->domWindow();
+ ASSERT(window);
+ RefPtr<SecurityOrigin> securityOrigin = document->securityOrigin();
+ bool isLocalStorage = window->optionalLocalStorage() == storage;
+ return storageId(securityOrigin.get(), isLocalStorage)->toJSONString();
+}
+
+PassRefPtr<TypeBuilder::DOMStorage::StorageId> InspectorDOMStorageAgent::storageId(SecurityOrigin* securityOrigin, bool isLocalStorage)
+{
+ return TypeBuilder::DOMStorage::StorageId::create()
+ .setSecurityOrigin(securityOrigin->toRawString())
+ .setIsLocalStorage(isLocalStorage).release();
+}
+
+void InspectorDOMStorageAgent::didDispatchDOMStorageEvent(const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin, Page*)
+{
+ if (!m_frontend || !isEnabled())
+ return;
+
+ RefPtr<TypeBuilder::DOMStorage::StorageId> id = storageId(securityOrigin, storageType == LocalStorage);
+
+ if (key.isNull())
+ m_frontend->domstorage()->domStorageItemsCleared(id);
+ else if (newValue.isNull())
+ m_frontend->domstorage()->domStorageItemRemoved(id, key);
+ else if (oldValue.isNull())
+ m_frontend->domstorage()->domStorageItemAdded(id, key, newValue);
+ else
+ m_frontend->domstorage()->domStorageItemUpdated(id, key, oldValue, newValue);
+}
+
+PassRefPtr<StorageArea> InspectorDOMStorageAgent::findStorageArea(ErrorString* errorString, const RefPtr<InspectorObject>& storageId, Frame*& targetFrame)
+{
+ String securityOrigin;
+ bool isLocalStorage = false;
+ bool success = storageId->getString("securityOrigin", &securityOrigin);
+ if (success)
+ success = storageId->getBoolean("isLocalStorage", &isLocalStorage);
+ if (!success) {
+ if (errorString)
+ *errorString = "Invalid storageId format";
+ return 0;
+ }
+
+ Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
+ if (!frame) {
+ if (errorString)
+ *errorString = "Frame not found for the given security origin";
+ return 0;
+ }
+ targetFrame = frame;
+
+ Page* page = m_pageAgent->page();
+ if (isLocalStorage)
+ return page->group().localStorage()->storageArea(frame->document()->securityOrigin());
+ return page->sessionStorage()->storageArea(frame->document()->securityOrigin());
+}
+
+void InspectorDOMStorageAgent::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorDOMStorageAgent);
+ InspectorBaseAgent<InspectorDOMStorageAgent>::reportMemoryUsage(memoryObjectInfo);
+ info.addWeakPointer(m_frontend);
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorDOMStorageAgent.h b/Source/core/inspector/InspectorDOMStorageAgent.h
new file mode 100644
index 0000000..960f14b
--- /dev/null
+++ b/Source/core/inspector/InspectorDOMStorageAgent.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorDOMStorageAgent_h
+#define InspectorDOMStorageAgent_h
+
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/storage/StorageArea.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Frame;
+class InspectorArray;
+class InspectorFrontend;
+class InspectorPageAgent;
+class InspectorState;
+class InstrumentingAgents;
+class Page;
+class Storage;
+class StorageArea;
+
+typedef String ErrorString;
+
+class InspectorDOMStorageAgent : public InspectorBaseAgent<InspectorDOMStorageAgent>, public InspectorBackendDispatcher::DOMStorageCommandHandler {
+public:
+ static PassOwnPtr<InspectorDOMStorageAgent> create(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* state)
+ {
+ return adoptPtr(new InspectorDOMStorageAgent(instrumentingAgents, pageAgent, state));
+ }
+ ~InspectorDOMStorageAgent();
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+
+ // Called from the front-end.
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void getDOMStorageItems(ErrorString*, const RefPtr<InspectorObject>& storageId, RefPtr<TypeBuilder::Array<TypeBuilder::Array<String> > >& items);
+ virtual void setDOMStorageItem(ErrorString*, const RefPtr<InspectorObject>& storageId, const String& key, const String& value);
+ virtual void removeDOMStorageItem(ErrorString*, const RefPtr<InspectorObject>& storageId, const String& key);
+
+ // Called from the injected script.
+ String storageId(Storage*);
+ PassRefPtr<TypeBuilder::DOMStorage::StorageId> storageId(SecurityOrigin*, bool isLocalStorage);
+
+ // Called from InspectorInstrumentation
+ void didDispatchDOMStorageEvent(const String& key, const String& oldValue, const String& newValue, StorageType, SecurityOrigin*, Page*);
+
+ virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+
+private:
+
+ InspectorDOMStorageAgent(InstrumentingAgents*, InspectorPageAgent*, InspectorCompositeState*);
+
+ bool isEnabled() const;
+ PassRefPtr<StorageArea> findStorageArea(ErrorString*, const RefPtr<InspectorObject>&, Frame*&);
+
+ InspectorPageAgent* m_pageAgent;
+ InspectorFrontend* m_frontend;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorDOMStorageAgent_h)
diff --git a/Source/core/inspector/InspectorDatabaseAgent.cpp b/Source/core/inspector/InspectorDatabaseAgent.cpp
new file mode 100644
index 0000000..df96e12
--- /dev/null
+++ b/Source/core/inspector/InspectorDatabaseAgent.cpp
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2010 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InspectorDatabaseAgent.h"
+
+#include "InspectorFrontend.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/html/VoidCallback.h"
+#include "core/inspector/InspectorDatabaseResource.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/platform/sql/SQLValue.h"
+#include "modules/webdatabase/Database.h"
+#include "modules/webdatabase/SQLError.h"
+#include "modules/webdatabase/SQLResultSet.h"
+#include "modules/webdatabase/SQLResultSetRowList.h"
+#include "modules/webdatabase/SQLStatementCallback.h"
+#include "modules/webdatabase/SQLStatementErrorCallback.h"
+#include "modules/webdatabase/SQLTransaction.h"
+#include "modules/webdatabase/SQLTransactionCallback.h"
+#include "modules/webdatabase/SQLTransactionErrorCallback.h"
+
+#include <wtf/Vector.h>
+
+typedef WebCore::InspectorBackendDispatcher::DatabaseCommandHandler::ExecuteSQLCallback ExecuteSQLCallback;
+
+namespace WebCore {
+
+namespace DatabaseAgentState {
+static const char databaseAgentEnabled[] = "databaseAgentEnabled";
+};
+
+namespace {
+
+void reportTransactionFailed(ExecuteSQLCallback* requestCallback, SQLError* error)
+{
+ RefPtr<TypeBuilder::Database::Error> errorObject = TypeBuilder::Database::Error::create()
+ .setMessage(error->message())
+ .setCode(error->code());
+ requestCallback->sendSuccess(0, 0, errorObject.release());
+}
+
+class StatementCallback : public SQLStatementCallback {
+public:
+ static PassRefPtr<StatementCallback> create(PassRefPtr<ExecuteSQLCallback> requestCallback)
+ {
+ return adoptRef(new StatementCallback(requestCallback));
+ }
+
+ virtual ~StatementCallback() { }
+
+ virtual bool handleEvent(SQLTransaction*, SQLResultSet* resultSet)
+ {
+ SQLResultSetRowList* rowList = resultSet->rows();
+
+ RefPtr<TypeBuilder::Array<String> > columnNames = TypeBuilder::Array<String>::create();
+ const Vector<String>& columns = rowList->columnNames();
+ for (size_t i = 0; i < columns.size(); ++i)
+ columnNames->addItem(columns[i]);
+
+ RefPtr<TypeBuilder::Array<InspectorValue> > values = TypeBuilder::Array<InspectorValue>::create();
+ const Vector<SQLValue>& data = rowList->values();
+ for (size_t i = 0; i < data.size(); ++i) {
+ const SQLValue& value = rowList->values()[i];
+ switch (value.type()) {
+ case SQLValue::StringValue: values->addItem(InspectorString::create(value.string())); break;
+ case SQLValue::NumberValue: values->addItem(InspectorBasicValue::create(value.number())); break;
+ case SQLValue::NullValue: values->addItem(InspectorValue::null()); break;
+ }
+ }
+ m_requestCallback->sendSuccess(columnNames.release(), values.release(), 0);
+ return true;
+ }
+
+private:
+ StatementCallback(PassRefPtr<ExecuteSQLCallback> requestCallback)
+ : m_requestCallback(requestCallback) { }
+ RefPtr<ExecuteSQLCallback> m_requestCallback;
+};
+
+class StatementErrorCallback : public SQLStatementErrorCallback {
+public:
+ static PassRefPtr<StatementErrorCallback> create(PassRefPtr<ExecuteSQLCallback> requestCallback)
+ {
+ return adoptRef(new StatementErrorCallback(requestCallback));
+ }
+
+ virtual ~StatementErrorCallback() { }
+
+ virtual bool handleEvent(SQLTransaction*, SQLError* error)
+ {
+ reportTransactionFailed(m_requestCallback.get(), error);
+ return true;
+ }
+
+private:
+ StatementErrorCallback(PassRefPtr<ExecuteSQLCallback> requestCallback)
+ : m_requestCallback(requestCallback) { }
+ RefPtr<ExecuteSQLCallback> m_requestCallback;
+};
+
+class TransactionCallback : public SQLTransactionCallback {
+public:
+ static PassRefPtr<TransactionCallback> create(const String& sqlStatement, PassRefPtr<ExecuteSQLCallback> requestCallback)
+ {
+ return adoptRef(new TransactionCallback(sqlStatement, requestCallback));
+ }
+
+ virtual ~TransactionCallback() { }
+
+ virtual bool handleEvent(SQLTransaction* transaction)
+ {
+ if (!m_requestCallback->isActive())
+ return true;
+
+ Vector<SQLValue> sqlValues;
+ RefPtr<SQLStatementCallback> callback(StatementCallback::create(m_requestCallback.get()));
+ RefPtr<SQLStatementErrorCallback> errorCallback(StatementErrorCallback::create(m_requestCallback.get()));
+ transaction->executeSQL(m_sqlStatement, sqlValues, callback.release(), errorCallback.release(), IGNORE_EXCEPTION);
+ return true;
+ }
+private:
+ TransactionCallback(const String& sqlStatement, PassRefPtr<ExecuteSQLCallback> requestCallback)
+ : m_sqlStatement(sqlStatement)
+ , m_requestCallback(requestCallback) { }
+ String m_sqlStatement;
+ RefPtr<ExecuteSQLCallback> m_requestCallback;
+};
+
+class TransactionErrorCallback : public SQLTransactionErrorCallback {
+public:
+ static PassRefPtr<TransactionErrorCallback> create(PassRefPtr<ExecuteSQLCallback> requestCallback)
+ {
+ return adoptRef(new TransactionErrorCallback(requestCallback));
+ }
+
+ virtual ~TransactionErrorCallback() { }
+
+ virtual bool handleEvent(SQLError* error)
+ {
+ reportTransactionFailed(m_requestCallback.get(), error);
+ return true;
+ }
+private:
+ TransactionErrorCallback(PassRefPtr<ExecuteSQLCallback> requestCallback)
+ : m_requestCallback(requestCallback) { }
+ RefPtr<ExecuteSQLCallback> m_requestCallback;
+};
+
+class TransactionSuccessCallback : public VoidCallback {
+public:
+ static PassRefPtr<TransactionSuccessCallback> create()
+ {
+ return adoptRef(new TransactionSuccessCallback());
+ }
+
+ virtual ~TransactionSuccessCallback() { }
+
+ virtual bool handleEvent() { return false; }
+
+private:
+ TransactionSuccessCallback() { }
+};
+
+} // namespace
+
+void InspectorDatabaseAgent::didOpenDatabase(PassRefPtr<Database> database, const String& domain, const String& name, const String& version)
+{
+ if (InspectorDatabaseResource* resource = findByFileName(database->fileName())) {
+ resource->setDatabase(database);
+ return;
+ }
+
+ RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
+ m_resources.set(resource->id(), resource);
+ // Resources are only bound while visible.
+ if (m_frontend && m_enabled)
+ resource->bind(m_frontend);
+}
+
+void InspectorDatabaseAgent::clearResources()
+{
+ m_resources.clear();
+}
+
+InspectorDatabaseAgent::InspectorDatabaseAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state)
+ : InspectorBaseAgent<InspectorDatabaseAgent>("Database", instrumentingAgents, state)
+ , m_enabled(false)
+{
+ m_instrumentingAgents->setInspectorDatabaseAgent(this);
+}
+
+InspectorDatabaseAgent::~InspectorDatabaseAgent()
+{
+ m_instrumentingAgents->setInspectorDatabaseAgent(0);
+}
+
+void InspectorDatabaseAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->database();
+}
+
+void InspectorDatabaseAgent::clearFrontend()
+{
+ m_frontend = 0;
+ disable(0);
+}
+
+void InspectorDatabaseAgent::enable(ErrorString*)
+{
+ if (m_enabled)
+ return;
+ m_enabled = true;
+ m_state->setBoolean(DatabaseAgentState::databaseAgentEnabled, m_enabled);
+
+ DatabaseResourcesMap::iterator databasesEnd = m_resources.end();
+ for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != databasesEnd; ++it)
+ it->value->bind(m_frontend);
+}
+
+void InspectorDatabaseAgent::disable(ErrorString*)
+{
+ if (!m_enabled)
+ return;
+ m_enabled = false;
+ m_state->setBoolean(DatabaseAgentState::databaseAgentEnabled, m_enabled);
+}
+
+void InspectorDatabaseAgent::restore()
+{
+ m_enabled = m_state->getBoolean(DatabaseAgentState::databaseAgentEnabled);
+}
+
+void InspectorDatabaseAgent::getDatabaseTableNames(ErrorString* error, const String& databaseId, RefPtr<TypeBuilder::Array<String> >& names)
+{
+ if (!m_enabled) {
+ *error = "Database agent is not enabled";
+ return;
+ }
+
+ names = TypeBuilder::Array<String>::create();
+
+ Database* database = databaseForId(databaseId);
+ if (database) {
+ Vector<String> tableNames = database->tableNames();
+ unsigned length = tableNames.size();
+ for (unsigned i = 0; i < length; ++i)
+ names->addItem(tableNames[i]);
+ }
+}
+
+void InspectorDatabaseAgent::executeSQL(ErrorString*, const String& databaseId, const String& query, PassRefPtr<ExecuteSQLCallback> prpRequestCallback)
+{
+ RefPtr<ExecuteSQLCallback> requestCallback = prpRequestCallback;
+
+ if (!m_enabled) {
+ requestCallback->sendFailure("Database agent is not enabled");
+ return;
+ }
+
+ Database* database = databaseForId(databaseId);
+ if (!database) {
+ requestCallback->sendFailure("Database not found");
+ return;
+ }
+
+ RefPtr<SQLTransactionCallback> callback(TransactionCallback::create(query, requestCallback.get()));
+ RefPtr<SQLTransactionErrorCallback> errorCallback(TransactionErrorCallback::create(requestCallback.get()));
+ RefPtr<VoidCallback> successCallback(TransactionSuccessCallback::create());
+ database->transaction(callback.release(), errorCallback.release(), successCallback.release());
+}
+
+String InspectorDatabaseAgent::databaseId(Database* database)
+{
+ for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
+ if (it->value->database() == database)
+ return it->key;
+ }
+ return String();
+}
+
+InspectorDatabaseResource* InspectorDatabaseAgent::findByFileName(const String& fileName)
+{
+ for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
+ if (it->value->database()->fileName() == fileName)
+ return it->value.get();
+ }
+ return 0;
+}
+
+Database* InspectorDatabaseAgent::databaseForId(const String& databaseId)
+{
+ DatabaseResourcesMap::iterator it = m_resources.find(databaseId);
+ if (it == m_resources.end())
+ return 0;
+ return it->value->database();
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InspectorDatabaseAgent.h b/Source/core/inspector/InspectorDatabaseAgent.h
new file mode 100644
index 0000000..7de93a1
--- /dev/null
+++ b/Source/core/inspector/InspectorDatabaseAgent.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorDatabaseAgent_h
+#define InspectorDatabaseAgent_h
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Database;
+class InspectorArray;
+class InspectorDatabaseResource;
+class InspectorFrontend;
+class InspectorState;
+class InstrumentingAgents;
+
+typedef String ErrorString;
+
+class InspectorDatabaseAgent : public InspectorBaseAgent<InspectorDatabaseAgent>, public InspectorBackendDispatcher::DatabaseCommandHandler {
+public:
+ static PassOwnPtr<InspectorDatabaseAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state)
+ {
+ return adoptPtr(new InspectorDatabaseAgent(instrumentingAgents, state));
+ }
+ ~InspectorDatabaseAgent();
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ void clearResources();
+
+ // Called from the front-end.
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void getDatabaseTableNames(ErrorString*, const String& databaseId, RefPtr<TypeBuilder::Array<String> >& names);
+ virtual void executeSQL(ErrorString*, const String& databaseId, const String& query, PassRefPtr<ExecuteSQLCallback>);
+
+ // Called from the injected script.
+ String databaseId(Database*);
+
+ void didOpenDatabase(PassRefPtr<Database>, const String& domain, const String& name, const String& version);
+private:
+ explicit InspectorDatabaseAgent(InstrumentingAgents*, InspectorCompositeState*);
+
+ Database* databaseForId(const String& databaseId);
+ InspectorDatabaseResource* findByFileName(const String& fileName);
+
+ InspectorFrontend::Database* m_frontend;
+ typedef HashMap<String, RefPtr<InspectorDatabaseResource> > DatabaseResourcesMap;
+ DatabaseResourcesMap m_resources;
+ bool m_enabled;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorDatabaseAgent_h)
diff --git a/Source/core/inspector/InspectorDatabaseInstrumentation.h b/Source/core/inspector/InspectorDatabaseInstrumentation.h
new file mode 100644
index 0000000..ae05d5f
--- /dev/null
+++ b/Source/core/inspector/InspectorDatabaseInstrumentation.h
@@ -0,0 +1,55 @@
+/*
+* Copyright (C) 2011 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 InspectorDatabaseInstrumentation_h
+#define InspectorDatabaseInstrumentation_h
+
+#include "core/inspector/InspectorInstrumentation.h"
+#include "modules/webdatabase/Database.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+namespace InspectorInstrumentation {
+
+void didOpenDatabaseImpl(InstrumentingAgents*, PassRefPtr<Database>, const String& domain, const String& name, const String& version);
+
+inline void didOpenDatabase(ScriptExecutionContext* context, PassRefPtr<Database> database, const String& domain, const String& name, const String& version)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ didOpenDatabaseImpl(instrumentingAgents, database, domain, name, version);
+}
+
+} // namespace InspectorInstrumentation
+
+} // namespace WebCore
+
+#endif // !defined(InspectorDatabaseInstrumentation_h)
diff --git a/Source/core/inspector/InspectorDatabaseResource.cpp b/Source/core/inspector/InspectorDatabaseResource.cpp
new file mode 100644
index 0000000..e63082c
--- /dev/null
+++ b/Source/core/inspector/InspectorDatabaseResource.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ * Copyright (C) 2009 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InspectorDatabaseResource.h"
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorValues.h"
+#include "modules/webdatabase/Database.h"
+
+namespace WebCore {
+
+static int nextUnusedId = 1;
+
+PassRefPtr<InspectorDatabaseResource> InspectorDatabaseResource::create(PassRefPtr<Database> database, const String& domain, const String& name, const String& version)
+{
+ return adoptRef(new InspectorDatabaseResource(database, domain, name, version));
+}
+
+InspectorDatabaseResource::InspectorDatabaseResource(PassRefPtr<Database> database, const String& domain, const String& name, const String& version)
+ : m_database(database)
+ , m_id(String::number(nextUnusedId++))
+ , m_domain(domain)
+ , m_name(name)
+ , m_version(version)
+{
+}
+
+void InspectorDatabaseResource::bind(InspectorFrontend::Database* frontend)
+{
+ RefPtr<TypeBuilder::Database::Database> jsonObject = TypeBuilder::Database::Database::create()
+ .setId(m_id)
+ .setDomain(m_domain)
+ .setName(m_name)
+ .setVersion(m_version);
+ frontend->addDatabase(jsonObject);
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InspectorDatabaseResource.h b/Source/core/inspector/InspectorDatabaseResource.h
new file mode 100644
index 0000000..6644fa2
--- /dev/null
+++ b/Source/core/inspector/InspectorDatabaseResource.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ * Copyright (C) 2009 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorDatabaseResource_h
+#define InspectorDatabaseResource_h
+
+#include "InspectorFrontend.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class Database;
+class InspectorFrontend;
+
+class InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> {
+public:
+ static PassRefPtr<InspectorDatabaseResource> create(PassRefPtr<Database> database, const String& domain, const String& name, const String& version);
+
+ void bind(InspectorFrontend::Database*);
+ Database* database() { return m_database.get(); }
+ void setDatabase(PassRefPtr<Database> database) { m_database = database; }
+ String id() const { return m_id; }
+
+private:
+ InspectorDatabaseResource(PassRefPtr<Database>, const String& domain, const String& name, const String& version);
+
+ RefPtr<Database> m_database;
+ String m_id;
+ String m_domain;
+ String m_name;
+ String m_version;
+};
+
+} // namespace WebCore
+
+#endif // InspectorDatabaseResource_h
diff --git a/Source/core/inspector/InspectorDebuggerAgent.cpp b/Source/core/inspector/InspectorDebuggerAgent.cpp
new file mode 100644
index 0000000..b352bda
--- /dev/null
+++ b/Source/core/inspector/InspectorDebuggerAgent.cpp
@@ -0,0 +1,780 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InspectorDebuggerAgent.h"
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptDebugServer.h"
+#include "bindings/v8/ScriptObject.h"
+#include "core/inspector/ContentSearchUtils.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/loader/cache/CachedResource.h"
+#include "core/platform/text/RegularExpression.h"
+#include <wtf/MemoryInstrumentationHashMap.h>
+#include <wtf/MemoryInstrumentationVector.h>
+#include <wtf/text/WTFString.h>
+
+using WebCore::TypeBuilder::Array;
+using WebCore::TypeBuilder::Debugger::FunctionDetails;
+using WebCore::TypeBuilder::Debugger::ScriptId;
+using WebCore::TypeBuilder::Runtime::RemoteObject;
+
+namespace WebCore {
+
+namespace DebuggerAgentState {
+static const char debuggerEnabled[] = "debuggerEnabled";
+static const char javaScriptBreakpoints[] = "javaScriptBreakopints";
+static const char pauseOnExceptionsState[] = "pauseOnExceptionsState";
+};
+
+const char* InspectorDebuggerAgent::backtraceObjectGroup = "backtrace";
+
+InspectorDebuggerAgent::InspectorDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager)
+ : InspectorBaseAgent<InspectorDebuggerAgent>("Debugger", instrumentingAgents, inspectorState)
+ , m_injectedScriptManager(injectedScriptManager)
+ , m_frontend(0)
+ , m_pausedScriptState(0)
+ , m_javaScriptPauseScheduled(false)
+ , m_listener(0)
+{
+ // FIXME: make breakReason optional so that there was no need to init it with "other".
+ clearBreakDetails();
+ m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServer::DontPauseOnExceptions);
+}
+
+InspectorDebuggerAgent::~InspectorDebuggerAgent()
+{
+ ASSERT(!m_instrumentingAgents->inspectorDebuggerAgent());
+}
+
+void InspectorDebuggerAgent::enable()
+{
+ m_instrumentingAgents->setInspectorDebuggerAgent(this);
+
+ // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends
+ scriptDebugServer().setBreakpointsActivated(true);
+ startListeningScriptDebugServer();
+
+ if (m_listener)
+ m_listener->debuggerWasEnabled();
+}
+
+void InspectorDebuggerAgent::disable()
+{
+ m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, InspectorObject::create());
+ m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServer::DontPauseOnExceptions);
+ m_instrumentingAgents->setInspectorDebuggerAgent(0);
+
+ stopListeningScriptDebugServer();
+ scriptDebugServer().clearBreakpoints();
+ scriptDebugServer().clearCompiledScripts();
+ clear();
+
+ if (m_listener)
+ m_listener->debuggerWasDisabled();
+}
+
+bool InspectorDebuggerAgent::enabled()
+{
+ return m_state->getBoolean(DebuggerAgentState::debuggerEnabled);
+}
+
+void InspectorDebuggerAgent::enable(ErrorString*)
+{
+ if (enabled())
+ return;
+
+ enable();
+ m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
+
+ ASSERT(m_frontend);
+}
+
+void InspectorDebuggerAgent::disable(ErrorString*)
+{
+ if (!enabled())
+ return;
+
+ disable();
+ m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
+}
+
+void InspectorDebuggerAgent::restore()
+{
+ if (enabled()) {
+ m_frontend->globalObjectCleared();
+ enable();
+ long pauseState = m_state->getLong(DebuggerAgentState::pauseOnExceptionsState);
+ String error;
+ setPauseOnExceptionsImpl(&error, pauseState);
+ }
+}
+
+void InspectorDebuggerAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->debugger();
+}
+
+void InspectorDebuggerAgent::clearFrontend()
+{
+ m_frontend = 0;
+
+ if (!enabled())
+ return;
+
+ disable();
+
+ // FIXME: due to m_state->mute() hack in InspectorController, debuggerEnabled is actually set to false only
+ // in InspectorState, but not in cookie. That's why after navigation debuggerEnabled will be true,
+ // but after front-end re-open it will still be false.
+ m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
+}
+
+void InspectorDebuggerAgent::setBreakpointsActive(ErrorString*, bool active)
+{
+ scriptDebugServer().setBreakpointsActivated(active);
+}
+
+bool InspectorDebuggerAgent::isPaused()
+{
+ return scriptDebugServer().isPaused();
+}
+
+bool InspectorDebuggerAgent::runningNestedMessageLoop()
+{
+ return scriptDebugServer().runningNestedMessageLoop();
+}
+
+void InspectorDebuggerAgent::addMessageToConsole(MessageSource source, MessageType type)
+{
+ if (scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions && source == ConsoleAPIMessageSource && type == AssertMessageType)
+ breakProgram(InspectorFrontend::Debugger::Reason::Assert, 0);
+}
+
+static PassRefPtr<InspectorObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, bool isRegex)
+{
+ RefPtr<InspectorObject> breakpointObject = InspectorObject::create();
+ breakpointObject->setString("url", url);
+ breakpointObject->setNumber("lineNumber", lineNumber);
+ breakpointObject->setNumber("columnNumber", columnNumber);
+ breakpointObject->setString("condition", condition);
+ breakpointObject->setBoolean("isRegex", isRegex);
+ return breakpointObject;
+}
+
+static bool matches(const String& url, const String& pattern, bool isRegex)
+{
+ if (isRegex) {
+ RegularExpression regex(pattern, TextCaseSensitive);
+ return regex.match(url) != -1;
+ }
+ return url == pattern;
+}
+
+void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const String* const optionalCondition, TypeBuilder::Debugger::BreakpointId* outBreakpointId, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::Location> >& locations)
+{
+ locations = Array<TypeBuilder::Debugger::Location>::create();
+ if (!optionalURL == !optionalURLRegex) {
+ *errorString = "Either url or urlRegex must be specified.";
+ return;
+ }
+
+ String url = optionalURL ? *optionalURL : *optionalURLRegex;
+ int columnNumber = optionalColumnNumber ? *optionalColumnNumber : 0;
+ String condition = optionalCondition ? *optionalCondition : "";
+ bool isRegex = optionalURLRegex;
+
+ String breakpointId = (isRegex ? "/" + url + "/" : url) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber);
+ RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
+ if (breakpointsCookie->find(breakpointId) != breakpointsCookie->end()) {
+ *errorString = "Breakpoint at specified location already exists.";
+ return;
+ }
+
+ breakpointsCookie->setObject(breakpointId, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, isRegex));
+ m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie);
+
+ ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
+ for (ScriptsMap::iterator it = m_scripts.begin(); it != m_scripts.end(); ++it) {
+ if (!matches(it->value.url, url, isRegex))
+ continue;
+ RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(breakpointId, it->key, breakpoint);
+ if (location)
+ locations->addItem(location);
+ }
+ *outBreakpointId = breakpointId;
+}
+
+static bool parseLocation(ErrorString* errorString, RefPtr<InspectorObject> location, String* scriptId, int* lineNumber, int* columnNumber)
+{
+ if (!location->getString("scriptId", scriptId) || !location->getNumber("lineNumber", lineNumber)) {
+ // FIXME: replace with input validation.
+ *errorString = "scriptId and lineNumber are required.";
+ return false;
+ }
+ *columnNumber = 0;
+ location->getNumber("columnNumber", columnNumber);
+ return true;
+}
+
+void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPtr<InspectorObject>& location, const String* const optionalCondition, TypeBuilder::Debugger::BreakpointId* outBreakpointId, RefPtr<TypeBuilder::Debugger::Location>& actualLocation)
+{
+ String scriptId;
+ int lineNumber;
+ int columnNumber;
+
+ if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
+ return;
+
+ String condition = optionalCondition ? *optionalCondition : emptyString();
+
+ String breakpointId = scriptId + ':' + String::number(lineNumber) + ':' + String::number(columnNumber);
+ if (m_breakpointIdToDebugServerBreakpointIds.find(breakpointId) != m_breakpointIdToDebugServerBreakpointIds.end()) {
+ *errorString = "Breakpoint at specified location already exists.";
+ return;
+ }
+ ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
+ actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint);
+ if (actualLocation)
+ *outBreakpointId = breakpointId;
+ else
+ *errorString = "Could not resolve breakpoint";
+}
+
+void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakpointId)
+{
+ RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
+ breakpointsCookie->remove(breakpointId);
+ m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie);
+
+ BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
+ if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
+ return;
+ for (size_t i = 0; i < debugServerBreakpointIdsIterator->value.size(); ++i)
+ scriptDebugServer().removeBreakpoint(debugServerBreakpointIdsIterator->value[i]);
+ m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIterator);
+}
+
+void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, const RefPtr<InspectorObject>& location)
+{
+ if (!m_continueToLocationBreakpointId.isEmpty()) {
+ scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
+ m_continueToLocationBreakpointId = "";
+ }
+
+ String scriptId;
+ int lineNumber;
+ int columnNumber;
+
+ if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
+ return;
+
+ ScriptBreakpoint breakpoint(lineNumber, columnNumber, "");
+ m_continueToLocationBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber);
+ resume(errorString);
+}
+
+PassRefPtr<TypeBuilder::Debugger::Location> InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const String& scriptId, const ScriptBreakpoint& breakpoint)
+{
+ ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
+ if (scriptIterator == m_scripts.end())
+ return 0;
+ Script& script = scriptIterator->value;
+ if (breakpoint.lineNumber < script.startLine || script.endLine < breakpoint.lineNumber)
+ return 0;
+
+ int actualLineNumber;
+ int actualColumnNumber;
+ String debugServerBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber);
+ if (debugServerBreakpointId.isEmpty())
+ return 0;
+
+ BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
+ if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
+ debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.set(breakpointId, Vector<String>()).iterator;
+ debugServerBreakpointIdsIterator->value.append(debugServerBreakpointId);
+
+ RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
+ .setScriptId(scriptId)
+ .setLineNumber(actualLineNumber);
+ location->setColumnNumber(actualColumnNumber);
+ return location;
+}
+
+static PassRefPtr<InspectorObject> scriptToInspectorObject(ScriptObject scriptObject)
+{
+ if (scriptObject.hasNoValue())
+ return 0;
+ RefPtr<InspectorValue> value = scriptObject.toInspectorValue(scriptObject.scriptState());
+ if (!value)
+ return 0;
+ return value->asObject();
+}
+
+void InspectorDebuggerAgent::searchInContent(ErrorString* error, const String& scriptId, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Array<WebCore::TypeBuilder::Page::SearchMatch> >& results)
+{
+ bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
+ bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
+
+ ScriptsMap::iterator it = m_scripts.find(scriptId);
+ if (it != m_scripts.end())
+ results = ContentSearchUtils::searchInTextByLines(it->value.source, query, caseSensitive, isRegex);
+ else
+ *error = "No script for id: " + scriptId;
+}
+
+void InspectorDebuggerAgent::setScriptSource(ErrorString* error, const String& scriptId, const String& newContent, const bool* const preview, RefPtr<Array<TypeBuilder::Debugger::CallFrame> >& newCallFrames, RefPtr<InspectorObject>& result)
+{
+ bool previewOnly = preview && *preview;
+ ScriptObject resultObject;
+ if (!scriptDebugServer().setScriptSource(scriptId, newContent, previewOnly, error, &m_currentCallStack, &resultObject))
+ return;
+ newCallFrames = currentCallFrames();
+ RefPtr<InspectorObject> object = scriptToInspectorObject(resultObject);
+ if (object)
+ result = object;
+}
+void InspectorDebuggerAgent::restartFrame(ErrorString* errorString, const String& callFrameId, RefPtr<Array<TypeBuilder::Debugger::CallFrame> >& newCallFrames, RefPtr<InspectorObject>& result)
+{
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected frame has gone";
+ return;
+ }
+
+ injectedScript.restartFrame(errorString, m_currentCallStack, callFrameId, &result);
+ scriptDebugServer().updateCallStack(&m_currentCallStack);
+ newCallFrames = currentCallFrames();
+}
+
+void InspectorDebuggerAgent::getScriptSource(ErrorString* error, const String& scriptId, String* scriptSource)
+{
+ ScriptsMap::iterator it = m_scripts.find(scriptId);
+ if (it != m_scripts.end())
+ *scriptSource = it->value.source;
+ else
+ *error = "No script for id: " + scriptId;
+}
+
+void InspectorDebuggerAgent::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<TypeBuilder::Debugger::FunctionDetails>& details)
+{
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(functionId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Function object id is obsolete";
+ return;
+ }
+ injectedScript.getFunctionDetails(errorString, functionId, &details);
+}
+
+void InspectorDebuggerAgent::schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<InspectorObject> data)
+{
+ if (m_javaScriptPauseScheduled)
+ return;
+ m_breakReason = breakReason;
+ m_breakAuxData = data;
+ scriptDebugServer().setPauseOnNextStatement(true);
+}
+
+void InspectorDebuggerAgent::cancelPauseOnNextStatement()
+{
+ if (m_javaScriptPauseScheduled)
+ return;
+ clearBreakDetails();
+ scriptDebugServer().setPauseOnNextStatement(false);
+}
+
+void InspectorDebuggerAgent::pause(ErrorString*)
+{
+ if (m_javaScriptPauseScheduled)
+ return;
+ clearBreakDetails();
+ scriptDebugServer().setPauseOnNextStatement(true);
+ m_javaScriptPauseScheduled = true;
+}
+
+void InspectorDebuggerAgent::resume(ErrorString* errorString)
+{
+ if (!assertPaused(errorString))
+ return;
+ m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
+ scriptDebugServer().continueProgram();
+}
+
+void InspectorDebuggerAgent::stepOver(ErrorString* errorString)
+{
+ if (!assertPaused(errorString))
+ return;
+ m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
+ scriptDebugServer().stepOverStatement();
+}
+
+void InspectorDebuggerAgent::stepInto(ErrorString* errorString)
+{
+ if (!assertPaused(errorString))
+ return;
+ m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
+ scriptDebugServer().stepIntoStatement();
+ if (m_listener)
+ m_listener->stepInto();
+}
+
+void InspectorDebuggerAgent::stepOut(ErrorString* errorString)
+{
+ if (!assertPaused(errorString))
+ return;
+ m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
+ scriptDebugServer().stepOutOfFunction();
+}
+
+void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, const String& stringPauseState)
+{
+ ScriptDebugServer::PauseOnExceptionsState pauseState;
+ if (stringPauseState == "none")
+ pauseState = ScriptDebugServer::DontPauseOnExceptions;
+ else if (stringPauseState == "all")
+ pauseState = ScriptDebugServer::PauseOnAllExceptions;
+ else if (stringPauseState == "uncaught")
+ pauseState = ScriptDebugServer::PauseOnUncaughtExceptions;
+ else {
+ *errorString = "Unknown pause on exceptions mode: " + stringPauseState;
+ return;
+ }
+ setPauseOnExceptionsImpl(errorString, pauseState);
+}
+
+void InspectorDebuggerAgent::setPauseOnExceptionsImpl(ErrorString* errorString, int pauseState)
+{
+ scriptDebugServer().setPauseOnExceptionsState(static_cast<ScriptDebugServer::PauseOnExceptionsState>(pauseState));
+ if (scriptDebugServer().pauseOnExceptionsState() != pauseState)
+ *errorString = "Internal error. Could not change pause on exceptions state";
+ else
+ m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, pauseState);
+}
+
+void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown)
+{
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected frame has gone";
+ return;
+ }
+
+ ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState();
+ if (doNotPauseOnExceptionsAndMuteConsole ? *doNotPauseOnExceptionsAndMuteConsole : false) {
+ if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions)
+ scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions);
+ muteConsole();
+ }
+
+ injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, generatePreview ? *generatePreview : false, &result, wasThrown);
+
+ if (doNotPauseOnExceptionsAndMuteConsole ? *doNotPauseOnExceptionsAndMuteConsole : false) {
+ unmuteConsole();
+ if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState)
+ scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState);
+ }
+}
+
+void InspectorDebuggerAgent::compileScript(ErrorString* errorString, const String& expression, const String& sourceURL, TypeBuilder::OptOutput<ScriptId>* scriptId, TypeBuilder::OptOutput<String>* syntaxErrorMessage)
+{
+ InjectedScript injectedScript = injectedScriptForEval(errorString, 0);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected frame has gone";
+ return;
+ }
+
+ String scriptIdValue;
+ String exceptionMessage;
+ scriptDebugServer().compileScript(injectedScript.scriptState(), expression, sourceURL, &scriptIdValue, &exceptionMessage);
+ if (!scriptIdValue && !exceptionMessage) {
+ *errorString = "Script compilation failed";
+ return;
+ }
+ *syntaxErrorMessage = exceptionMessage;
+ *scriptId = scriptIdValue;
+}
+
+void InspectorDebuggerAgent::runScript(ErrorString* errorString, const ScriptId& scriptId, const int* executionContextId, const String* const objectGroup, const bool* const doNotPauseOnExceptionsAndMuteConsole, RefPtr<TypeBuilder::Runtime::RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown)
+{
+ InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected frame has gone";
+ return;
+ }
+
+ ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState();
+ if (doNotPauseOnExceptionsAndMuteConsole && *doNotPauseOnExceptionsAndMuteConsole) {
+ if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions)
+ scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions);
+ muteConsole();
+ }
+
+ ScriptValue value;
+ bool wasThrownValue;
+ String exceptionMessage;
+ scriptDebugServer().runScript(injectedScript.scriptState(), scriptId, &value, &wasThrownValue, &exceptionMessage);
+ *wasThrown = wasThrownValue;
+ if (value.hasNoValue()) {
+ *errorString = "Script execution failed";
+ return;
+ }
+ result = injectedScript.wrapObject(value, objectGroup ? *objectGroup : "");
+ if (wasThrownValue)
+ result->setDescription(exceptionMessage);
+
+ if (doNotPauseOnExceptionsAndMuteConsole && *doNotPauseOnExceptionsAndMuteConsole) {
+ unmuteConsole();
+ if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState)
+ scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState);
+ }
+}
+
+void InspectorDebuggerAgent::setOverlayMessage(ErrorString*, const String*)
+{
+}
+
+void InspectorDebuggerAgent::setVariableValue(ErrorString* errorString, int scopeNumber, const String& variableName, const RefPtr<InspectorObject>& newValue, const String* callFrameId, const String* functionObjectId)
+{
+ InjectedScript injectedScript;
+ if (callFrameId) {
+ injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*callFrameId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected frame has gone";
+ return;
+ }
+ } else if (functionObjectId) {
+ injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*functionObjectId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Function object id cannot be resolved";
+ return;
+ }
+ } else {
+ *errorString = "Either call frame or function object must be specified";
+ return;
+ }
+ String newValueString = newValue->toJSONString();
+
+ injectedScript.setVariableValue(errorString, m_currentCallStack, callFrameId, functionObjectId, scopeNumber, variableName, newValueString);
+}
+
+void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText)
+{
+ if (scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions) {
+ RefPtr<InspectorObject> directive = InspectorObject::create();
+ directive->setString("directiveText", directiveText);
+ breakProgram(InspectorFrontend::Debugger::Reason::CSPViolation, directive.release());
+ }
+}
+
+PassRefPtr<Array<TypeBuilder::Debugger::CallFrame> > InspectorDebuggerAgent::currentCallFrames()
+{
+ if (!m_pausedScriptState)
+ return Array<TypeBuilder::Debugger::CallFrame>::create();
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState);
+ if (injectedScript.hasNoValue()) {
+ ASSERT_NOT_REACHED();
+ return Array<TypeBuilder::Debugger::CallFrame>::create();
+ }
+ return injectedScript.wrapCallFrames(m_currentCallStack);
+}
+
+String InspectorDebuggerAgent::sourceMapURLForScript(const Script& script)
+{
+ DEFINE_STATIC_LOCAL(String, sourceMapHttpHeader, (ASCIILiteral("X-SourceMap")));
+
+ String sourceMapURL = ContentSearchUtils::findSourceMapURL(script.source);
+ if (!sourceMapURL.isEmpty())
+ return sourceMapURL;
+
+ if (script.url.isEmpty())
+ return String();
+
+ InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent();
+ if (!pageAgent)
+ return String();
+
+ CachedResource* resource = pageAgent->cachedResource(pageAgent->mainFrame(), KURL(ParsedURLString, script.url));
+ if (resource)
+ return resource->response().httpHeaderField(sourceMapHttpHeader);
+ return String();
+}
+
+// JavaScriptDebugListener functions
+
+void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& script)
+{
+ // Don't send script content to the front end until it's really needed.
+ const bool* isContentScript = script.isContentScript ? &script.isContentScript : 0;
+ String sourceMapURL = sourceMapURLForScript(script);
+ String* sourceMapURLParam = sourceMapURL.isNull() ? 0 : &sourceMapURL;
+ String sourceURL;
+ if (!script.startLine && !script.startColumn)
+ sourceURL = ContentSearchUtils::findSourceURL(script.source);
+ bool hasSourceURL = !sourceURL.isEmpty();
+ String scriptURL = hasSourceURL ? sourceURL : script.url;
+ bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : 0;
+ m_frontend->scriptParsed(scriptId, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam);
+
+ m_scripts.set(scriptId, script);
+
+ if (scriptURL.isEmpty())
+ return;
+
+ RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
+ for (InspectorObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
+ RefPtr<InspectorObject> breakpointObject = it->value->asObject();
+ bool isRegex;
+ breakpointObject->getBoolean("isRegex", &isRegex);
+ String url;
+ breakpointObject->getString("url", &url);
+ if (!matches(scriptURL, url, isRegex))
+ continue;
+ ScriptBreakpoint breakpoint;
+ breakpointObject->getNumber("lineNumber", &breakpoint.lineNumber);
+ breakpointObject->getNumber("columnNumber", &breakpoint.columnNumber);
+ breakpointObject->getString("condition", &breakpoint.condition);
+ RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(it->key, scriptId, breakpoint);
+ if (location)
+ m_frontend->breakpointResolved(it->key, location);
+ }
+}
+
+void InspectorDebuggerAgent::failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage)
+{
+ m_frontend->scriptFailedToParse(url, data, firstLine, errorLine, errorMessage);
+}
+
+void InspectorDebuggerAgent::didPause(ScriptState* scriptState, const ScriptValue& callFrames, const ScriptValue& exception)
+{
+ ASSERT(scriptState && !m_pausedScriptState);
+ m_pausedScriptState = scriptState;
+ m_currentCallStack = callFrames;
+
+ if (!exception.hasNoValue()) {
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
+ if (!injectedScript.hasNoValue()) {
+ m_breakReason = InspectorFrontend::Debugger::Reason::Exception;
+ m_breakAuxData = injectedScript.wrapObject(exception, "backtrace")->openAccessors();
+ // m_breakAuxData might be null after this.
+ }
+ }
+
+ m_frontend->paused(currentCallFrames(), m_breakReason, m_breakAuxData);
+ m_javaScriptPauseScheduled = false;
+
+ if (!m_continueToLocationBreakpointId.isEmpty()) {
+ scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
+ m_continueToLocationBreakpointId = "";
+ }
+ if (m_listener)
+ m_listener->didPause();
+}
+
+void InspectorDebuggerAgent::didContinue()
+{
+ m_pausedScriptState = 0;
+ m_currentCallStack = ScriptValue();
+ clearBreakDetails();
+ m_frontend->resumed();
+}
+
+void InspectorDebuggerAgent::breakProgram(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<InspectorObject> data)
+{
+ m_breakReason = breakReason;
+ m_breakAuxData = data;
+ scriptDebugServer().breakProgram();
+}
+
+void InspectorDebuggerAgent::clear()
+{
+ m_pausedScriptState = 0;
+ m_currentCallStack = ScriptValue();
+ m_scripts.clear();
+ m_breakpointIdToDebugServerBreakpointIds.clear();
+ m_continueToLocationBreakpointId = String();
+ clearBreakDetails();
+ m_javaScriptPauseScheduled = false;
+ ErrorString error;
+ setOverlayMessage(&error, 0);
+}
+
+bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString)
+{
+ if (!m_pausedScriptState) {
+ *errorString = "Can only perform operation while paused.";
+ return false;
+ }
+ return true;
+}
+
+void InspectorDebuggerAgent::clearBreakDetails()
+{
+ m_breakReason = InspectorFrontend::Debugger::Reason::Other;
+ m_breakAuxData = 0;
+}
+
+void InspectorDebuggerAgent::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorDebuggerAgent);
+ InspectorBaseAgent<InspectorDebuggerAgent>::reportMemoryUsage(memoryObjectInfo);
+ info.addMember(m_injectedScriptManager, "injectedScriptManager");
+ info.addWeakPointer(m_frontend);
+ info.addMember(m_pausedScriptState, "pausedScriptState");
+ info.addMember(m_currentCallStack, "currentCallStack");
+ info.addMember(m_scripts, "scripts");
+ info.addMember(m_breakpointIdToDebugServerBreakpointIds, "breakpointIdToDebugServerBreakpointIds");
+ info.addMember(m_continueToLocationBreakpointId, "continueToLocationBreakpointId");
+ info.addMember(m_breakAuxData, "breakAuxData");
+ info.addWeakPointer(m_listener);
+}
+
+void ScriptDebugListener::Script::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorDebuggerAgent);
+ info.addMember(url, "url");
+ info.addMember(source, "source");
+ info.addMember(sourceMappingURL, "sourceMappingURL");
+}
+
+void InspectorDebuggerAgent::reset()
+{
+ m_scripts.clear();
+ m_breakpointIdToDebugServerBreakpointIds.clear();
+ if (m_frontend)
+ m_frontend->globalObjectCleared();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorDebuggerAgent.h b/Source/core/inspector/InspectorDebuggerAgent.h
new file mode 100644
index 0000000..1d8b715
--- /dev/null
+++ b/Source/core/inspector/InspectorDebuggerAgent.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorDebuggerAgent_h
+#define InspectorDebuggerAgent_h
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/ConsoleAPITypes.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/inspector/ScriptBreakpoint.h"
+#include "core/inspector/ScriptDebugListener.h"
+#include "core/page/ConsoleTypes.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class InjectedScriptManager;
+class InspectorFrontend;
+class InspectorArray;
+class InspectorObject;
+class InspectorState;
+class InspectorValue;
+class InstrumentingAgents;
+class ScriptDebugServer;
+class ScriptValue;
+
+typedef String ErrorString;
+
+class InspectorDebuggerAgent : public InspectorBaseAgent<InspectorDebuggerAgent>, public ScriptDebugListener, public InspectorBackendDispatcher::DebuggerCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorDebuggerAgent); WTF_MAKE_FAST_ALLOCATED;
+public:
+ static const char* backtraceObjectGroup;
+
+ virtual ~InspectorDebuggerAgent();
+
+ virtual void canSetScriptSource(ErrorString*, bool* result) { *result = true; }
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ bool isPaused();
+ bool runningNestedMessageLoop();
+ void addMessageToConsole(MessageSource, MessageType);
+
+ // Part of the protocol.
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void setBreakpointsActive(ErrorString*, bool active);
+
+ virtual void setBreakpointByUrl(ErrorString*, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const String* optionalCondition, TypeBuilder::Debugger::BreakpointId*, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::Location> >& locations);
+ virtual void setBreakpoint(ErrorString*, const RefPtr<InspectorObject>& location, const String* optionalCondition, TypeBuilder::Debugger::BreakpointId*, RefPtr<TypeBuilder::Debugger::Location>& actualLocation);
+ virtual void removeBreakpoint(ErrorString*, const String& breakpointId);
+ virtual void continueToLocation(ErrorString*, const RefPtr<InspectorObject>& location);
+
+ virtual void searchInContent(ErrorString*, const String& scriptId, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> >&);
+ virtual void setScriptSource(ErrorString*, const String& scriptId, const String& newContent, const bool* preview, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame> >& newCallFrames, RefPtr<InspectorObject>& result);
+ virtual void restartFrame(ErrorString*, const String& callFrameId, RefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame> >& newCallFrames, RefPtr<InspectorObject>& result);
+ virtual void getScriptSource(ErrorString*, const String& scriptId, String* scriptSource);
+ virtual void getFunctionDetails(ErrorString*, const String& functionId, RefPtr<TypeBuilder::Debugger::FunctionDetails>&);
+ virtual void pause(ErrorString*);
+ virtual void resume(ErrorString*);
+ virtual void stepOver(ErrorString*);
+ virtual void stepInto(ErrorString*);
+ virtual void stepOut(ErrorString*);
+ virtual void setPauseOnExceptions(ErrorString*, const String& pauseState);
+ virtual void evaluateOnCallFrame(ErrorString*,
+ const String& callFrameId,
+ const String& expression,
+ const String* objectGroup,
+ const bool* includeCommandLineAPI,
+ const bool* doNotPauseOnExceptionsAndMuteConsole,
+ const bool* returnByValue,
+ const bool* generatePreview,
+ RefPtr<TypeBuilder::Runtime::RemoteObject>& result,
+ TypeBuilder::OptOutput<bool>* wasThrown);
+ void compileScript(ErrorString*, const String& expression, const String& sourceURL, TypeBuilder::OptOutput<TypeBuilder::Debugger::ScriptId>*, TypeBuilder::OptOutput<String>* syntaxErrorMessage);
+ void runScript(ErrorString*, const TypeBuilder::Debugger::ScriptId&, const int* executionContextId, const String* objectGroup, const bool* doNotPauseOnExceptionsAndMuteConsole, RefPtr<TypeBuilder::Runtime::RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown);
+ virtual void setOverlayMessage(ErrorString*, const String*);
+ virtual void setVariableValue(ErrorString*, int in_scopeNumber, const String& in_variableName, const RefPtr<InspectorObject>& in_newValue, const String* in_callFrame, const String* in_functionObjectId);
+
+ void schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<InspectorObject> data);
+ void cancelPauseOnNextStatement();
+ void breakProgram(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<InspectorObject> data);
+ virtual void scriptExecutionBlockedByCSP(const String& directiveText);
+
+ class Listener {
+ public:
+ virtual ~Listener() { }
+ virtual void debuggerWasEnabled() = 0;
+ virtual void debuggerWasDisabled() = 0;
+ virtual void stepInto() = 0;
+ virtual void didPause() = 0;
+ };
+ void setListener(Listener* listener) { m_listener = listener; }
+
+ virtual ScriptDebugServer& scriptDebugServer() = 0;
+
+ virtual void reportMemoryUsage(MemoryObjectInfo*) const;
+
+protected:
+ InspectorDebuggerAgent(InstrumentingAgents*, InspectorCompositeState*, InjectedScriptManager*);
+
+ virtual void startListeningScriptDebugServer() = 0;
+ virtual void stopListeningScriptDebugServer() = 0;
+ virtual void muteConsole() = 0;
+ virtual void unmuteConsole() = 0;
+ InjectedScriptManager* injectedScriptManager() { return m_injectedScriptManager; }
+ virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId) = 0;
+
+ virtual void enable();
+ virtual void disable();
+ virtual void didPause(ScriptState*, const ScriptValue& callFrames, const ScriptValue& exception);
+ virtual void didContinue();
+ void reset();
+
+private:
+ bool enabled();
+
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame> > currentCallFrames();
+
+ virtual void didParseSource(const String& scriptId, const Script&);
+ virtual void failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage);
+
+ void setPauseOnExceptionsImpl(ErrorString*, int);
+
+ PassRefPtr<TypeBuilder::Debugger::Location> resolveBreakpoint(const String& breakpointId, const String& scriptId, const ScriptBreakpoint&);
+ void clear();
+ bool assertPaused(ErrorString*);
+ void clearBreakDetails();
+
+ String sourceMapURLForScript(const Script&);
+
+ typedef HashMap<String, Script> ScriptsMap;
+ typedef HashMap<String, Vector<String> > BreakpointIdToDebugServerBreakpointIdsMap;
+
+ InjectedScriptManager* m_injectedScriptManager;
+ InspectorFrontend::Debugger* m_frontend;
+ ScriptState* m_pausedScriptState;
+ ScriptValue m_currentCallStack;
+ ScriptsMap m_scripts;
+ BreakpointIdToDebugServerBreakpointIdsMap m_breakpointIdToDebugServerBreakpointIds;
+ String m_continueToLocationBreakpointId;
+ InspectorFrontend::Debugger::Reason::Enum m_breakReason;
+ RefPtr<InspectorObject> m_breakAuxData;
+ bool m_javaScriptPauseScheduled;
+ Listener* m_listener;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorDebuggerAgent_h)
diff --git a/Source/core/inspector/InspectorFileSystemAgent.cpp b/Source/core/inspector/InspectorFileSystemAgent.cpp
new file mode 100644
index 0000000..389d9c4
--- /dev/null
+++ b/Source/core/inspector/InspectorFileSystemAgent.cpp
@@ -0,0 +1,738 @@
+/*
+ * Copyright (C) 2011, 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorFileSystemAgent.h"
+
+#include "core/dom/DOMImplementation.h"
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/dom/ScriptExecutionContext.h"
+#include "core/fileapi/File.h"
+#include "core/fileapi/FileError.h"
+#include "core/fileapi/FileReader.h"
+#include "core/html/VoidCallback.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/loader/TextResourceDecoder.h"
+#include "core/page/Frame.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/platform/KURL.h"
+#include "core/platform/MIMETypeRegistry.h"
+#include "core/platform/text/TextEncoding.h"
+#include "modules/filesystem/DOMFileSystem.h"
+#include "modules/filesystem/DirectoryEntry.h"
+#include "modules/filesystem/DirectoryReader.h"
+#include "modules/filesystem/EntriesCallback.h"
+#include "modules/filesystem/EntryArray.h"
+#include "modules/filesystem/EntryCallback.h"
+#include "modules/filesystem/ErrorCallback.h"
+#include "modules/filesystem/FileCallback.h"
+#include "modules/filesystem/FileEntry.h"
+#include "modules/filesystem/FileSystemCallback.h"
+#include "modules/filesystem/FileSystemCallbacks.h"
+#include "modules/filesystem/LocalFileSystem.h"
+#include "modules/filesystem/Metadata.h"
+#include "modules/filesystem/MetadataCallback.h"
+#include <wtf/text/Base64.h>
+
+using WebCore::TypeBuilder::Array;
+
+typedef WebCore::InspectorBackendDispatcher::FileSystemCommandHandler::RequestFileSystemRootCallback RequestFileSystemRootCallback;
+typedef WebCore::InspectorBackendDispatcher::FileSystemCommandHandler::RequestDirectoryContentCallback RequestDirectoryContentCallback;
+typedef WebCore::InspectorBackendDispatcher::FileSystemCommandHandler::RequestMetadataCallback RequestMetadataCallback;
+typedef WebCore::InspectorBackendDispatcher::FileSystemCommandHandler::RequestFileContentCallback RequestFileContentCallback;
+typedef WebCore::InspectorBackendDispatcher::FileSystemCommandHandler::DeleteEntryCallback DeleteEntryCallback;
+
+namespace WebCore {
+
+namespace FileSystemAgentState {
+static const char fileSystemAgentEnabled[] = "fileSystemAgentEnabled";
+}
+
+namespace {
+
+template<typename BaseCallback, typename Handler, typename Argument>
+class CallbackDispatcher : public BaseCallback {
+public:
+ typedef bool (Handler::*HandlingMethod)(Argument*);
+
+ static PassRefPtr<CallbackDispatcher> create(PassRefPtr<Handler> handler, HandlingMethod handlingMethod)
+ {
+ return adoptRef(new CallbackDispatcher(handler, handlingMethod));
+ }
+
+ virtual bool handleEvent(Argument* argument) OVERRIDE
+ {
+ return (m_handler.get()->*m_handlingMethod)(argument);
+ }
+
+private:
+ CallbackDispatcher(PassRefPtr<Handler> handler, HandlingMethod handlingMethod)
+ : m_handler(handler)
+ , m_handlingMethod(handlingMethod) { }
+
+ RefPtr<Handler> m_handler;
+ HandlingMethod m_handlingMethod;
+};
+
+template<typename BaseCallback>
+class CallbackDispatcherFactory {
+public:
+ template<typename Handler, typename Argument>
+ static PassRefPtr<CallbackDispatcher<BaseCallback, Handler, Argument> > create(Handler* handler, bool (Handler::*handlingMethod)(Argument*))
+ {
+ return CallbackDispatcher<BaseCallback, Handler, Argument>::create(PassRefPtr<Handler>(handler), handlingMethod);
+ }
+};
+
+class FileSystemRootRequest : public RefCounted<FileSystemRootRequest> {
+ WTF_MAKE_NONCOPYABLE(FileSystemRootRequest);
+public:
+ static PassRefPtr<FileSystemRootRequest> create(PassRefPtr<RequestFileSystemRootCallback> requestCallback, const String& type)
+ {
+ return adoptRef(new FileSystemRootRequest(requestCallback, type));
+ }
+
+ void start(ScriptExecutionContext*);
+
+private:
+ bool didHitError(FileError* error)
+ {
+ reportResult(error->code());
+ return true;
+ }
+
+ bool didGetEntry(Entry*);
+
+ void reportResult(FileError::ErrorCode errorCode, PassRefPtr<TypeBuilder::FileSystem::Entry> entry = 0)
+ {
+ m_requestCallback->sendSuccess(static_cast<int>(errorCode), entry);
+ }
+
+ FileSystemRootRequest(PassRefPtr<RequestFileSystemRootCallback> requestCallback, const String& type)
+ : m_requestCallback(requestCallback)
+ , m_type(type) { }
+
+ RefPtr<RequestFileSystemRootCallback> m_requestCallback;
+ String m_type;
+};
+
+void FileSystemRootRequest::start(ScriptExecutionContext* scriptExecutionContext)
+{
+ ASSERT(scriptExecutionContext);
+
+ RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &FileSystemRootRequest::didHitError);
+ FileSystemType type;
+ if (m_type == DOMFileSystemBase::persistentPathPrefix)
+ type = FileSystemTypePersistent;
+ else if (m_type == DOMFileSystemBase::temporaryPathPrefix)
+ type = FileSystemTypeTemporary;
+ else {
+ errorCallback->handleEvent(FileError::create(FileError::SYNTAX_ERR).get());
+ return;
+ }
+
+ RefPtr<EntryCallback> successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &FileSystemRootRequest::didGetEntry);
+ OwnPtr<ResolveURICallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, scriptExecutionContext, type, "/");
+
+ LocalFileSystem::localFileSystem().readFileSystem(scriptExecutionContext, type, fileSystemCallbacks.release());
+}
+
+bool FileSystemRootRequest::didGetEntry(Entry* entry)
+{
+ RefPtr<TypeBuilder::FileSystem::Entry> result = TypeBuilder::FileSystem::Entry::create()
+ .setUrl(entry->toURL())
+ .setName("/")
+ .setIsDirectory(true);
+ reportResult(static_cast<FileError::ErrorCode>(0), result);
+ return true;
+}
+
+class DirectoryContentRequest : public RefCounted<DirectoryContentRequest> {
+ WTF_MAKE_NONCOPYABLE(DirectoryContentRequest);
+public:
+ static PassRefPtr<DirectoryContentRequest> create(PassRefPtr<RequestDirectoryContentCallback> requestCallback, const String& url)
+ {
+ return adoptRef(new DirectoryContentRequest(requestCallback, url));
+ }
+
+ virtual ~DirectoryContentRequest()
+ {
+ reportResult(FileError::ABORT_ERR);
+ }
+
+ void start(ScriptExecutionContext*);
+
+private:
+ bool didHitError(FileError* error)
+ {
+ reportResult(error->code());
+ return true;
+ }
+
+ bool didGetEntry(Entry*);
+ bool didReadDirectoryEntries(EntryArray*);
+
+ void reportResult(FileError::ErrorCode errorCode, PassRefPtr<Array<TypeBuilder::FileSystem::Entry> > entries = 0)
+ {
+ m_requestCallback->sendSuccess(static_cast<int>(errorCode), entries);
+ }
+
+ DirectoryContentRequest(PassRefPtr<RequestDirectoryContentCallback> requestCallback, const String& url)
+ : m_requestCallback(requestCallback)
+ , m_url(ParsedURLString, url) { }
+
+ void readDirectoryEntries();
+
+ RefPtr<RequestDirectoryContentCallback> m_requestCallback;
+ KURL m_url;
+ RefPtr<Array<TypeBuilder::FileSystem::Entry> > m_entries;
+ RefPtr<DirectoryReader> m_directoryReader;
+};
+
+void DirectoryContentRequest::start(ScriptExecutionContext* scriptExecutionContext)
+{
+ ASSERT(scriptExecutionContext);
+
+ RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &DirectoryContentRequest::didHitError);
+ FileSystemType type;
+ String path;
+ if (!DOMFileSystemBase::crackFileSystemURL(m_url, type, path)) {
+ errorCallback->handleEvent(FileError::create(FileError::SYNTAX_ERR).get());
+ return;
+ }
+
+ RefPtr<EntryCallback> successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &DirectoryContentRequest::didGetEntry);
+ OwnPtr<ResolveURICallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, scriptExecutionContext, type, path);
+
+ LocalFileSystem::localFileSystem().readFileSystem(scriptExecutionContext, type, fileSystemCallbacks.release());
+}
+
+bool DirectoryContentRequest::didGetEntry(Entry* entry)
+{
+ if (!entry->isDirectory()) {
+ reportResult(FileError::TYPE_MISMATCH_ERR);
+ return true;
+ }
+
+ m_directoryReader = static_cast<DirectoryEntry*>(entry)->createReader();
+ m_entries = Array<TypeBuilder::FileSystem::Entry>::create();
+ readDirectoryEntries();
+ return true;
+}
+
+void DirectoryContentRequest::readDirectoryEntries()
+{
+ if (!m_directoryReader->filesystem()->scriptExecutionContext()) {
+ reportResult(FileError::ABORT_ERR);
+ return;
+ }
+
+ RefPtr<EntriesCallback> successCallback = CallbackDispatcherFactory<EntriesCallback>::create(this, &DirectoryContentRequest::didReadDirectoryEntries);
+ RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &DirectoryContentRequest::didHitError);
+ m_directoryReader->readEntries(successCallback, errorCallback);
+}
+
+bool DirectoryContentRequest::didReadDirectoryEntries(EntryArray* entries)
+{
+ if (!entries->length()) {
+ reportResult(static_cast<FileError::ErrorCode>(0), m_entries);
+ return true;
+ }
+
+ for (unsigned i = 0; i < entries->length(); ++i) {
+ Entry* entry = entries->item(i);
+ RefPtr<TypeBuilder::FileSystem::Entry> entryForFrontend = TypeBuilder::FileSystem::Entry::create()
+ .setUrl(entry->toURL())
+ .setName(entry->name())
+ .setIsDirectory(entry->isDirectory());
+
+ using TypeBuilder::Page::ResourceType;
+ if (!entry->isDirectory()) {
+ String mimeType = MIMETypeRegistry::getMIMETypeForPath(entry->name());
+ ResourceType::Enum resourceType;
+ if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType)) {
+ resourceType = ResourceType::Image;
+ entryForFrontend->setIsTextFile(false);
+ } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType)) {
+ resourceType = ResourceType::Script;
+ entryForFrontend->setIsTextFile(true);
+ } else if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)) {
+ resourceType = ResourceType::Document;
+ entryForFrontend->setIsTextFile(true);
+ } else {
+ resourceType = ResourceType::Other;
+ entryForFrontend->setIsTextFile(DOMImplementation::isXMLMIMEType(mimeType) || DOMImplementation::isTextMIMEType(mimeType));
+ }
+
+ entryForFrontend->setMimeType(mimeType);
+ entryForFrontend->setResourceType(resourceType);
+ }
+
+ m_entries->addItem(entryForFrontend);
+ }
+ readDirectoryEntries();
+ return true;
+}
+
+class MetadataRequest : public RefCounted<MetadataRequest> {
+ WTF_MAKE_NONCOPYABLE(MetadataRequest);
+public:
+ static PassRefPtr<MetadataRequest> create(PassRefPtr<RequestMetadataCallback> requestCallback, const String& url)
+ {
+ return adoptRef(new MetadataRequest(requestCallback, url));
+ }
+
+ virtual ~MetadataRequest()
+ {
+ reportResult(FileError::ABORT_ERR);
+ }
+
+ void start(ScriptExecutionContext*);
+
+private:
+ bool didHitError(FileError* error)
+ {
+ reportResult(error->code());
+ return true;
+ }
+
+ bool didGetEntry(Entry*);
+ bool didGetMetadata(Metadata*);
+
+ void reportResult(FileError::ErrorCode errorCode, PassRefPtr<TypeBuilder::FileSystem::Metadata> metadata = 0)
+ {
+ m_requestCallback->sendSuccess(static_cast<int>(errorCode), metadata);
+ }
+
+ MetadataRequest(PassRefPtr<RequestMetadataCallback> requestCallback, const String& url)
+ : m_requestCallback(requestCallback)
+ , m_url(ParsedURLString, url) { }
+
+ RefPtr<RequestMetadataCallback> m_requestCallback;
+ KURL m_url;
+ String m_path;
+ bool m_isDirectory;
+};
+
+void MetadataRequest::start(ScriptExecutionContext* scriptExecutionContext)
+{
+ ASSERT(scriptExecutionContext);
+
+ RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &MetadataRequest::didHitError);
+
+ FileSystemType type;
+ if (!DOMFileSystemBase::crackFileSystemURL(m_url, type, m_path)) {
+ errorCallback->handleEvent(FileError::create(FileError::SYNTAX_ERR).get());
+ return;
+ }
+
+ RefPtr<EntryCallback> successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &MetadataRequest::didGetEntry);
+ OwnPtr<ResolveURICallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, scriptExecutionContext, type, m_path);
+ LocalFileSystem::localFileSystem().readFileSystem(scriptExecutionContext, type, fileSystemCallbacks.release());
+}
+
+bool MetadataRequest::didGetEntry(Entry* entry)
+{
+ if (!entry->filesystem()->scriptExecutionContext()) {
+ reportResult(FileError::ABORT_ERR);
+ return true;
+ }
+
+ RefPtr<MetadataCallback> successCallback = CallbackDispatcherFactory<MetadataCallback>::create(this, &MetadataRequest::didGetMetadata);
+ RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &MetadataRequest::didHitError);
+ entry->getMetadata(successCallback, errorCallback);
+ m_isDirectory = entry->isDirectory();
+ return true;
+}
+
+bool MetadataRequest::didGetMetadata(Metadata* metadata)
+{
+ using TypeBuilder::FileSystem::Metadata;
+ RefPtr<Metadata> result = Metadata::create()
+ .setModificationTime(metadata->modificationTime())
+ .setSize(metadata->size());
+ reportResult(static_cast<FileError::ErrorCode>(0), result);
+ return true;
+}
+
+class FileContentRequest : public EventListener {
+ WTF_MAKE_NONCOPYABLE(FileContentRequest);
+public:
+ static PassRefPtr<FileContentRequest> create(PassRefPtr<RequestFileContentCallback> requestCallback, const String& url, bool readAsText, long long start, long long end, const String& charset)
+ {
+ return adoptRef(new FileContentRequest(requestCallback, url, readAsText, start, end, charset));
+ }
+
+ virtual ~FileContentRequest()
+ {
+ reportResult(FileError::ABORT_ERR);
+ }
+
+ void start(ScriptExecutionContext*);
+
+ virtual bool operator==(const EventListener& other) OVERRIDE
+ {
+ return this == &other;
+ }
+
+ virtual void handleEvent(ScriptExecutionContext*, Event* event) OVERRIDE
+ {
+ if (event->type() == eventNames().loadEvent)
+ didRead();
+ else if (event->type() == eventNames().errorEvent)
+ didHitError(m_reader->error().get());
+ }
+
+private:
+ bool didHitError(FileError* error)
+ {
+ reportResult(error->code());
+ return true;
+ }
+
+ bool didGetEntry(Entry*);
+ bool didGetFile(File*);
+ void didRead();
+
+ void reportResult(FileError::ErrorCode errorCode, const String* result = 0, const String* charset = 0)
+ {
+ m_requestCallback->sendSuccess(static_cast<int>(errorCode), result, charset);
+ }
+
+ FileContentRequest(PassRefPtr<RequestFileContentCallback> requestCallback, const String& url, bool readAsText, long long start, long long end, const String& charset)
+ : EventListener(EventListener::CPPEventListenerType)
+ , m_requestCallback(requestCallback)
+ , m_url(ParsedURLString, url)
+ , m_readAsText(readAsText)
+ , m_start(start)
+ , m_end(end)
+ , m_charset(charset) { }
+
+ RefPtr<RequestFileContentCallback> m_requestCallback;
+ KURL m_url;
+ bool m_readAsText;
+ int m_start;
+ long long m_end;
+ String m_mimeType;
+ String m_charset;
+
+ RefPtr<FileReader> m_reader;
+};
+
+void FileContentRequest::start(ScriptExecutionContext* scriptExecutionContext)
+{
+ ASSERT(scriptExecutionContext);
+
+ RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &FileContentRequest::didHitError);
+
+ FileSystemType type;
+ String path;
+ if (!DOMFileSystemBase::crackFileSystemURL(m_url, type, path)) {
+ errorCallback->handleEvent(FileError::create(FileError::SYNTAX_ERR).get());
+ return;
+ }
+
+ RefPtr<EntryCallback> successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &FileContentRequest::didGetEntry);
+ OwnPtr<ResolveURICallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, scriptExecutionContext, type, path);
+
+ LocalFileSystem::localFileSystem().readFileSystem(scriptExecutionContext, type, fileSystemCallbacks.release());
+}
+
+bool FileContentRequest::didGetEntry(Entry* entry)
+{
+ if (entry->isDirectory()) {
+ reportResult(FileError::TYPE_MISMATCH_ERR);
+ return true;
+ }
+
+ if (!entry->filesystem()->scriptExecutionContext()) {
+ reportResult(FileError::ABORT_ERR);
+ return true;
+ }
+
+ RefPtr<FileCallback> successCallback = CallbackDispatcherFactory<FileCallback>::create(this, &FileContentRequest::didGetFile);
+ RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &FileContentRequest::didHitError);
+ static_cast<FileEntry*>(entry)->file(successCallback, errorCallback);
+
+ m_reader = FileReader::create(entry->filesystem()->scriptExecutionContext());
+ m_mimeType = MIMETypeRegistry::getMIMETypeForPath(entry->name());
+
+ return true;
+}
+
+bool FileContentRequest::didGetFile(File* file)
+{
+ RefPtr<Blob> blob = file->slice(m_start, m_end);
+ m_reader->setOnload(this);
+ m_reader->setOnerror(this);
+
+ m_reader->readAsArrayBuffer(blob.get(), IGNORE_EXCEPTION);
+ return true;
+}
+
+void FileContentRequest::didRead()
+{
+ RefPtr<ArrayBuffer> buffer = m_reader->arrayBufferResult();
+
+ if (!m_readAsText) {
+ String result = base64Encode(static_cast<char*>(buffer->data()), buffer->byteLength());
+ reportResult(static_cast<FileError::ErrorCode>(0), &result, 0);
+ return;
+ }
+
+ RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create(m_mimeType, m_charset, true);
+ String result = decoder->decode(static_cast<char*>(buffer->data()), buffer->byteLength());
+ result.append(decoder->flush());
+ m_charset = decoder->encoding().domName();
+ reportResult(static_cast<FileError::ErrorCode>(0), &result, &m_charset);
+}
+
+class DeleteEntryRequest : public VoidCallback {
+public:
+ static PassRefPtr<DeleteEntryRequest> create(PassRefPtr<DeleteEntryCallback> requestCallback, const KURL& url)
+ {
+ return adoptRef(new DeleteEntryRequest(requestCallback, url));
+ }
+
+ virtual ~DeleteEntryRequest()
+ {
+ reportResult(FileError::ABORT_ERR);
+ }
+
+ virtual bool handleEvent() OVERRIDE
+ {
+ return didDeleteEntry();
+ }
+
+ void start(ScriptExecutionContext*);
+
+private:
+ bool didHitError(FileError* error)
+ {
+ reportResult(error->code());
+ return true;
+ }
+
+ bool didGetEntry(Entry*);
+ bool didDeleteEntry();
+
+ void reportResult(FileError::ErrorCode errorCode)
+ {
+ m_requestCallback->sendSuccess(static_cast<int>(errorCode));
+ }
+
+ DeleteEntryRequest(PassRefPtr<DeleteEntryCallback> requestCallback, const KURL& url)
+ : m_requestCallback(requestCallback)
+ , m_url(url) { }
+
+ RefPtr<DeleteEntryCallback> m_requestCallback;
+ KURL m_url;
+};
+
+void DeleteEntryRequest::start(ScriptExecutionContext* scriptExecutionContext)
+{
+ ASSERT(scriptExecutionContext);
+
+ RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &DeleteEntryRequest::didHitError);
+
+ FileSystemType type;
+ String path;
+ if (!DOMFileSystemBase::crackFileSystemURL(m_url, type, path)) {
+ errorCallback->handleEvent(FileError::create(FileError::SYNTAX_ERR).get());
+ return;
+ }
+
+ if (path == "/") {
+ OwnPtr<AsyncFileSystemCallbacks> fileSystemCallbacks = VoidCallbacks::create(this, errorCallback);
+ LocalFileSystem::localFileSystem().deleteFileSystem(scriptExecutionContext, type, fileSystemCallbacks.release());
+ } else {
+ RefPtr<EntryCallback> successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &DeleteEntryRequest::didGetEntry);
+ OwnPtr<ResolveURICallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, scriptExecutionContext, type, path);
+ LocalFileSystem::localFileSystem().readFileSystem(scriptExecutionContext, type, fileSystemCallbacks.release());
+ }
+}
+
+bool DeleteEntryRequest::didGetEntry(Entry* entry)
+{
+ RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &DeleteEntryRequest::didHitError);
+ if (entry->isDirectory()) {
+ DirectoryEntry* directoryEntry = static_cast<DirectoryEntry*>(entry);
+ directoryEntry->removeRecursively(this, errorCallback);
+ } else
+ entry->remove(this, errorCallback);
+ return true;
+}
+
+bool DeleteEntryRequest::didDeleteEntry()
+{
+ reportResult(static_cast<FileError::ErrorCode>(0));
+ return true;
+}
+
+} // anonymous namespace
+
+// static
+PassOwnPtr<InspectorFileSystemAgent> InspectorFileSystemAgent::create(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* state)
+{
+ return adoptPtr(new InspectorFileSystemAgent(instrumentingAgents, pageAgent, state));
+}
+
+InspectorFileSystemAgent::~InspectorFileSystemAgent()
+{
+ m_instrumentingAgents->setInspectorFileSystemAgent(0);
+}
+
+void InspectorFileSystemAgent::enable(ErrorString*)
+{
+ if (m_enabled)
+ return;
+ m_enabled = true;
+ m_state->setBoolean(FileSystemAgentState::fileSystemAgentEnabled, m_enabled);
+}
+
+void InspectorFileSystemAgent::disable(ErrorString*)
+{
+ if (!m_enabled)
+ return;
+ m_enabled = false;
+ m_state->setBoolean(FileSystemAgentState::fileSystemAgentEnabled, m_enabled);
+}
+
+void InspectorFileSystemAgent::requestFileSystemRoot(ErrorString* error, const String& origin, const String& type, PassRefPtr<RequestFileSystemRootCallback> requestCallback)
+{
+ if (!assertEnabled(error))
+ return;
+
+ ScriptExecutionContext* scriptExecutionContext = assertScriptExecutionContextForOrigin(error, SecurityOrigin::createFromString(origin).get());
+ if (!scriptExecutionContext)
+ return;
+
+ FileSystemRootRequest::create(requestCallback, type)->start(scriptExecutionContext);
+}
+
+void InspectorFileSystemAgent::requestDirectoryContent(ErrorString* error, const String& url, PassRefPtr<RequestDirectoryContentCallback> requestCallback)
+{
+ if (!assertEnabled(error))
+ return;
+
+ ScriptExecutionContext* scriptExecutionContext = assertScriptExecutionContextForOrigin(error, SecurityOrigin::createFromString(url).get());
+ if (!scriptExecutionContext)
+ return;
+
+ DirectoryContentRequest::create(requestCallback, url)->start(scriptExecutionContext);
+}
+
+void InspectorFileSystemAgent::requestMetadata(ErrorString* error, const String& url, PassRefPtr<RequestMetadataCallback> requestCallback)
+{
+ if (!assertEnabled(error))
+ return;
+
+ ScriptExecutionContext* scriptExecutionContext = assertScriptExecutionContextForOrigin(error, SecurityOrigin::createFromString(url).get());
+ if (!scriptExecutionContext)
+ return;
+
+ MetadataRequest::create(requestCallback, url)->start(scriptExecutionContext);
+}
+
+void InspectorFileSystemAgent::requestFileContent(ErrorString* error, const String& url, bool readAsText, const int* start, const int* end, const String* charset, PassRefPtr<RequestFileContentCallback> requestCallback)
+{
+ if (!assertEnabled(error))
+ return;
+
+ ScriptExecutionContext* scriptExecutionContext = assertScriptExecutionContextForOrigin(error, SecurityOrigin::createFromString(url).get());
+ if (!scriptExecutionContext)
+ return;
+
+ long long startPosition = start ? *start : 0;
+ long long endPosition = end ? *end : std::numeric_limits<long long>::max();
+ FileContentRequest::create(requestCallback, url, readAsText, startPosition, endPosition, charset ? *charset : "")->start(scriptExecutionContext);
+}
+
+void InspectorFileSystemAgent::deleteEntry(ErrorString* error, const String& urlString, PassRefPtr<DeleteEntryCallback> requestCallback)
+{
+ if (!assertEnabled(error))
+ return;
+
+ KURL url(ParsedURLString, urlString);
+
+ ScriptExecutionContext* scriptExecutionContext = assertScriptExecutionContextForOrigin(error, SecurityOrigin::create(url).get());
+ if (!scriptExecutionContext)
+ return;
+
+ DeleteEntryRequest::create(requestCallback, url)->start(scriptExecutionContext);
+}
+
+void InspectorFileSystemAgent::clearFrontend()
+{
+ m_enabled = false;
+ m_state->setBoolean(FileSystemAgentState::fileSystemAgentEnabled, m_enabled);
+}
+
+void InspectorFileSystemAgent::restore()
+{
+ m_enabled = m_state->getBoolean(FileSystemAgentState::fileSystemAgentEnabled);
+}
+
+InspectorFileSystemAgent::InspectorFileSystemAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* state)
+ : InspectorBaseAgent<InspectorFileSystemAgent>("FileSystem", instrumentingAgents, state)
+ , m_pageAgent(pageAgent)
+ , m_enabled(false)
+{
+ ASSERT(instrumentingAgents);
+ ASSERT(state);
+ ASSERT(m_pageAgent);
+ m_instrumentingAgents->setInspectorFileSystemAgent(this);
+}
+
+bool InspectorFileSystemAgent::assertEnabled(ErrorString* error)
+{
+ if (!m_enabled) {
+ *error = "FileSystem agent is not enabled.";
+ return false;
+ }
+ return true;
+}
+
+ScriptExecutionContext* InspectorFileSystemAgent::assertScriptExecutionContextForOrigin(ErrorString* error, SecurityOrigin* origin)
+{
+ for (Frame* frame = m_pageAgent->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (frame->document() && frame->document()->securityOrigin()->isSameSchemeHostPort(origin))
+ return frame->document();
+ }
+
+ *error = "No frame is available for the request";
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InspectorFileSystemAgent.h b/Source/core/inspector/InspectorFileSystemAgent.h
new file mode 100644
index 0000000..4b38b8c
--- /dev/null
+++ b/Source/core/inspector/InspectorFileSystemAgent.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011, 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorFileSystemAgent_h
+#define InspectorFileSystemAgent_h
+
+#include "core/inspector/InspectorBaseAgent.h"
+
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class InspectorFrontend;
+class InspectorPageAgent;
+class ScriptExecutionContext;
+class SecurityOrigin;
+
+class InspectorFileSystemAgent : public InspectorBaseAgent<InspectorFileSystemAgent>, public InspectorBackendDispatcher::FileSystemCommandHandler {
+public:
+ static PassOwnPtr<InspectorFileSystemAgent> create(InstrumentingAgents*, InspectorPageAgent*, InspectorCompositeState*);
+ virtual ~InspectorFileSystemAgent();
+
+ virtual void enable(ErrorString*) OVERRIDE;
+ virtual void disable(ErrorString*) OVERRIDE;
+
+ virtual void requestFileSystemRoot(ErrorString*, const String& origin, const String& typeString, PassRefPtr<RequestFileSystemRootCallback>) OVERRIDE;
+ virtual void requestDirectoryContent(ErrorString*, const String& url, PassRefPtr<RequestDirectoryContentCallback>) OVERRIDE;
+ virtual void requestMetadata(ErrorString*, const String& url, PassRefPtr<RequestMetadataCallback>) OVERRIDE;
+ virtual void requestFileContent(ErrorString*, const String& url, bool readAsText, const int* start, const int* end, const String* charset, PassRefPtr<RequestFileContentCallback>) OVERRIDE;
+ virtual void deleteEntry(ErrorString*, const String& url, PassRefPtr<DeleteEntryCallback>) OVERRIDE;
+
+ virtual void clearFrontend() OVERRIDE;
+ virtual void restore() OVERRIDE;
+
+private:
+ InspectorFileSystemAgent(InstrumentingAgents*, InspectorPageAgent*, InspectorCompositeState*);
+ bool assertEnabled(ErrorString*);
+ ScriptExecutionContext* assertScriptExecutionContextForOrigin(ErrorString*, SecurityOrigin*);
+
+ InspectorPageAgent* m_pageAgent;
+ bool m_enabled;
+};
+
+} // namespace WebCore
+
+#endif // InspectorFileSystemAgent_h
diff --git a/Source/core/inspector/InspectorFrontendChannel.h b/Source/core/inspector/InspectorFrontendChannel.h
new file mode 100644
index 0000000..b3214ef
--- /dev/null
+++ b/Source/core/inspector/InspectorFrontendChannel.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 Google 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 COMPUTER, INC. ``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 COMPUTER, INC. OR
+ * 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 InspectorFrontendChannel_h
+#define InspectorFrontendChannel_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class InspectorFrontendChannel {
+public:
+ virtual ~InspectorFrontendChannel() { }
+ virtual bool sendMessageToFrontend(const String& message) = 0;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorFrontendChannel_h)
diff --git a/Source/core/inspector/InspectorFrontendClient.h b/Source/core/inspector/InspectorFrontendClient.h
new file mode 100644
index 0000000..ef6a23c
--- /dev/null
+++ b/Source/core/inspector/InspectorFrontendClient.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorFrontendClient_h
+#define InspectorFrontendClient_h
+
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ContextMenuItem;
+class Event;
+
+class InspectorFrontendClient {
+public:
+ enum DockSide {
+ UNDOCKED = 0,
+ DOCKED_TO_RIGHT,
+ DOCKED_TO_BOTTOM
+ };
+
+ virtual ~InspectorFrontendClient() { }
+
+ virtual void windowObjectCleared() = 0;
+ virtual void moveWindowBy(float x, float y) = 0;
+
+ virtual void bringToFront() = 0;
+ virtual void closeWindow() = 0;
+
+ virtual void requestSetDockSide(DockSide) = 0;
+ virtual void changeAttachedWindowHeight(unsigned) = 0;
+
+ virtual void openInNewTab(const String& url) = 0;
+
+ virtual void save(const WTF::String& url, const WTF::String& content, bool forceSaveAs) = 0;
+ virtual void append(const WTF::String& url, const WTF::String& content) = 0;
+
+ virtual void inspectedURLChanged(const String&) = 0;
+
+ virtual void sendMessageToBackend(const String&) = 0;
+
+ virtual void requestFileSystems() = 0;
+ virtual void addFileSystem() = 0;
+ virtual void removeFileSystem(const String& fileSystemPath) = 0;
+
+ virtual bool isUnderTest() = 0;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/inspector/InspectorFrontendHost.cpp b/Source/core/inspector/InspectorFrontendHost.cpp
new file mode 100644
index 0000000..9881f83
--- /dev/null
+++ b/Source/core/inspector/InspectorFrontendHost.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ *
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InspectorFrontendHost.h"
+
+#include "bindings/v8/DOMWrapperWorld.h"
+#include "bindings/v8/ScriptFunctionCall.h"
+#include "core/dom/Element.h"
+#include "core/dom/UserGestureIndicator.h"
+#include "core/html/HTMLFrameOwnerElement.h"
+#include "core/inspector/InspectorAgent.h"
+#include "core/inspector/InspectorController.h"
+#include "core/inspector/InspectorFrontendClient.h"
+#include "core/loader/FrameLoader.h"
+#include "core/page/ContextMenuController.h"
+#include "core/page/ContextMenuProvider.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/platform/ContextMenu.h"
+#include "core/platform/ContextMenuItem.h"
+#include "core/platform/Pasteboard.h"
+#include "core/platform/network/ResourceError.h"
+#include "core/platform/network/ResourceRequest.h"
+#include "core/platform/network/ResourceResponse.h"
+#include "core/rendering/HitTestResult.h"
+#include "core/rendering/RenderTheme.h"
+#include "modules/filesystem/DOMFileSystem.h"
+#include <wtf/StdLibExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+class FrontendMenuProvider : public ContextMenuProvider {
+public:
+ static PassRefPtr<FrontendMenuProvider> create(InspectorFrontendHost* frontendHost, ScriptObject frontendApiObject, const Vector<ContextMenuItem>& items)
+ {
+ return adoptRef(new FrontendMenuProvider(frontendHost, frontendApiObject, items));
+ }
+
+ void disconnect()
+ {
+ m_frontendApiObject = ScriptObject();
+ m_frontendHost = 0;
+ }
+
+private:
+ FrontendMenuProvider(InspectorFrontendHost* frontendHost, ScriptObject frontendApiObject, const Vector<ContextMenuItem>& items)
+ : m_frontendHost(frontendHost)
+ , m_frontendApiObject(frontendApiObject)
+ , m_items(items)
+ {
+ }
+
+ virtual ~FrontendMenuProvider()
+ {
+ contextMenuCleared();
+ }
+
+ virtual void populateContextMenu(ContextMenu* menu)
+ {
+ for (size_t i = 0; i < m_items.size(); ++i)
+ menu->appendItem(m_items[i]);
+ }
+
+ virtual void contextMenuItemSelected(const ContextMenuItem* item)
+ {
+ if (m_frontendHost) {
+ UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
+ int itemNumber = item->action() - ContextMenuItemBaseCustomTag;
+
+ ScriptFunctionCall function(m_frontendApiObject, "contextMenuItemSelected");
+ function.appendArgument(itemNumber);
+ function.call();
+ }
+ }
+
+ virtual void contextMenuCleared()
+ {
+ if (m_frontendHost) {
+ ScriptFunctionCall function(m_frontendApiObject, "contextMenuCleared");
+ function.call();
+
+ m_frontendHost->m_menuProvider = 0;
+ }
+ m_items.clear();
+ }
+
+ InspectorFrontendHost* m_frontendHost;
+ ScriptObject m_frontendApiObject;
+ Vector<ContextMenuItem> m_items;
+};
+
+InspectorFrontendHost::InspectorFrontendHost(InspectorFrontendClient* client, Page* frontendPage)
+ : m_client(client)
+ , m_frontendPage(frontendPage)
+ , m_menuProvider(0)
+{
+}
+
+InspectorFrontendHost::~InspectorFrontendHost()
+{
+ ASSERT(!m_client);
+}
+
+void InspectorFrontendHost::disconnectClient()
+{
+ m_client = 0;
+ if (m_menuProvider)
+ m_menuProvider->disconnect();
+ m_frontendPage = 0;
+}
+
+void InspectorFrontendHost::loaded()
+{
+}
+
+void InspectorFrontendHost::requestSetDockSide(const String& side)
+{
+ if (!m_client)
+ return;
+ if (side == "undocked")
+ m_client->requestSetDockSide(InspectorFrontendClient::UNDOCKED);
+ else if (side == "right")
+ m_client->requestSetDockSide(InspectorFrontendClient::DOCKED_TO_RIGHT);
+ else if (side == "bottom")
+ m_client->requestSetDockSide(InspectorFrontendClient::DOCKED_TO_BOTTOM);
+}
+
+void InspectorFrontendHost::closeWindow()
+{
+ if (m_client) {
+ m_client->closeWindow();
+ disconnectClient(); // Disconnect from client.
+ }
+}
+
+void InspectorFrontendHost::bringToFront()
+{
+ if (m_client)
+ m_client->bringToFront();
+}
+
+void InspectorFrontendHost::setZoomFactor(float zoom)
+{
+ m_frontendPage->mainFrame()->setPageAndTextZoomFactors(zoom, 1);
+}
+
+void InspectorFrontendHost::inspectedURLChanged(const String& newURL)
+{
+ if (m_client)
+ m_client->inspectedURLChanged(newURL);
+}
+
+void InspectorFrontendHost::setAttachedWindowHeight(unsigned height)
+{
+ if (m_client)
+ m_client->changeAttachedWindowHeight(height);
+}
+
+void InspectorFrontendHost::moveWindowBy(float x, float y) const
+{
+ if (m_client)
+ m_client->moveWindowBy(x, y);
+}
+
+void InspectorFrontendHost::setInjectedScriptForOrigin(const String& origin, const String& script)
+{
+ ASSERT(m_frontendPage->inspectorController());
+ m_frontendPage->inspectorController()->setInjectedScriptForOrigin(origin, script);
+}
+
+String InspectorFrontendHost::localizedStringsURL()
+{
+ return "";
+}
+
+void InspectorFrontendHost::copyText(const String& text)
+{
+ Pasteboard::generalPasteboard()->writePlainText(text, Pasteboard::CannotSmartReplace);
+}
+
+void InspectorFrontendHost::openInNewTab(const String& url)
+{
+ if (m_client)
+ m_client->openInNewTab(url);
+}
+
+bool InspectorFrontendHost::canSave()
+{
+ return true;
+}
+
+void InspectorFrontendHost::save(const String& url, const String& content, bool forceSaveAs)
+{
+ if (m_client)
+ m_client->save(url, content, forceSaveAs);
+}
+
+void InspectorFrontendHost::append(const String& url, const String& content)
+{
+ if (m_client)
+ m_client->append(url, content);
+}
+
+void InspectorFrontendHost::close(const String&)
+{
+}
+
+void InspectorFrontendHost::sendMessageToBackend(const String& message)
+{
+ if (m_client)
+ m_client->sendMessageToBackend(message);
+}
+
+void InspectorFrontendHost::showContextMenu(Event* event, const Vector<ContextMenuItem>& items)
+{
+ if (!event)
+ return;
+
+ ASSERT(m_frontendPage);
+ ScriptState* frontendScriptState = scriptStateFromPage(debuggerWorld(), m_frontendPage);
+ ScriptObject frontendApiObject;
+ if (!ScriptGlobalObject::get(frontendScriptState, "InspectorFrontendAPI", frontendApiObject)) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ RefPtr<FrontendMenuProvider> menuProvider = FrontendMenuProvider::create(this, frontendApiObject, items);
+ ContextMenuController* menuController = m_frontendPage->contextMenuController();
+ menuController->showContextMenu(event, menuProvider);
+ m_menuProvider = menuProvider.get();
+}
+
+String InspectorFrontendHost::loadResourceSynchronously(const String& url)
+{
+ ResourceRequest request(url);
+ request.setHTTPMethod("GET");
+
+ Vector<char> data;
+ ResourceError error;
+ ResourceResponse response;
+ m_frontendPage->mainFrame()->loader()->loadResourceSynchronously(request, DoNotAllowStoredCredentials, error, response, data);
+ return String(data.data(), data.size());
+}
+
+String InspectorFrontendHost::getSelectionBackgroundColor()
+{
+ Color color = m_frontendPage->theme()->activeSelectionBackgroundColor();
+ return color.isValid() ? color.serialized() : "";
+}
+
+String InspectorFrontendHost::getSelectionForegroundColor()
+{
+ Color color = m_frontendPage->theme()->activeSelectionForegroundColor();
+ return color.isValid() ? color.serialized() : "";
+}
+
+bool InspectorFrontendHost::supportsFileSystems()
+{
+ return true;
+}
+
+void InspectorFrontendHost::requestFileSystems()
+{
+ if (m_client)
+ m_client->requestFileSystems();
+}
+
+void InspectorFrontendHost::addFileSystem()
+{
+ if (m_client)
+ m_client->addFileSystem();
+}
+
+void InspectorFrontendHost::removeFileSystem(const String& fileSystemPath)
+{
+ if (m_client)
+ m_client->removeFileSystem(fileSystemPath);
+}
+
+PassRefPtr<DOMFileSystem> InspectorFrontendHost::isolatedFileSystem(const String& fileSystemName, const String& rootURL)
+{
+ ScriptExecutionContext* context = m_frontendPage->mainFrame()->document();
+ return DOMFileSystem::create(context, fileSystemName, FileSystemTypeIsolated, KURL(ParsedURLString, rootURL), AsyncFileSystem::create());
+}
+
+bool InspectorFrontendHost::isUnderTest()
+{
+ return m_client && m_client->isUnderTest();
+}
+
+bool InspectorFrontendHost::canSaveAs()
+{
+ return false;
+}
+
+bool InspectorFrontendHost::canInspectWorkers()
+{
+ return false;
+}
+
+String InspectorFrontendHost::hiddenPanels()
+{
+ return "";
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InspectorFrontendHost.h b/Source/core/inspector/InspectorFrontendHost.h
new file mode 100644
index 0000000..f7682e8
--- /dev/null
+++ b/Source/core/inspector/InspectorFrontendHost.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorFrontendHost_h
+#define InspectorFrontendHost_h
+
+#include "core/page/ConsoleTypes.h"
+#include "core/page/ContextMenuProvider.h"
+#include "core/platform/ContextMenu.h"
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ContextMenuItem;
+class DOMFileSystem;
+class Event;
+class FrontendMenuProvider;
+class InspectorClient;
+class InspectorFrontendClient;
+class Node;
+class Page;
+
+class InspectorFrontendHost : public RefCounted<InspectorFrontendHost> {
+public:
+ static PassRefPtr<InspectorFrontendHost> create(InspectorFrontendClient* client, Page* frontendPage)
+ {
+ return adoptRef(new InspectorFrontendHost(client, frontendPage));
+ }
+
+ ~InspectorFrontendHost();
+ void disconnectClient();
+
+ void requestSetDockSide(const String&);
+ void closeWindow();
+ void bringToFront();
+ void setZoomFactor(float);
+ void inspectedURLChanged(const String&);
+
+ void setAttachedWindowHeight(unsigned);
+ void moveWindowBy(float x, float y) const;
+ void setInjectedScriptForOrigin(const String& origin, const String& script);
+
+ void copyText(const String& text);
+ void openInNewTab(const String& url);
+ void save(const String& url, const String& content, bool forceSaveAs);
+ void append(const String& url, const String& content);
+ void close(const String& url);
+
+ // Called from [Custom] implementations.
+ void showContextMenu(Event*, const Vector<ContextMenuItem>& items);
+ void sendMessageToBackend(const String& message);
+
+ String loadResourceSynchronously(const String& url);
+ String getSelectionBackgroundColor();
+ String getSelectionForegroundColor();
+
+ void requestFileSystems();
+ void addFileSystem();
+ void removeFileSystem(const String& fileSystemPath);
+ PassRefPtr<DOMFileSystem> isolatedFileSystem(const String& fileSystemName, const String& rootURL);
+
+ bool isUnderTest();
+
+ // Deprecated but should stay around for a while as old front-ends may use them.
+ bool canInspectWorkers();
+ bool canSaveAs();
+ bool canSave();
+ bool supportsFileSystems();
+ void loaded();
+ String hiddenPanels();
+ String localizedStringsURL();
+
+private:
+ friend class FrontendMenuProvider;
+ InspectorFrontendHost(InspectorFrontendClient* client, Page* frontendPage);
+
+ InspectorFrontendClient* m_client;
+ Page* m_frontendPage;
+ FrontendMenuProvider* m_menuProvider;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorFrontendHost_h)
diff --git a/Source/core/inspector/InspectorFrontendHost.idl b/Source/core/inspector/InspectorFrontendHost.idl
new file mode 100644
index 0000000..2ebcf0a
--- /dev/null
+++ b/Source/core/inspector/InspectorFrontendHost.idl
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+[
+ ImplementationLacksVTable
+] interface InspectorFrontendHost {
+ void closeWindow();
+ void bringToFront();
+ void setZoomFactor(float zoom);
+ void inspectedURLChanged(DOMString newURL);
+
+ void requestSetDockSide(DOMString side);
+ void setAttachedWindowHeight(unsigned long height);
+ void moveWindowBy(float x, float y);
+ void setInjectedScriptForOrigin(DOMString origin, DOMString script);
+
+ void copyText(DOMString text);
+ void openInNewTab(DOMString url);
+ void save(DOMString url, DOMString content, boolean forceSaveAs);
+ void append(DOMString url, DOMString content);
+ void close(DOMString url);
+
+ [Custom] DOMString platform();
+ [Custom] DOMString port();
+ [Custom] void showContextMenu(MouseEvent event, any items);
+ void sendMessageToBackend(DOMString message);
+
+ [Custom] void recordActionTaken(unsigned long actionCode);
+ [Custom] void recordPanelShown(unsigned long panelCode);
+ [Custom] void recordSettingChanged(unsigned long settingChanged);
+
+ DOMString loadResourceSynchronously(DOMString url);
+ DOMString getSelectionBackgroundColor();
+ DOMString getSelectionForegroundColor();
+
+ void requestFileSystems();
+ void addFileSystem();
+ void removeFileSystem(DOMString fileSystemPath);
+ DOMFileSystem isolatedFileSystem(DOMString fileSystemId, DOMString registeredName);
+
+ boolean isUnderTest();
+
+ // Deprecated
+ boolean canInspectWorkers();
+ boolean canSaveAs();
+ boolean canSave();
+ boolean supportsFileSystems();
+ void loaded();
+ DOMString hiddenPanels();
+ DOMString localizedStringsURL();
+};
diff --git a/Source/core/inspector/InspectorHeapProfilerAgent.cpp b/Source/core/inspector/InspectorHeapProfilerAgent.cpp
new file mode 100644
index 0000000..0653db9
--- /dev/null
+++ b/Source/core/inspector/InspectorHeapProfilerAgent.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2013 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorHeapProfilerAgent.h"
+
+#include "bindings/v8/ScriptProfiler.h"
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptHost.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/platform/Timer.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/MemoryInstrumentationHashMap.h>
+
+namespace WebCore {
+
+namespace HeapProfilerAgentState {
+static const char profileHeadersRequested[] = "profileHeadersRequested";
+}
+
+static const char* const UserInitiatedProfileNameHeap = "org.webkit.profiles.user-initiated";
+
+class InspectorHeapProfilerAgent::HeapStatsUpdateTask {
+public:
+ HeapStatsUpdateTask(InspectorHeapProfilerAgent*);
+ void startTimer();
+ void resetTimer() { m_timer.stop(); }
+ void onTimer(Timer<HeapStatsUpdateTask>*);
+
+private:
+ InspectorHeapProfilerAgent* m_heapProfilerAgent;
+ Timer<HeapStatsUpdateTask> m_timer;
+};
+
+PassOwnPtr<InspectorHeapProfilerAgent> InspectorHeapProfilerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager)
+{
+ return adoptPtr(new InspectorHeapProfilerAgent(instrumentingAgents, inspectorState, injectedScriptManager));
+}
+
+InspectorHeapProfilerAgent::InspectorHeapProfilerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager)
+ : InspectorBaseAgent<InspectorHeapProfilerAgent>("HeapProfiler", instrumentingAgents, inspectorState)
+ , m_injectedScriptManager(injectedScriptManager)
+ , m_frontend(0)
+ , m_nextUserInitiatedHeapSnapshotNumber(1)
+{
+ m_instrumentingAgents->setInspectorHeapProfilerAgent(this);
+}
+
+InspectorHeapProfilerAgent::~InspectorHeapProfilerAgent()
+{
+ m_instrumentingAgents->setInspectorHeapProfilerAgent(0);
+}
+
+void InspectorHeapProfilerAgent::clearProfiles(ErrorString*)
+{
+ m_snapshots.clear();
+ m_nextUserInitiatedHeapSnapshotNumber = 1;
+ resetFrontendProfiles();
+ m_injectedScriptManager->injectedScriptHost()->clearInspectedObjects();
+}
+
+void InspectorHeapProfilerAgent::resetFrontendProfiles()
+{
+ stopTrackingHeapObjects(0);
+ if (!m_frontend)
+ return;
+ if (!m_state->getBoolean(HeapProfilerAgentState::profileHeadersRequested))
+ return;
+ if (m_snapshots.isEmpty())
+ m_frontend->resetProfiles();
+}
+
+void InspectorHeapProfilerAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->heapprofiler();
+}
+
+void InspectorHeapProfilerAgent::clearFrontend()
+{
+ m_state->setBoolean(HeapProfilerAgentState::profileHeadersRequested, false);
+ m_frontend = 0;
+}
+
+void InspectorHeapProfilerAgent::restore()
+{
+ resetFrontendProfiles();
+}
+
+void InspectorHeapProfilerAgent::collectGarbage(WebCore::ErrorString*)
+{
+ ScriptProfiler::collectGarbage();
+}
+
+PassRefPtr<TypeBuilder::HeapProfiler::ProfileHeader> InspectorHeapProfilerAgent::createSnapshotHeader(const ScriptHeapSnapshot& snapshot)
+{
+ RefPtr<TypeBuilder::HeapProfiler::ProfileHeader> header = TypeBuilder::HeapProfiler::ProfileHeader::create()
+ .setUid(snapshot.uid())
+ .setTitle(snapshot.title());
+ header->setMaxJSObjectId(snapshot.maxSnapshotJSObjectId());
+ return header.release();
+}
+
+InspectorHeapProfilerAgent::HeapStatsUpdateTask::HeapStatsUpdateTask(InspectorHeapProfilerAgent* heapProfilerAgent)
+ : m_heapProfilerAgent(heapProfilerAgent)
+ , m_timer(this, &HeapStatsUpdateTask::onTimer)
+{
+}
+
+void InspectorHeapProfilerAgent::HeapStatsUpdateTask::onTimer(Timer<HeapStatsUpdateTask>*)
+{
+ // The timer is stopped on m_heapProfilerAgent destruction,
+ // so this method will never be called after m_heapProfilerAgent has been destroyed.
+ m_heapProfilerAgent->requestHeapStatsUpdate();
+}
+
+void InspectorHeapProfilerAgent::HeapStatsUpdateTask::startTimer()
+{
+ ASSERT(!m_timer.isActive());
+ m_timer.startRepeating(0.05);
+}
+
+class InspectorHeapProfilerAgent::HeapStatsStream : public ScriptProfiler::OutputStream {
+public:
+ HeapStatsStream(InspectorHeapProfilerAgent* heapProfilerAgent)
+ : m_heapProfilerAgent(heapProfilerAgent)
+ {
+ }
+
+ virtual void write(const uint32_t* chunk, const int size) OVERRIDE
+ {
+ ASSERT(chunk);
+ ASSERT(size > 0);
+ m_heapProfilerAgent->pushHeapStatsUpdate(chunk, size);
+ }
+private:
+ InspectorHeapProfilerAgent* m_heapProfilerAgent;
+};
+
+void InspectorHeapProfilerAgent::startTrackingHeapObjects(ErrorString*)
+{
+ if (m_heapStatsUpdateTask)
+ return;
+ ScriptProfiler::startTrackingHeapObjects();
+ m_heapStatsUpdateTask = adoptPtr(new HeapStatsUpdateTask(this));
+ m_heapStatsUpdateTask->startTimer();
+}
+
+void InspectorHeapProfilerAgent::requestHeapStatsUpdate()
+{
+ if (!m_frontend)
+ return;
+ HeapStatsStream stream(this);
+ SnapshotObjectId lastSeenObjectId = ScriptProfiler::requestHeapStatsUpdate(&stream);
+ m_frontend->lastSeenObjectId(lastSeenObjectId, WTF::currentTimeMS());
+}
+
+void InspectorHeapProfilerAgent::pushHeapStatsUpdate(const uint32_t* const data, const int size)
+{
+ if (!m_frontend)
+ return;
+ RefPtr<TypeBuilder::Array<int> > statsDiff = TypeBuilder::Array<int>::create();
+ for (int i = 0; i < size; ++i)
+ statsDiff->addItem(data[i]);
+ m_frontend->heapStatsUpdate(statsDiff.release());
+}
+
+void InspectorHeapProfilerAgent::stopTrackingHeapObjects(ErrorString*)
+{
+ if (!m_heapStatsUpdateTask)
+ return;
+ ScriptProfiler::stopTrackingHeapObjects();
+ m_heapStatsUpdateTask->resetTimer();
+ m_heapStatsUpdateTask.clear();
+}
+
+void InspectorHeapProfilerAgent::getProfileHeaders(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::HeapProfiler::ProfileHeader> >& headers)
+{
+ m_state->setBoolean(HeapProfilerAgentState::profileHeadersRequested, true);
+ headers = TypeBuilder::Array<TypeBuilder::HeapProfiler::ProfileHeader>::create();
+
+ IdToHeapSnapshotMap::iterator snapshotsEnd = m_snapshots.end();
+ for (IdToHeapSnapshotMap::iterator it = m_snapshots.begin(); it != snapshotsEnd; ++it)
+ headers->addItem(createSnapshotHeader(*it->value));
+}
+
+void InspectorHeapProfilerAgent::getHeapSnapshot(ErrorString* errorString, int rawUid)
+{
+ class OutputStream : public ScriptHeapSnapshot::OutputStream {
+ public:
+ OutputStream(InspectorFrontend::HeapProfiler* frontend, unsigned uid)
+ : m_frontend(frontend), m_uid(uid) { }
+ void Write(const String& chunk) { m_frontend->addHeapSnapshotChunk(m_uid, chunk); }
+ void Close() { m_frontend->finishHeapSnapshot(m_uid); }
+ private:
+ InspectorFrontend::HeapProfiler* m_frontend;
+ int m_uid;
+ };
+
+ unsigned uid = static_cast<unsigned>(rawUid);
+ IdToHeapSnapshotMap::iterator it = m_snapshots.find(uid);
+ if (it == m_snapshots.end()) {
+ *errorString = "Profile wasn't found";
+ return;
+ }
+ RefPtr<ScriptHeapSnapshot> snapshot = it->value;
+ if (m_frontend) {
+ OutputStream stream(m_frontend, uid);
+ snapshot->writeJSON(&stream);
+ }
+}
+
+void InspectorHeapProfilerAgent::removeProfile(ErrorString*, int rawUid)
+{
+ unsigned uid = static_cast<unsigned>(rawUid);
+ if (m_snapshots.contains(uid))
+ m_snapshots.remove(uid);
+}
+
+void InspectorHeapProfilerAgent::takeHeapSnapshot(ErrorString*, const bool* reportProgress)
+{
+ class HeapSnapshotProgress: public ScriptProfiler::HeapSnapshotProgress {
+ public:
+ explicit HeapSnapshotProgress(InspectorFrontend::HeapProfiler* frontend)
+ : m_frontend(frontend) { }
+ void Start(int totalWork)
+ {
+ m_totalWork = totalWork;
+ }
+ void Worked(int workDone)
+ {
+ if (m_frontend)
+ m_frontend->reportHeapSnapshotProgress(workDone, m_totalWork);
+ }
+ void Done() { }
+ bool isCanceled() { return false; }
+ private:
+ InspectorFrontend::HeapProfiler* m_frontend;
+ int m_totalWork;
+ };
+
+ String title = makeString(UserInitiatedProfileNameHeap, '.', String::number(m_nextUserInitiatedHeapSnapshotNumber));
+ ++m_nextUserInitiatedHeapSnapshotNumber;
+
+ HeapSnapshotProgress progress(reportProgress && *reportProgress ? m_frontend : 0);
+ RefPtr<ScriptHeapSnapshot> snapshot = ScriptProfiler::takeHeapSnapshot(title, &progress);
+ if (snapshot) {
+ m_snapshots.add(snapshot->uid(), snapshot);
+ if (m_frontend)
+ m_frontend->addProfileHeader(createSnapshotHeader(*snapshot));
+ }
+}
+
+void InspectorHeapProfilerAgent::getObjectByHeapObjectId(ErrorString* error, const String& heapSnapshotObjectId, const String* objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result)
+{
+ bool ok;
+ unsigned id = heapSnapshotObjectId.toUInt(&ok);
+ if (!ok) {
+ *error = "Invalid heap snapshot object id";
+ return;
+ }
+ ScriptObject heapObject = ScriptProfiler::objectByHeapObjectId(id);
+ if (heapObject.hasNoValue()) {
+ *error = "Object is not available";
+ return;
+ }
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(heapObject.scriptState());
+ if (injectedScript.hasNoValue()) {
+ *error = "Object is not available. Inspected context is gone";
+ return;
+ }
+ result = injectedScript.wrapObject(heapObject, objectGroup ? *objectGroup : "");
+ if (!result)
+ *error = "Failed to wrap object";
+}
+
+void InspectorHeapProfilerAgent::getHeapObjectId(ErrorString* errorString, const String& objectId, String* heapSnapshotObjectId)
+{
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected context has gone";
+ return;
+ }
+ ScriptValue value = injectedScript.findObjectById(objectId);
+ if (value.hasNoValue() || value.isUndefined()) {
+ *errorString = "Object with given id not found";
+ return;
+ }
+ unsigned id = ScriptProfiler::getHeapObjectId(value);
+ *heapSnapshotObjectId = String::number(id);
+}
+
+void InspectorHeapProfilerAgent::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorProfilerAgent);
+ InspectorBaseAgent<InspectorHeapProfilerAgent>::reportMemoryUsage(memoryObjectInfo);
+ info.addMember(m_injectedScriptManager, "injectedScriptManager");
+ info.addWeakPointer(m_frontend);
+ info.addMember(m_snapshots, "snapshots");
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorHeapProfilerAgent.h b/Source/core/inspector/InspectorHeapProfilerAgent.h
new file mode 100644
index 0000000..03ac560
--- /dev/null
+++ b/Source/core/inspector/InspectorHeapProfilerAgent.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2013 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorHeapProfilerAgent_h
+#define InspectorHeapProfilerAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class HeapObjectsStatsStream;
+class InjectedScriptManager;
+class HeapStatsUpdateTask;
+class ScriptHeapSnapshot;
+class ScriptProfile;
+
+typedef String ErrorString;
+
+class InspectorHeapProfilerAgent : public InspectorBaseAgent<InspectorHeapProfilerAgent>, public InspectorBackendDispatcher::HeapProfilerCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorHeapProfilerAgent); WTF_MAKE_FAST_ALLOCATED;
+public:
+ static PassOwnPtr<InspectorHeapProfilerAgent> create(InstrumentingAgents*, InspectorCompositeState*, InjectedScriptManager*);
+ virtual ~InspectorHeapProfilerAgent();
+
+ virtual void collectGarbage(ErrorString*);
+ virtual void clearProfiles(ErrorString*);
+
+ virtual void getProfileHeaders(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::HeapProfiler::ProfileHeader> >&);
+ virtual void getHeapSnapshot(ErrorString*, int uid);
+ virtual void removeProfile(ErrorString*, int uid);
+ virtual void startTrackingHeapObjects(ErrorString*);
+ virtual void stopTrackingHeapObjects(ErrorString*);
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ virtual void takeHeapSnapshot(ErrorString*, const bool* reportProgress);
+
+ virtual void getObjectByHeapObjectId(ErrorString*, const String& heapSnapshotObjectId, const String* objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result);
+ virtual void getHeapObjectId(ErrorString*, const String& objectId, String* heapSnapshotObjectId);
+
+ virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+
+
+private:
+ class HeapStatsStream;
+ class HeapStatsUpdateTask;
+
+ InspectorHeapProfilerAgent(InstrumentingAgents*, InspectorCompositeState*, InjectedScriptManager*);
+
+ typedef HashMap<unsigned, RefPtr<ScriptHeapSnapshot> > IdToHeapSnapshotMap;
+
+ void resetFrontendProfiles();
+ void requestHeapStatsUpdate();
+ void pushHeapStatsUpdate(const uint32_t* const data, const int size);
+
+ PassRefPtr<TypeBuilder::HeapProfiler::ProfileHeader> createSnapshotHeader(const ScriptHeapSnapshot&);
+
+ InjectedScriptManager* m_injectedScriptManager;
+ InspectorFrontend::HeapProfiler* m_frontend;
+ unsigned m_nextUserInitiatedHeapSnapshotNumber;
+ IdToHeapSnapshotMap m_snapshots;
+ OwnPtr<HeapStatsUpdateTask> m_heapStatsUpdateTask;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorHeapProfilerAgent_h)
diff --git a/Source/core/inspector/InspectorHistory.cpp b/Source/core/inspector/InspectorHistory.cpp
new file mode 100644
index 0000000..565c142
--- /dev/null
+++ b/Source/core/inspector/InspectorHistory.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorHistory.h"
+
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/Node.h"
+
+namespace WebCore {
+
+namespace {
+
+class UndoableStateMark : public InspectorHistory::Action {
+public:
+ UndoableStateMark() : InspectorHistory::Action("[UndoableState]") { }
+
+ virtual bool perform(ExceptionCode&) { return true; }
+
+ virtual bool undo(ExceptionCode&) { return true; }
+
+ virtual bool redo(ExceptionCode&) { return true; }
+
+ virtual bool isUndoableStateMark() { return true; }
+};
+
+}
+
+InspectorHistory::Action::Action(const String& name) : m_name(name)
+{
+}
+
+InspectorHistory::Action::~Action()
+{
+}
+
+String InspectorHistory::Action::toString()
+{
+ return m_name;
+}
+
+bool InspectorHistory::Action::isUndoableStateMark()
+{
+ return false;
+}
+
+String InspectorHistory::Action::mergeId()
+{
+ return "";
+}
+
+void InspectorHistory::Action::merge(PassOwnPtr<Action>)
+{
+}
+
+InspectorHistory::InspectorHistory() : m_afterLastActionIndex(0) { }
+
+InspectorHistory::~InspectorHistory() { }
+
+bool InspectorHistory::perform(PassOwnPtr<Action> action, ExceptionCode& ec)
+{
+ if (!action->perform(ec))
+ return false;
+
+ if (!action->mergeId().isEmpty() && m_afterLastActionIndex > 0 && action->mergeId() == m_history[m_afterLastActionIndex - 1]->mergeId())
+ m_history[m_afterLastActionIndex - 1]->merge(action);
+ else {
+ m_history.resize(m_afterLastActionIndex);
+ m_history.append(action);
+ ++m_afterLastActionIndex;
+ }
+ return true;
+}
+
+void InspectorHistory::markUndoableState()
+{
+ perform(adoptPtr(new UndoableStateMark()), IGNORE_EXCEPTION);
+}
+
+bool InspectorHistory::undo(ExceptionCode& ec)
+{
+ while (m_afterLastActionIndex > 0 && m_history[m_afterLastActionIndex - 1]->isUndoableStateMark())
+ --m_afterLastActionIndex;
+
+ while (m_afterLastActionIndex > 0) {
+ Action* action = m_history[m_afterLastActionIndex - 1].get();
+ if (!action->undo(ec)) {
+ reset();
+ return false;
+ }
+ --m_afterLastActionIndex;
+ if (action->isUndoableStateMark())
+ break;
+ }
+
+ return true;
+}
+
+bool InspectorHistory::redo(ExceptionCode& ec)
+{
+ while (m_afterLastActionIndex < m_history.size() && m_history[m_afterLastActionIndex]->isUndoableStateMark())
+ ++m_afterLastActionIndex;
+
+ while (m_afterLastActionIndex < m_history.size()) {
+ Action* action = m_history[m_afterLastActionIndex].get();
+ if (!action->redo(ec)) {
+ reset();
+ return false;
+ }
+ ++m_afterLastActionIndex;
+ if (action->isUndoableStateMark())
+ break;
+ }
+ return true;
+}
+
+void InspectorHistory::reset()
+{
+ m_afterLastActionIndex = 0;
+ m_history.clear();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorHistory.h b/Source/core/inspector/InspectorHistory.h
new file mode 100644
index 0000000..36504ce
--- /dev/null
+++ b/Source/core/inspector/InspectorHistory.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorHistory_h
+#define InspectorHistory_h
+
+#include "core/dom/ExceptionCode.h"
+
+#include <wtf/OwnPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ContainerNode;
+class Element;
+class Node;
+
+
+class InspectorHistory {
+ WTF_MAKE_NONCOPYABLE(InspectorHistory); WTF_MAKE_FAST_ALLOCATED;
+public:
+ class Action {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ Action(const String& name);
+ virtual ~Action();
+ virtual String toString();
+
+ virtual String mergeId();
+ virtual void merge(PassOwnPtr<Action>);
+
+ virtual bool perform(ExceptionCode&) = 0;
+
+ virtual bool undo(ExceptionCode&) = 0;
+ virtual bool redo(ExceptionCode&) = 0;
+
+ virtual bool isUndoableStateMark();
+ private:
+ String m_name;
+ };
+
+ InspectorHistory();
+ virtual ~InspectorHistory();
+
+ bool perform(PassOwnPtr<Action>, ExceptionCode&);
+ void markUndoableState();
+
+ bool undo(ExceptionCode&);
+ bool redo(ExceptionCode&);
+ void reset();
+
+private:
+ Vector<OwnPtr<Action> > m_history;
+ size_t m_afterLastActionIndex;
+};
+
+
+} // namespace WebCore
+
+#endif // !defined(InspectorHistory_h)
diff --git a/Source/core/inspector/InspectorIndexedDBAgent.cpp b/Source/core/inspector/InspectorIndexedDBAgent.cpp
new file mode 100644
index 0000000..9eafcf6
--- /dev/null
+++ b/Source/core/inspector/InspectorIndexedDBAgent.cpp
@@ -0,0 +1,792 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorIndexedDBAgent.h"
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/DOMStringList.h"
+#include "core/dom/Document.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventListener.h"
+#include "core/dom/EventTarget.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/SecurityOrigin.h"
+#include "modules/indexeddb/DOMWindowIndexedDatabase.h"
+#include "modules/indexeddb/IDBCursor.h"
+#include "modules/indexeddb/IDBCursorWithValue.h"
+#include "modules/indexeddb/IDBDatabase.h"
+#include "modules/indexeddb/IDBDatabaseCallbacks.h"
+#include "modules/indexeddb/IDBFactory.h"
+#include "modules/indexeddb/IDBIndex.h"
+#include "modules/indexeddb/IDBKey.h"
+#include "modules/indexeddb/IDBKeyPath.h"
+#include "modules/indexeddb/IDBKeyRange.h"
+#include "modules/indexeddb/IDBMetadata.h"
+#include "modules/indexeddb/IDBObjectStore.h"
+#include "modules/indexeddb/IDBOpenDBRequest.h"
+#include "modules/indexeddb/IDBPendingTransactionMonitor.h"
+#include "modules/indexeddb/IDBRequest.h"
+#include "modules/indexeddb/IDBTransaction.h"
+
+#include <wtf/Vector.h>
+
+using WebCore::TypeBuilder::Array;
+using WebCore::TypeBuilder::IndexedDB::DatabaseWithObjectStores;
+using WebCore::TypeBuilder::IndexedDB::DataEntry;
+using WebCore::TypeBuilder::IndexedDB::Key;
+using WebCore::TypeBuilder::IndexedDB::KeyPath;
+using WebCore::TypeBuilder::IndexedDB::KeyRange;
+using WebCore::TypeBuilder::IndexedDB::ObjectStore;
+using WebCore::TypeBuilder::IndexedDB::ObjectStoreIndex;
+
+typedef WebCore::InspectorBackendDispatcher::IndexedDBCommandHandler::RequestDatabaseNamesCallback RequestDatabaseNamesCallback;
+typedef WebCore::InspectorBackendDispatcher::IndexedDBCommandHandler::RequestDatabaseCallback RequestDatabaseCallback;
+typedef WebCore::InspectorBackendDispatcher::IndexedDBCommandHandler::RequestDataCallback RequestDataCallback;
+typedef WebCore::InspectorBackendDispatcher::CallbackBase RequestCallback;
+typedef WebCore::InspectorBackendDispatcher::IndexedDBCommandHandler::ClearObjectStoreCallback ClearObjectStoreCallback;
+
+namespace WebCore {
+
+namespace IndexedDBAgentState {
+static const char indexedDBAgentEnabled[] = "indexedDBAgentEnabled";
+};
+
+namespace {
+
+class GetDatabaseNamesCallback : public EventListener {
+ WTF_MAKE_NONCOPYABLE(GetDatabaseNamesCallback);
+public:
+ static PassRefPtr<GetDatabaseNamesCallback> create(PassRefPtr<RequestDatabaseNamesCallback> requestCallback, const String& securityOrigin)
+ {
+ return adoptRef(new GetDatabaseNamesCallback(requestCallback, securityOrigin));
+ }
+
+ virtual ~GetDatabaseNamesCallback() { }
+
+ virtual bool operator==(const EventListener& other) OVERRIDE
+ {
+ return this == &other;
+ }
+
+ virtual void handleEvent(ScriptExecutionContext*, Event* event) OVERRIDE
+ {
+ if (!m_requestCallback->isActive())
+ return;
+ if (event->type() != eventNames().successEvent) {
+ m_requestCallback->sendFailure("Unexpected event type.");
+ return;
+ }
+
+ IDBRequest* idbRequest = static_cast<IDBRequest*>(event->target());
+ ExceptionCode ec = 0;
+ RefPtr<IDBAny> requestResult = idbRequest->result(ec);
+ if (ec) {
+ m_requestCallback->sendFailure("Could not get result in callback.");
+ return;
+ }
+ if (requestResult->type() != IDBAny::DOMStringListType) {
+ m_requestCallback->sendFailure("Unexpected result type.");
+ return;
+ }
+
+ RefPtr<DOMStringList> databaseNamesList = requestResult->domStringList();
+ RefPtr<TypeBuilder::Array<String> > databaseNames = TypeBuilder::Array<String>::create();
+ for (size_t i = 0; i < databaseNamesList->length(); ++i)
+ databaseNames->addItem(databaseNamesList->item(i));
+ m_requestCallback->sendSuccess(databaseNames.release());
+ }
+
+private:
+ GetDatabaseNamesCallback(PassRefPtr<RequestDatabaseNamesCallback> requestCallback, const String& securityOrigin)
+ : EventListener(EventListener::CPPEventListenerType)
+ , m_requestCallback(requestCallback)
+ , m_securityOrigin(securityOrigin) { }
+ RefPtr<RequestDatabaseNamesCallback> m_requestCallback;
+ String m_securityOrigin;
+};
+
+class ExecutableWithDatabase : public RefCounted<ExecutableWithDatabase> {
+public:
+ ExecutableWithDatabase(ScriptExecutionContext* context)
+ : m_context(context) { }
+ virtual ~ExecutableWithDatabase() { };
+ void start(IDBFactory*, SecurityOrigin*, const String& databaseName);
+ virtual void execute(PassRefPtr<IDBDatabase>) = 0;
+ virtual RequestCallback* requestCallback() = 0;
+ ScriptExecutionContext* context() { return m_context; };
+private:
+ ScriptExecutionContext* m_context;
+};
+
+class OpenDatabaseCallback : public EventListener {
+public:
+ static PassRefPtr<OpenDatabaseCallback> create(ExecutableWithDatabase* executableWithDatabase)
+ {
+ return adoptRef(new OpenDatabaseCallback(executableWithDatabase));
+ }
+
+ virtual ~OpenDatabaseCallback() { }
+
+ virtual bool operator==(const EventListener& other) OVERRIDE
+ {
+ return this == &other;
+ }
+
+ virtual void handleEvent(ScriptExecutionContext*, Event* event) OVERRIDE
+ {
+ if (event->type() != eventNames().successEvent) {
+ m_executableWithDatabase->requestCallback()->sendFailure("Unexpected event type.");
+ return;
+ }
+
+ IDBOpenDBRequest* idbOpenDBRequest = static_cast<IDBOpenDBRequest*>(event->target());
+ ExceptionCode ec = 0;
+ RefPtr<IDBAny> requestResult = idbOpenDBRequest->result(ec);
+ if (ec) {
+ m_executableWithDatabase->requestCallback()->sendFailure("Could not get result in callback.");
+ return;
+ }
+ if (requestResult->type() != IDBAny::IDBDatabaseType) {
+ m_executableWithDatabase->requestCallback()->sendFailure("Unexpected result type.");
+ return;
+ }
+
+ RefPtr<IDBDatabase> idbDatabase = requestResult->idbDatabase();
+ m_executableWithDatabase->execute(idbDatabase);
+ IDBPendingTransactionMonitor::deactivateNewTransactions();
+ idbDatabase->close();
+ }
+
+private:
+ OpenDatabaseCallback(ExecutableWithDatabase* executableWithDatabase)
+ : EventListener(EventListener::CPPEventListenerType)
+ , m_executableWithDatabase(executableWithDatabase) { }
+ RefPtr<ExecutableWithDatabase> m_executableWithDatabase;
+};
+
+void ExecutableWithDatabase::start(IDBFactory* idbFactory, SecurityOrigin*, const String& databaseName)
+{
+ RefPtr<OpenDatabaseCallback> callback = OpenDatabaseCallback::create(this);
+ ExceptionCode ec = 0;
+ RefPtr<IDBOpenDBRequest> idbOpenDBRequest = idbFactory->open(context(), databaseName, ec);
+ if (ec) {
+ requestCallback()->sendFailure("Could not open database.");
+ return;
+ }
+ idbOpenDBRequest->addEventListener(eventNames().successEvent, callback, false);
+}
+
+static PassRefPtr<IDBTransaction> transactionForDatabase(ScriptExecutionContext* scriptExecutionContext, IDBDatabase* idbDatabase, const String& objectStoreName, const String& mode = IDBTransaction::modeReadOnly())
+{
+ ExceptionCode ec = 0;
+ RefPtr<IDBTransaction> idbTransaction = idbDatabase->transaction(scriptExecutionContext, objectStoreName, mode, ec);
+ if (ec)
+ return 0;
+ return idbTransaction;
+}
+
+static PassRefPtr<IDBObjectStore> objectStoreForTransaction(IDBTransaction* idbTransaction, const String& objectStoreName)
+{
+ ExceptionCode ec = 0;
+ RefPtr<IDBObjectStore> idbObjectStore = idbTransaction->objectStore(objectStoreName, ec);
+ if (ec)
+ return 0;
+ return idbObjectStore;
+}
+
+static PassRefPtr<IDBIndex> indexForObjectStore(IDBObjectStore* idbObjectStore, const String& indexName)
+{
+ ExceptionCode ec = 0;
+ RefPtr<IDBIndex> idbIndex = idbObjectStore->index(indexName, ec);
+ if (ec)
+ return 0;
+ return idbIndex;
+}
+
+static PassRefPtr<KeyPath> keyPathFromIDBKeyPath(const IDBKeyPath& idbKeyPath)
+{
+ RefPtr<KeyPath> keyPath;
+ switch (idbKeyPath.type()) {
+ case IDBKeyPath::NullType:
+ keyPath = KeyPath::create().setType(KeyPath::Type::Null);
+ break;
+ case IDBKeyPath::StringType:
+ keyPath = KeyPath::create().setType(KeyPath::Type::String);
+ keyPath->setString(idbKeyPath.string());
+ break;
+ case IDBKeyPath::ArrayType: {
+ keyPath = KeyPath::create().setType(KeyPath::Type::Array);
+ RefPtr<TypeBuilder::Array<String> > array = TypeBuilder::Array<String>::create();
+ const Vector<String>& stringArray = idbKeyPath.array();
+ for (size_t i = 0; i < stringArray.size(); ++i)
+ array->addItem(stringArray[i]);
+ keyPath->setArray(array);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return keyPath.release();
+}
+
+class DatabaseLoader : public ExecutableWithDatabase {
+public:
+ static PassRefPtr<DatabaseLoader> create(ScriptExecutionContext* context, PassRefPtr<RequestDatabaseCallback> requestCallback)
+ {
+ return adoptRef(new DatabaseLoader(context, requestCallback));
+ }
+
+ virtual ~DatabaseLoader() { }
+
+ virtual void execute(PassRefPtr<IDBDatabase> prpDatabase)
+ {
+ RefPtr<IDBDatabase> idbDatabase = prpDatabase;
+ if (!requestCallback()->isActive())
+ return;
+
+ const IDBDatabaseMetadata databaseMetadata = idbDatabase->metadata();
+
+ RefPtr<TypeBuilder::Array<TypeBuilder::IndexedDB::ObjectStore> > objectStores = TypeBuilder::Array<TypeBuilder::IndexedDB::ObjectStore>::create();
+
+ for (IDBDatabaseMetadata::ObjectStoreMap::const_iterator it = databaseMetadata.objectStores.begin(); it != databaseMetadata.objectStores.end(); ++it) {
+ const IDBObjectStoreMetadata& objectStoreMetadata = it->value;
+
+ RefPtr<TypeBuilder::Array<TypeBuilder::IndexedDB::ObjectStoreIndex> > indexes = TypeBuilder::Array<TypeBuilder::IndexedDB::ObjectStoreIndex>::create();
+
+ for (IDBObjectStoreMetadata::IndexMap::const_iterator it = objectStoreMetadata.indexes.begin(); it != objectStoreMetadata.indexes.end(); ++it) {
+ const IDBIndexMetadata& indexMetadata = it->value;
+
+ RefPtr<ObjectStoreIndex> objectStoreIndex = ObjectStoreIndex::create()
+ .setName(indexMetadata.name)
+ .setKeyPath(keyPathFromIDBKeyPath(indexMetadata.keyPath))
+ .setUnique(indexMetadata.unique)
+ .setMultiEntry(indexMetadata.multiEntry);
+ indexes->addItem(objectStoreIndex);
+ }
+
+ RefPtr<ObjectStore> objectStore = ObjectStore::create()
+ .setName(objectStoreMetadata.name)
+ .setKeyPath(keyPathFromIDBKeyPath(objectStoreMetadata.keyPath))
+ .setAutoIncrement(objectStoreMetadata.autoIncrement)
+ .setIndexes(indexes);
+ objectStores->addItem(objectStore);
+ }
+ RefPtr<DatabaseWithObjectStores> result = DatabaseWithObjectStores::create()
+ .setName(databaseMetadata.name)
+ .setIntVersion(databaseMetadata.intVersion)
+ .setVersion(databaseMetadata.version)
+ .setObjectStores(objectStores);
+
+ m_requestCallback->sendSuccess(result);
+ }
+
+ virtual RequestCallback* requestCallback() { return m_requestCallback.get(); }
+private:
+ DatabaseLoader(ScriptExecutionContext* context, PassRefPtr<RequestDatabaseCallback> requestCallback)
+ : ExecutableWithDatabase(context)
+ , m_requestCallback(requestCallback) { }
+ RefPtr<RequestDatabaseCallback> m_requestCallback;
+};
+
+static PassRefPtr<IDBKey> idbKeyFromInspectorObject(InspectorObject* key)
+{
+ RefPtr<IDBKey> idbKey;
+
+ String type;
+ if (!key->getString("type", &type))
+ return 0;
+
+ DEFINE_STATIC_LOCAL(String, number, (ASCIILiteral("number")));
+ DEFINE_STATIC_LOCAL(String, string, (ASCIILiteral("string")));
+ DEFINE_STATIC_LOCAL(String, date, (ASCIILiteral("date")));
+ DEFINE_STATIC_LOCAL(String, array, (ASCIILiteral("array")));
+
+ if (type == number) {
+ double number;
+ if (!key->getNumber("number", &number))
+ return 0;
+ idbKey = IDBKey::createNumber(number);
+ } else if (type == string) {
+ String string;
+ if (!key->getString("string", &string))
+ return 0;
+ idbKey = IDBKey::createString(string);
+ } else if (type == date) {
+ double date;
+ if (!key->getNumber("date", &date))
+ return 0;
+ idbKey = IDBKey::createDate(date);
+ } else if (type == array) {
+ IDBKey::KeyArray keyArray;
+ RefPtr<InspectorArray> array = key->getArray("array");
+ for (size_t i = 0; i < array->length(); ++i) {
+ RefPtr<InspectorValue> value = array->get(i);
+ RefPtr<InspectorObject> object;
+ if (!value->asObject(&object))
+ return 0;
+ keyArray.append(idbKeyFromInspectorObject(object.get()));
+ }
+ idbKey = IDBKey::createArray(keyArray);
+ } else
+ return 0;
+
+ return idbKey.release();
+}
+
+static PassRefPtr<IDBKeyRange> idbKeyRangeFromKeyRange(InspectorObject* keyRange)
+{
+ RefPtr<InspectorObject> lower = keyRange->getObject("lower");
+ RefPtr<IDBKey> idbLower = lower ? idbKeyFromInspectorObject(lower.get()) : 0;
+ if (lower && !idbLower)
+ return 0;
+
+ RefPtr<InspectorObject> upper = keyRange->getObject("upper");
+ RefPtr<IDBKey> idbUpper = upper ? idbKeyFromInspectorObject(upper.get()) : 0;
+ if (upper && !idbUpper)
+ return 0;
+
+ bool lowerOpen;
+ if (!keyRange->getBoolean("lowerOpen", &lowerOpen))
+ return 0;
+ IDBKeyRange::LowerBoundType lowerBoundType = lowerOpen ? IDBKeyRange::LowerBoundOpen : IDBKeyRange::LowerBoundClosed;
+
+ bool upperOpen;
+ if (!keyRange->getBoolean("upperOpen", &upperOpen))
+ return 0;
+ IDBKeyRange::UpperBoundType upperBoundType = upperOpen ? IDBKeyRange::UpperBoundOpen : IDBKeyRange::UpperBoundClosed;
+
+ RefPtr<IDBKeyRange> idbKeyRange = IDBKeyRange::create(idbLower, idbUpper, lowerBoundType, upperBoundType);
+ return idbKeyRange.release();
+}
+
+class DataLoader;
+
+class OpenCursorCallback : public EventListener {
+public:
+ static PassRefPtr<OpenCursorCallback> create(InjectedScript injectedScript, PassRefPtr<RequestDataCallback> requestCallback, int skipCount, unsigned pageSize)
+ {
+ return adoptRef(new OpenCursorCallback(injectedScript, requestCallback, skipCount, pageSize));
+ }
+
+ virtual ~OpenCursorCallback() { }
+
+ virtual bool operator==(const EventListener& other) OVERRIDE
+ {
+ return this == &other;
+ }
+
+ virtual void handleEvent(ScriptExecutionContext*, Event* event) OVERRIDE
+ {
+ if (event->type() != eventNames().successEvent) {
+ m_requestCallback->sendFailure("Unexpected event type.");
+ return;
+ }
+
+ IDBRequest* idbRequest = static_cast<IDBRequest*>(event->target());
+ ExceptionCode ec = 0;
+ RefPtr<IDBAny> requestResult = idbRequest->result(ec);
+ if (ec) {
+ m_requestCallback->sendFailure("Could not get result in callback.");
+ return;
+ }
+ if (requestResult->type() == IDBAny::ScriptValueType) {
+ end(false);
+ return;
+ }
+ if (requestResult->type() != IDBAny::IDBCursorWithValueType) {
+ m_requestCallback->sendFailure("Unexpected result type.");
+ return;
+ }
+
+ RefPtr<IDBCursorWithValue> idbCursor = requestResult->idbCursorWithValue();
+
+ if (m_skipCount) {
+ ExceptionCode ec = 0;
+ idbCursor->advance(m_skipCount, ec);
+ if (ec)
+ m_requestCallback->sendFailure("Could not advance cursor.");
+ m_skipCount = 0;
+ return;
+ }
+
+ if (m_result->length() == m_pageSize) {
+ end(true);
+ return;
+ }
+
+ // Continue cursor before making injected script calls, otherwise transaction might be finished.
+ idbCursor->continueFunction(0, ec);
+ if (ec) {
+ m_requestCallback->sendFailure("Could not continue cursor.");
+ return;
+ }
+
+ RefPtr<DataEntry> dataEntry = DataEntry::create()
+ .setKey(m_injectedScript.wrapObject(idbCursor->key(), String()))
+ .setPrimaryKey(m_injectedScript.wrapObject(idbCursor->primaryKey(), String()))
+ .setValue(m_injectedScript.wrapObject(idbCursor->value(), String()));
+ m_result->addItem(dataEntry);
+
+ }
+
+ void end(bool hasMore)
+ {
+ if (!m_requestCallback->isActive())
+ return;
+ m_requestCallback->sendSuccess(m_result.release(), hasMore);
+ }
+
+private:
+ OpenCursorCallback(InjectedScript injectedScript, PassRefPtr<RequestDataCallback> requestCallback, int skipCount, unsigned pageSize)
+ : EventListener(EventListener::CPPEventListenerType)
+ , m_injectedScript(injectedScript)
+ , m_requestCallback(requestCallback)
+ , m_skipCount(skipCount)
+ , m_pageSize(pageSize)
+ {
+ m_result = Array<DataEntry>::create();
+ }
+ InjectedScript m_injectedScript;
+ RefPtr<RequestDataCallback> m_requestCallback;
+ int m_skipCount;
+ unsigned m_pageSize;
+ RefPtr<Array<DataEntry> > m_result;
+};
+
+class DataLoader : public ExecutableWithDatabase {
+public:
+ static PassRefPtr<DataLoader> create(ScriptExecutionContext* context, PassRefPtr<RequestDataCallback> requestCallback, const InjectedScript& injectedScript, const String& objectStoreName, const String& indexName, PassRefPtr<IDBKeyRange> idbKeyRange, int skipCount, unsigned pageSize)
+ {
+ return adoptRef(new DataLoader(context, requestCallback, injectedScript, objectStoreName, indexName, idbKeyRange, skipCount, pageSize));
+ }
+
+ virtual ~DataLoader() { }
+
+ virtual void execute(PassRefPtr<IDBDatabase> prpDatabase)
+ {
+ RefPtr<IDBDatabase> idbDatabase = prpDatabase;
+ if (!requestCallback()->isActive())
+ return;
+ RefPtr<IDBTransaction> idbTransaction = transactionForDatabase(context(), idbDatabase.get(), m_objectStoreName);
+ if (!idbTransaction) {
+ m_requestCallback->sendFailure("Could not get transaction");
+ return;
+ }
+ RefPtr<IDBObjectStore> idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName);
+ if (!idbObjectStore) {
+ m_requestCallback->sendFailure("Could not get object store");
+ return;
+ }
+
+ RefPtr<OpenCursorCallback> openCursorCallback = OpenCursorCallback::create(m_injectedScript, m_requestCallback, m_skipCount, m_pageSize);
+
+ ExceptionCode ec = 0;
+ RefPtr<IDBRequest> idbRequest;
+ if (!m_indexName.isEmpty()) {
+ RefPtr<IDBIndex> idbIndex = indexForObjectStore(idbObjectStore.get(), m_indexName);
+ if (!idbIndex) {
+ m_requestCallback->sendFailure("Could not get index");
+ return;
+ }
+
+ idbRequest = idbIndex->openCursor(context(), PassRefPtr<IDBKeyRange>(m_idbKeyRange), IDBCursor::directionNext(), ec);
+ } else
+ idbRequest = idbObjectStore->openCursor(context(), PassRefPtr<IDBKeyRange>(m_idbKeyRange), IDBCursor::directionNext(), ec);
+ idbRequest->addEventListener(eventNames().successEvent, openCursorCallback, false);
+ }
+
+ virtual RequestCallback* requestCallback() { return m_requestCallback.get(); }
+ DataLoader(ScriptExecutionContext* scriptExecutionContext, PassRefPtr<RequestDataCallback> requestCallback, const InjectedScript& injectedScript, const String& objectStoreName, const String& indexName, PassRefPtr<IDBKeyRange> idbKeyRange, int skipCount, unsigned pageSize)
+ : ExecutableWithDatabase(scriptExecutionContext)
+ , m_requestCallback(requestCallback)
+ , m_injectedScript(injectedScript)
+ , m_objectStoreName(objectStoreName)
+ , m_indexName(indexName)
+ , m_idbKeyRange(idbKeyRange)
+ , m_skipCount(skipCount)
+ , m_pageSize(pageSize) { }
+ RefPtr<RequestDataCallback> m_requestCallback;
+ InjectedScript m_injectedScript;
+ String m_objectStoreName;
+ String m_indexName;
+ RefPtr<IDBKeyRange> m_idbKeyRange;
+ int m_skipCount;
+ unsigned m_pageSize;
+};
+
+} // namespace
+
+InspectorIndexedDBAgent::InspectorIndexedDBAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, InspectorPageAgent* pageAgent)
+ : InspectorBaseAgent<InspectorIndexedDBAgent>("IndexedDB", instrumentingAgents, state)
+ , m_injectedScriptManager(injectedScriptManager)
+ , m_pageAgent(pageAgent)
+{
+}
+
+InspectorIndexedDBAgent::~InspectorIndexedDBAgent()
+{
+}
+
+void InspectorIndexedDBAgent::clearFrontend()
+{
+ disable(0);
+}
+
+void InspectorIndexedDBAgent::restore()
+{
+ if (m_state->getBoolean(IndexedDBAgentState::indexedDBAgentEnabled)) {
+ ErrorString error;
+ enable(&error);
+ }
+}
+
+void InspectorIndexedDBAgent::enable(ErrorString*)
+{
+ m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, true);
+}
+
+void InspectorIndexedDBAgent::disable(ErrorString*)
+{
+ m_state->setBoolean(IndexedDBAgentState::indexedDBAgentEnabled, false);
+}
+
+static Document* assertDocument(ErrorString* errorString, Frame* frame)
+{
+ Document* document = frame ? frame->document() : 0;
+
+ if (!document)
+ *errorString = "No document for given frame found";
+
+ return document;
+}
+
+static IDBFactory* assertIDBFactory(ErrorString* errorString, Document* document)
+{
+ DOMWindow* domWindow = document->domWindow();
+ if (!domWindow) {
+ *errorString = "No IndexedDB factory for given frame found";
+ return 0;
+ }
+ IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(domWindow);
+
+ if (!idbFactory)
+ *errorString = "No IndexedDB factory for given frame found";
+
+ return idbFactory;
+}
+
+void InspectorIndexedDBAgent::requestDatabaseNames(ErrorString* errorString, const String& securityOrigin, PassRefPtr<RequestDatabaseNamesCallback> requestCallback)
+{
+ Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
+ Document* document = assertDocument(errorString, frame);
+ if (!document)
+ return;
+ IDBFactory* idbFactory = assertIDBFactory(errorString, document);
+ if (!idbFactory)
+ return;
+
+ // FIXME: This should probably use ScriptState/ScriptScope instead of V8 API
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Context> context = document->frame()->script()->mainWorldContext();
+ ASSERT(!context.IsEmpty());
+ v8::Context::Scope contextScope(context);
+
+ ExceptionCode ec = 0;
+ RefPtr<IDBRequest> idbRequest = idbFactory->getDatabaseNames(document, ec);
+ if (ec) {
+ requestCallback->sendFailure("Could not obtain database names.");
+ return;
+ }
+ idbRequest->addEventListener(eventNames().successEvent, GetDatabaseNamesCallback::create(requestCallback, document->securityOrigin()->toRawString()), false);
+}
+
+void InspectorIndexedDBAgent::requestDatabase(ErrorString* errorString, const String& securityOrigin, const String& databaseName, PassRefPtr<RequestDatabaseCallback> requestCallback)
+{
+ Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
+ Document* document = assertDocument(errorString, frame);
+ if (!document)
+ return;
+ IDBFactory* idbFactory = assertIDBFactory(errorString, document);
+ if (!idbFactory)
+ return;
+
+ // FIXME: This should probably use ScriptState/ScriptScope instead of V8 API
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Context> context = document->frame()->script()->mainWorldContext();
+ ASSERT(!context.IsEmpty());
+ v8::Context::Scope contextScope(context);
+
+ RefPtr<DatabaseLoader> databaseLoader = DatabaseLoader::create(document, requestCallback);
+ databaseLoader->start(idbFactory, document->securityOrigin(), databaseName);
+}
+
+void InspectorIndexedDBAgent::requestData(ErrorString* errorString, const String& securityOrigin, const String& databaseName, const String& objectStoreName, const String& indexName, int skipCount, int pageSize, const RefPtr<InspectorObject>* keyRange, PassRefPtr<RequestDataCallback> requestCallback)
+{
+ Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
+ Document* document = assertDocument(errorString, frame);
+ if (!document)
+ return;
+ IDBFactory* idbFactory = assertIDBFactory(errorString, document);
+ if (!idbFactory)
+ return;
+
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
+
+ RefPtr<IDBKeyRange> idbKeyRange = keyRange ? idbKeyRangeFromKeyRange(keyRange->get()) : 0;
+ if (keyRange && !idbKeyRange) {
+ *errorString = "Can not parse key range.";
+ return;
+ }
+
+ // FIXME: This should probably use ScriptState/ScriptScope instead of V8 API
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Context> context = document->frame()->script()->mainWorldContext();
+ ASSERT(!context.IsEmpty());
+ v8::Context::Scope contextScope(context);
+
+ RefPtr<DataLoader> dataLoader = DataLoader::create(document, requestCallback, injectedScript, objectStoreName, indexName, idbKeyRange, skipCount, pageSize);
+ dataLoader->start(idbFactory, document->securityOrigin(), databaseName);
+}
+
+class ClearObjectStoreListener : public EventListener {
+ WTF_MAKE_NONCOPYABLE(ClearObjectStoreListener);
+public:
+ static PassRefPtr<ClearObjectStoreListener> create(PassRefPtr<ClearObjectStoreCallback> requestCallback)
+ {
+ return adoptRef(new ClearObjectStoreListener(requestCallback));
+ }
+
+ virtual ~ClearObjectStoreListener() { }
+
+ virtual bool operator==(const EventListener& other) OVERRIDE
+ {
+ return this == &other;
+ }
+
+ virtual void handleEvent(ScriptExecutionContext*, Event* event) OVERRIDE
+ {
+ if (!m_requestCallback->isActive())
+ return;
+ if (event->type() != eventNames().completeEvent) {
+ m_requestCallback->sendFailure("Unexpected event type.");
+ return;
+ }
+
+ m_requestCallback->sendSuccess();
+ }
+private:
+ ClearObjectStoreListener(PassRefPtr<ClearObjectStoreCallback> requestCallback)
+ : EventListener(EventListener::CPPEventListenerType)
+ , m_requestCallback(requestCallback)
+ {
+ }
+
+ RefPtr<ClearObjectStoreCallback> m_requestCallback;
+};
+
+
+class ClearObjectStore : public ExecutableWithDatabase {
+public:
+ static PassRefPtr<ClearObjectStore> create(ScriptExecutionContext* context, const String& objectStoreName, PassRefPtr<ClearObjectStoreCallback> requestCallback)
+ {
+ return adoptRef(new ClearObjectStore(context, objectStoreName, requestCallback));
+ }
+
+ ClearObjectStore(ScriptExecutionContext* context, const String& objectStoreName, PassRefPtr<ClearObjectStoreCallback> requestCallback)
+ : ExecutableWithDatabase(context)
+ , m_objectStoreName(objectStoreName)
+ , m_requestCallback(requestCallback)
+ {
+ }
+
+ virtual void execute(PassRefPtr<IDBDatabase> prpDatabase)
+ {
+ RefPtr<IDBDatabase> idbDatabase = prpDatabase;
+ if (!requestCallback()->isActive())
+ return;
+ RefPtr<IDBTransaction> idbTransaction = transactionForDatabase(context(), idbDatabase.get(), m_objectStoreName, IDBTransaction::modeReadWrite());
+ if (!idbTransaction) {
+ m_requestCallback->sendFailure("Could not get transaction");
+ return;
+ }
+ RefPtr<IDBObjectStore> idbObjectStore = objectStoreForTransaction(idbTransaction.get(), m_objectStoreName);
+ if (!idbObjectStore) {
+ m_requestCallback->sendFailure("Could not get object store");
+ return;
+ }
+
+ ExceptionCode ec = 0;
+ RefPtr<IDBRequest> idbRequest = idbObjectStore->clear(context(), ec);
+ ASSERT(!ec);
+ if (ec) {
+ m_requestCallback->sendFailure(String::format("Could not clear object store '%s': %d", m_objectStoreName.utf8().data(), ec));
+ return;
+ }
+ idbTransaction->addEventListener(eventNames().completeEvent, ClearObjectStoreListener::create(m_requestCallback), false);
+ }
+
+ virtual RequestCallback* requestCallback() { return m_requestCallback.get(); }
+private:
+ const String m_objectStoreName;
+ RefPtr<ClearObjectStoreCallback> m_requestCallback;
+};
+
+void InspectorIndexedDBAgent::clearObjectStore(ErrorString* errorString, const String& securityOrigin, const String& databaseName, const String& objectStoreName, PassRefPtr<ClearObjectStoreCallback> requestCallback)
+{
+ Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
+ Document* document = assertDocument(errorString, frame);
+ if (!document)
+ return;
+ IDBFactory* idbFactory = assertIDBFactory(errorString, document);
+ if (!idbFactory)
+ return;
+
+ // FIXME: This should probably use ScriptState/ScriptScope instead of V8 API
+ v8::HandleScope handleScope;
+ v8::Handle<v8::Context> context = document->frame()->script()->mainWorldContext();
+ ASSERT(!context.IsEmpty());
+ v8::Context::Scope contextScope(context);
+
+ RefPtr<ClearObjectStore> clearObjectStore = ClearObjectStore::create(document, objectStoreName, requestCallback);
+ clearObjectStore->start(idbFactory, document->securityOrigin(), databaseName);
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InspectorIndexedDBAgent.h b/Source/core/inspector/InspectorIndexedDBAgent.h
new file mode 100644
index 0000000..259b2a7
--- /dev/null
+++ b/Source/core/inspector/InspectorIndexedDBAgent.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorIndexedDBAgent_h
+#define InspectorIndexedDBAgent_h
+
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InjectedScriptManager;
+class InspectorPageAgent;
+
+typedef String ErrorString;
+
+class InspectorIndexedDBAgent : public InspectorBaseAgent<InspectorIndexedDBAgent>, public InspectorBackendDispatcher::IndexedDBCommandHandler {
+public:
+ static PassOwnPtr<InspectorIndexedDBAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, InspectorPageAgent* pageAgent)
+ {
+ return adoptPtr(new InspectorIndexedDBAgent(instrumentingAgents, state, injectedScriptManager, pageAgent));
+ }
+ ~InspectorIndexedDBAgent();
+
+ virtual void clearFrontend();
+ virtual void restore();
+
+ // Called from the front-end.
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void requestDatabaseNames(ErrorString*, const String& securityOrigin, PassRefPtr<RequestDatabaseNamesCallback>);
+ virtual void requestDatabase(ErrorString*, const String& securityOrigin, const String& databaseName, PassRefPtr<RequestDatabaseCallback>);
+ virtual void requestData(ErrorString*, const String& securityOrigin, const String& databaseName, const String& objectStoreName, const String& indexName, int skipCount, int pageSize, const RefPtr<InspectorObject>* keyRange, PassRefPtr<RequestDataCallback>);
+ virtual void clearObjectStore(ErrorString*, const String& in_securityOrigin, const String& in_databaseName, const String& in_objectStoreName, PassRefPtr<ClearObjectStoreCallback>);
+
+private:
+ InspectorIndexedDBAgent(InstrumentingAgents*, InspectorCompositeState*, InjectedScriptManager*, InspectorPageAgent*);
+
+ InjectedScriptManager* m_injectedScriptManager;
+ InspectorPageAgent* m_pageAgent;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorIndexedDBAgent_h)
diff --git a/Source/core/inspector/InspectorInputAgent.cpp b/Source/core/inspector/InspectorInputAgent.cpp
new file mode 100644
index 0000000..0292338
--- /dev/null
+++ b/Source/core/inspector/InspectorInputAgent.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorInputAgent.h"
+
+#include "core/page/Chrome.h"
+#include "core/page/EventHandler.h"
+#include "core/page/FocusController.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/platform/PlatformEvent.h"
+#include "core/platform/PlatformKeyboardEvent.h"
+#include "core/platform/PlatformMouseEvent.h"
+#include "core/platform/graphics/IntPoint.h"
+#include "core/platform/graphics/IntRect.h"
+#include "core/platform/graphics/IntSize.h"
+
+#include <wtf/CurrentTime.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+InspectorInputAgent::InspectorInputAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, Page* page)
+ : InspectorBaseAgent<InspectorInputAgent>("Input", instrumentingAgents, inspectorState)
+ , m_page(page)
+{
+}
+
+InspectorInputAgent::~InspectorInputAgent()
+{
+}
+
+void InspectorInputAgent::dispatchKeyEvent(ErrorString* error, const String& type, const int* modifiers, const double* timestamp, const String* text, const String* unmodifiedText, const String* keyIdentifier, const int* windowsVirtualKeyCode, const int* nativeVirtualKeyCode, const int* macCharCode, const bool* autoRepeat, const bool* isKeypad, const bool* isSystemKey)
+{
+ PlatformEvent::Type convertedType;
+ if (type == "keyDown")
+ convertedType = PlatformEvent::KeyDown;
+ else if (type == "keyUp")
+ convertedType = PlatformEvent::KeyUp;
+ else if (type == "char")
+ convertedType = PlatformEvent::Char;
+ else if (type == "rawKeyDown")
+ convertedType = PlatformEvent::RawKeyDown;
+ else {
+ *error = "Unrecognized type: " + type;
+ return;
+ }
+
+ PlatformKeyboardEvent event(
+ convertedType,
+ text ? *text : "",
+ unmodifiedText ? *unmodifiedText : "",
+ keyIdentifier ? *keyIdentifier : "",
+ windowsVirtualKeyCode ? *windowsVirtualKeyCode : 0,
+ nativeVirtualKeyCode ? *nativeVirtualKeyCode : 0,
+ macCharCode ? *macCharCode : 0,
+ autoRepeat ? *autoRepeat : false,
+ isKeypad ? *isKeypad : false,
+ isSystemKey ? *isSystemKey : false,
+ static_cast<PlatformEvent::Modifiers>(modifiers ? *modifiers : 0),
+ timestamp ? *timestamp : currentTime());
+ m_page->focusController()->focusedOrMainFrame()->eventHandler()->keyEvent(event);
+}
+
+void InspectorInputAgent::dispatchMouseEvent(ErrorString* error, const String& type, int x, int y, const int* modifiers, const double* timestamp, const String* button, const int* clickCount)
+{
+ PlatformEvent::Type convertedType;
+ if (type == "mousePressed")
+ convertedType = PlatformEvent::MousePressed;
+ else if (type == "mouseReleased")
+ convertedType = PlatformEvent::MouseReleased;
+ else if (type == "mouseMoved")
+ convertedType = PlatformEvent::MouseMoved;
+ else {
+ *error = "Unrecognized type: " + type;
+ return;
+ }
+
+ int convertedModifiers = modifiers ? *modifiers : 0;
+
+ MouseButton convertedButton = NoButton;
+ if (button) {
+ if (*button == "left")
+ convertedButton = LeftButton;
+ else if (*button == "middle")
+ convertedButton = MiddleButton;
+ else if (*button == "right")
+ convertedButton = RightButton;
+ else if (*button != "none") {
+ *error = "Unrecognized button: " + *button;
+ return;
+ }
+ }
+
+ // Some platforms may have flipped coordinate systems, but the given coordinates
+ // assume the origin is in the top-left of the window. Convert.
+ IntPoint convertedPoint = m_page->mainFrame()->view()->convertToContainingWindow(IntPoint(x, y));
+ IntPoint globalPoint = m_page->chrome()->rootViewToScreen(IntRect(IntPoint(x, y), IntSize(0, 0))).location();
+
+ PlatformMouseEvent event(
+ convertedPoint,
+ globalPoint,
+ convertedButton,
+ convertedType,
+ clickCount ? *clickCount : 0,
+ convertedModifiers & PlatformEvent::ShiftKey,
+ convertedModifiers & PlatformEvent::CtrlKey,
+ convertedModifiers & PlatformEvent::AltKey,
+ convertedModifiers & PlatformEvent::MetaKey,
+ timestamp ? *timestamp : currentTime());
+
+ EventHandler* handler = m_page->mainFrame()->eventHandler();
+ switch (convertedType) {
+ case PlatformEvent::MousePressed:
+ handler->handleMousePressEvent(event);
+ break;
+ case PlatformEvent::MouseReleased:
+ handler->handleMouseReleaseEvent(event);
+ break;
+ case PlatformEvent::MouseMoved:
+ handler->handleMouseMoveEvent(event);
+ break;
+ default:
+ *error = "Unhandled type: " + type;
+ }
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorInputAgent.h b/Source/core/inspector/InspectorInputAgent.h
new file mode 100644
index 0000000..fbb5d36
--- /dev/null
+++ b/Source/core/inspector/InspectorInputAgent.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorInputAgent_h
+#define InspectorInputAgent_h
+
+
+#include "core/inspector/InspectorBaseAgent.h"
+
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class InspectorState;
+class Page;
+
+typedef String ErrorString;
+
+class InspectorInputAgent : public InspectorBaseAgent<InspectorInputAgent>, public InspectorBackendDispatcher::InputCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorInputAgent);
+public:
+ static PassOwnPtr<InspectorInputAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, Page* page)
+ {
+ return adoptPtr(new InspectorInputAgent(instrumentingAgents, inspectorState, page));
+ }
+
+ ~InspectorInputAgent();
+
+ // Methods called from the frontend for simulating input.
+ virtual void dispatchKeyEvent(ErrorString*, const String& type, const int* modifiers, const double* timestamp, const String* text, const String* unmodifiedText, const String* keyIdentifier, const int* windowsVirtualKeyCode, const int* nativeVirtualKeyCode, const int* macCharCode, const bool* autoRepeat, const bool* isKeypad, const bool* isSystemKey);
+ virtual void dispatchMouseEvent(ErrorString*, const String& type, int x, int y, const int* modifiers, const double* timestamp, const String* button, const int* clickCount);
+
+private:
+ InspectorInputAgent(InstrumentingAgents*, InspectorCompositeState*, Page*);
+
+ Page* m_page;
+};
+
+
+} // namespace WebCore
+
+#endif // !defined(InspectorInputAgent_h)
diff --git a/Source/core/inspector/InspectorInstrumentation.cpp b/Source/core/inspector/InspectorInstrumentation.cpp
new file mode 100644
index 0000000..79b3ffc
--- /dev/null
+++ b/Source/core/inspector/InspectorInstrumentation.cpp
@@ -0,0 +1,1328 @@
+/*
+* Copyright (C) 2011 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 "core/inspector/InspectorInstrumentation.h"
+
+#include "bindings/v8/DOMWrapperWorld.h"
+#include "bindings/v8/ScriptController.h"
+#include "core/css/CSSRule.h"
+#include "core/css/CSSStyleRule.h"
+#include "core/css/StyleResolver.h"
+#include "core/css/StyleRule.h"
+#include "core/dom/DeviceOrientationData.h"
+#include "core/dom/Event.h"
+#include "core/dom/EventContext.h"
+#include "core/inspector/ConsoleAPITypes.h"
+#include "core/inspector/InspectorAgent.h"
+#include "core/inspector/InspectorApplicationCacheAgent.h"
+#include "core/inspector/InspectorCSSAgent.h"
+#include "core/inspector/InspectorCanvasAgent.h"
+#include "core/inspector/InspectorConsoleAgent.h"
+#include "core/inspector/InspectorController.h"
+#include "core/inspector/InspectorDOMAgent.h"
+#include "core/inspector/InspectorDOMDebuggerAgent.h"
+#include "core/inspector/InspectorDOMStorageAgent.h"
+#include "core/inspector/InspectorDatabaseAgent.h"
+#include "core/inspector/InspectorDebuggerAgent.h"
+#include "core/inspector/InspectorHeapProfilerAgent.h"
+#include "core/inspector/InspectorLayerTreeAgent.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorProfilerAgent.h"
+#include "core/inspector/InspectorResourceAgent.h"
+#include "core/inspector/InspectorTimelineAgent.h"
+#include "core/inspector/InspectorWorkerAgent.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/inspector/PageDebuggerAgent.h"
+#include "core/inspector/PageRuntimeAgent.h"
+#include "core/inspector/ScriptArguments.h"
+#include "core/inspector/ScriptCallStack.h"
+#include "core/inspector/ScriptProfile.h"
+#include "core/inspector/WorkerInspectorController.h"
+#include "core/inspector/WorkerRuntimeAgent.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/page/ConsoleTypes.h"
+#include "core/page/DOMWindow.h"
+#include "core/rendering/RenderObject.h"
+#include "core/workers/WorkerContext.h"
+#include "core/workers/WorkerThread.h"
+#include "core/xml/XMLHttpRequest.h"
+#include "modules/webdatabase/Database.h"
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/CString.h>
+
+#include "core/platform/chromium/TraceEvent.h"
+
+namespace WebCore {
+
+static const char* const requestAnimationFrameEventName = "requestAnimationFrame";
+static const char* const cancelAnimationFrameEventName = "cancelAnimationFrame";
+static const char* const animationFrameFiredEventName = "animationFrameFired";
+static const char* const setTimerEventName = "setTimer";
+static const char* const clearTimerEventName = "clearTimer";
+static const char* const timerFiredEventName = "timerFired";
+
+namespace {
+static HashSet<InstrumentingAgents*>* instrumentingAgentsSet = 0;
+}
+
+namespace InspectorInstrumentation {
+int FrontendCounter::s_frontendCounter = 0;
+}
+
+InspectorInstrumentationCookie::InspectorInstrumentationCookie()
+ : m_instrumentingAgents(0)
+ , m_timelineAgentId(0)
+{
+}
+
+InspectorInstrumentationCookie::InspectorInstrumentationCookie(InstrumentingAgents* agents, int timelineAgentId)
+ : m_instrumentingAgents(agents)
+ , m_timelineAgentId(timelineAgentId)
+{
+}
+
+InspectorInstrumentationCookie::InspectorInstrumentationCookie(const InspectorInstrumentationCookie& other)
+ : m_instrumentingAgents(other.m_instrumentingAgents)
+ , m_timelineAgentId(other.m_timelineAgentId)
+{
+}
+
+InspectorInstrumentationCookie& InspectorInstrumentationCookie::operator=(const InspectorInstrumentationCookie& other)
+{
+ if (this != &other) {
+ m_instrumentingAgents = other.m_instrumentingAgents;
+ m_timelineAgentId = other.m_timelineAgentId;
+ }
+ return *this;
+}
+
+InspectorInstrumentationCookie::~InspectorInstrumentationCookie()
+{
+}
+
+namespace InspectorInstrumentation {
+
+void pauseOnNativeEventIfNeeded(InstrumentingAgents*, bool isDOMEvent, const String& eventName, bool synchronous);
+
+void cancelPauseOnNativeEvent(InstrumentingAgents*);
+
+InspectorTimelineAgent* retrieveTimelineAgent(const InspectorInstrumentationCookie&);
+
+void didClearWindowObjectInWorldImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, DOMWrapperWorld* world)
+{
+ InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent();
+ if (pageAgent)
+ pageAgent->didClearWindowObjectInWorld(frame, world);
+ if (InspectorAgent* inspectorAgent = instrumentingAgents->inspectorAgent())
+ inspectorAgent->didClearWindowObjectInWorld(frame, world);
+ if (PageDebuggerAgent* debuggerAgent = instrumentingAgents->pageDebuggerAgent()) {
+ if (pageAgent && world == mainThreadNormalWorld() && frame == pageAgent->mainFrame())
+ debuggerAgent->didClearMainFrameWindowObject();
+ }
+ if (PageRuntimeAgent* pageRuntimeAgent = instrumentingAgents->pageRuntimeAgent()) {
+ if (world == mainThreadNormalWorld())
+ pageRuntimeAgent->didCreateMainWorldContext(frame);
+ }
+}
+
+bool isDebuggerPausedImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents->inspectorDebuggerAgent())
+ return debuggerAgent->isPaused();
+ return false;
+}
+
+void willInsertDOMNodeImpl(InstrumentingAgents* instrumentingAgents, Node* parent)
+{
+ if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents->inspectorDOMDebuggerAgent())
+ domDebuggerAgent->willInsertDOMNode(parent);
+}
+
+void didInsertDOMNodeImpl(InstrumentingAgents* instrumentingAgents, Node* node)
+{
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->didInsertDOMNode(node);
+ if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents->inspectorDOMDebuggerAgent())
+ domDebuggerAgent->didInsertDOMNode(node);
+}
+
+void willRemoveDOMNodeImpl(InstrumentingAgents* instrumentingAgents, Node* node)
+{
+ if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents->inspectorDOMDebuggerAgent())
+ domDebuggerAgent->willRemoveDOMNode(node);
+}
+
+void didRemoveDOMNodeImpl(InstrumentingAgents* instrumentingAgents, Node* node)
+{
+ if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents->inspectorDOMDebuggerAgent())
+ domDebuggerAgent->didRemoveDOMNode(node);
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->didRemoveDOMNode(node);
+}
+
+void willModifyDOMAttrImpl(InstrumentingAgents* instrumentingAgents, Element* element, const AtomicString& oldValue, const AtomicString& newValue)
+{
+ if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents->inspectorDOMDebuggerAgent())
+ domDebuggerAgent->willModifyDOMAttr(element, oldValue, newValue);
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->willModifyDOMAttr(element, oldValue, newValue);
+}
+
+void didModifyDOMAttrImpl(InstrumentingAgents* instrumentingAgents, Element* element, const AtomicString& name, const AtomicString& value)
+{
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->didModifyDOMAttr(element, name, value);
+}
+
+void didRemoveDOMAttrImpl(InstrumentingAgents* instrumentingAgents, Element* element, const AtomicString& name)
+{
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->didRemoveDOMAttr(element, name);
+}
+
+void didInvalidateStyleAttrImpl(InstrumentingAgents* instrumentingAgents, Node* node)
+{
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->didInvalidateStyleAttr(node);
+ if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents->inspectorDOMDebuggerAgent())
+ domDebuggerAgent->didInvalidateStyleAttr(node);
+}
+
+void activeStyleSheetsUpdatedImpl(InstrumentingAgents* instrumentingAgents, const Vector<RefPtr<StyleSheet> >& newSheets)
+{
+ if (InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent())
+ cssAgent->activeStyleSheetsUpdated(newSheets);
+}
+
+void frameWindowDiscardedImpl(InstrumentingAgents* instrumentingAgents, DOMWindow* window)
+{
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->frameWindowDiscarded(window);
+}
+
+void mediaQueryResultChangedImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent())
+ cssAgent->mediaQueryResultChanged();
+}
+
+void didPushShadowRootImpl(InstrumentingAgents* instrumentingAgents, Element* host, ShadowRoot* root)
+{
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->didPushShadowRoot(host, root);
+}
+
+void willPopShadowRootImpl(InstrumentingAgents* instrumentingAgents, Element* host, ShadowRoot* root)
+{
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->willPopShadowRoot(host, root);
+}
+
+void didCreateNamedFlowImpl(InstrumentingAgents* instrumentingAgents, Document* document, NamedFlow* namedFlow)
+{
+ if (InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent())
+ cssAgent->didCreateNamedFlow(document, namedFlow);
+}
+
+void willRemoveNamedFlowImpl(InstrumentingAgents* instrumentingAgents, Document* document, NamedFlow* namedFlow)
+{
+ if (InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent())
+ cssAgent->willRemoveNamedFlow(document, namedFlow);
+}
+
+void didUpdateRegionLayoutImpl(InstrumentingAgents* instrumentingAgents, Document* document, NamedFlow* namedFlow)
+{
+ if (InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent())
+ cssAgent->didUpdateRegionLayout(document, namedFlow);
+}
+
+void didScrollImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->didScroll();
+}
+
+void didResizeMainFrameImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->didResizeMainFrame();
+}
+
+bool forcePseudoStateImpl(InstrumentingAgents* instrumentingAgents, Element* element, CSSSelector::PseudoType pseudoState)
+{
+ if (InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent())
+ return cssAgent->forcePseudoState(element, pseudoState);
+ return false;
+}
+
+void characterDataModifiedImpl(InstrumentingAgents* instrumentingAgents, CharacterData* characterData)
+{
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->characterDataModified(characterData);
+}
+
+void willSendXMLHttpRequestImpl(InstrumentingAgents* instrumentingAgents, const String& url)
+{
+ if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents->inspectorDOMDebuggerAgent())
+ domDebuggerAgent->willSendXMLHttpRequest(url);
+}
+
+void didScheduleResourceRequestImpl(InstrumentingAgents* instrumentingAgents, Document* document, const String& url)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didScheduleResourceRequest(document, url);
+}
+
+void didInstallTimerImpl(InstrumentingAgents* instrumentingAgents, ScriptExecutionContext* context, int timerId, int timeout, bool singleShot)
+{
+ pauseOnNativeEventIfNeeded(instrumentingAgents, false, setTimerEventName, true);
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didInstallTimer(context, timerId, timeout, singleShot);
+}
+
+void didRemoveTimerImpl(InstrumentingAgents* instrumentingAgents, ScriptExecutionContext* context, int timerId)
+{
+ pauseOnNativeEventIfNeeded(instrumentingAgents, false, clearTimerEventName, true);
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didRemoveTimer(context, timerId);
+}
+
+InspectorInstrumentationCookie willCallFunctionImpl(InstrumentingAgents* instrumentingAgents, ScriptExecutionContext* context, const String& scriptName, int scriptLine)
+{
+ int timelineAgentId = 0;
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent()) {
+ if (timelineAgent->willCallFunction(context, scriptName, scriptLine))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didCallFunctionImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didCallFunction();
+}
+
+InspectorInstrumentationCookie willDispatchXHRReadyStateChangeEventImpl(InstrumentingAgents* instrumentingAgents, ScriptExecutionContext* context, XMLHttpRequest* request)
+{
+ int timelineAgentId = 0;
+ InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent();
+ if (timelineAgent) {
+ if (timelineAgent->willDispatchXHRReadyStateChangeEvent(context, request))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didDispatchXHRReadyStateChangeEventImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didDispatchXHRReadyStateChangeEvent();
+}
+
+InspectorInstrumentationCookie willDispatchEventImpl(InstrumentingAgents* instrumentingAgents, Document* document, const Event& event, DOMWindow* window, Node* node, const EventPath& eventPath)
+{
+ int timelineAgentId = 0;
+ InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent();
+ if (timelineAgent) {
+ if (timelineAgent->willDispatchEvent(document, event, window, node, eventPath))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+InspectorInstrumentationCookie willHandleEventImpl(InstrumentingAgents* instrumentingAgents, Event* event)
+{
+ pauseOnNativeEventIfNeeded(instrumentingAgents, true, event->type(), false);
+ return InspectorInstrumentationCookie(instrumentingAgents, 0);
+}
+
+void didHandleEventImpl(const InspectorInstrumentationCookie& cookie)
+{
+ cancelPauseOnNativeEvent(cookie.instrumentingAgents());
+}
+
+void didDispatchEventImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didDispatchEvent();
+}
+
+InspectorInstrumentationCookie willDispatchEventOnWindowImpl(InstrumentingAgents* instrumentingAgents, const Event& event, DOMWindow* window)
+{
+ int timelineAgentId = 0;
+ InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent();
+ if (timelineAgent) {
+ if (timelineAgent->willDispatchEventOnWindow(event, window))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didDispatchEventOnWindowImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didDispatchEvent();
+}
+
+InspectorInstrumentationCookie willEvaluateScriptImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, const String& url, int lineNumber)
+{
+ int timelineAgentId = 0;
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent()) {
+ if (timelineAgent->willEvaluateScript(frame, url, lineNumber))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didEvaluateScriptImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didEvaluateScript();
+}
+
+void scriptsEnabledImpl(InstrumentingAgents* instrumentingAgents, bool isEnabled)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->scriptsEnabled(isEnabled);
+}
+
+void didCreateIsolatedContextImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, ScriptState* scriptState, SecurityOrigin* origin)
+{
+ if (PageRuntimeAgent* runtimeAgent = instrumentingAgents->pageRuntimeAgent())
+ runtimeAgent->didCreateIsolatedContext(frame, scriptState, origin);
+}
+
+InspectorInstrumentationCookie willFireTimerImpl(InstrumentingAgents* instrumentingAgents, ScriptExecutionContext* context, int timerId)
+{
+ pauseOnNativeEventIfNeeded(instrumentingAgents, false, timerFiredEventName, false);
+
+ int timelineAgentId = 0;
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent()) {
+ if (timelineAgent->willFireTimer(context, timerId))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didFireTimerImpl(const InspectorInstrumentationCookie& cookie)
+{
+ cancelPauseOnNativeEvent(cookie.instrumentingAgents());
+
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didFireTimer();
+}
+
+void didInvalidateLayoutImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didInvalidateLayout(frame);
+}
+
+InspectorInstrumentationCookie willLayoutImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ int timelineAgentId = 0;
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent()) {
+ if (timelineAgent->willLayout(frame))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didLayoutImpl(const InspectorInstrumentationCookie& cookie, RenderObject* root)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didLayout(root);
+
+ if (InspectorPageAgent* pageAgent = cookie.instrumentingAgents()->inspectorPageAgent())
+ pageAgent->didLayout(root);
+}
+
+InspectorInstrumentationCookie willDispatchXHRLoadEventImpl(InstrumentingAgents* instrumentingAgents, ScriptExecutionContext* context, XMLHttpRequest* request)
+{
+ int timelineAgentId = 0;
+ InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent();
+ if (timelineAgent) {
+ if (timelineAgent->willDispatchXHRLoadEvent(context, request))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didDispatchXHRLoadEventImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didDispatchXHRLoadEvent();
+}
+
+void willPaintImpl(InstrumentingAgents* instrumentingAgents, RenderObject* renderer)
+{
+ TRACE_EVENT_INSTANT1("instrumentation", InstrumentationEvents::Paint, InstrumentationEventArguments::PageId, reinterpret_cast<unsigned long long>(renderer->frame()->page()));
+
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->willPaint(renderer->frame());
+}
+
+void didPaintImpl(InstrumentingAgents* instrumentingAgents, RenderObject* renderer, GraphicsContext* context, const LayoutRect& rect)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didPaint(renderer, context, rect);
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->didPaint(renderer, context, rect);
+}
+
+void willScrollLayerImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->willScrollLayer(frame);
+}
+
+void didScrollLayerImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didScrollLayer();
+}
+
+InspectorInstrumentationCookie willRecalculateStyleImpl(InstrumentingAgents* instrumentingAgents, Document* document)
+{
+ int timelineAgentId = 0;
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent()) {
+ if (timelineAgent->willRecalculateStyle(document))
+ timelineAgentId = timelineAgent->id();
+ }
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->willRecalculateStyle(document);
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didRecalculateStyleImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didRecalculateStyle();
+ InstrumentingAgents* instrumentingAgents = cookie.instrumentingAgents();
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didRecalculateStyle();
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->didRecalculateStyle();
+}
+
+void didRecalculateStyleForElementImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didRecalculateStyleForElement();
+}
+
+void didScheduleStyleRecalculationImpl(InstrumentingAgents* instrumentingAgents, Document* document)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didScheduleStyleRecalculation(document);
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didScheduleStyleRecalculation(document);
+}
+
+InspectorInstrumentationCookie willMatchRuleImpl(InstrumentingAgents* instrumentingAgents, StyleRule* rule, InspectorCSSOMWrappers& inspectorCSSOMWrappers, DocumentStyleSheetCollection* sheetCollection)
+{
+ InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent();
+ if (cssAgent) {
+ cssAgent->willMatchRule(rule, inspectorCSSOMWrappers, sheetCollection);
+ return InspectorInstrumentationCookie(instrumentingAgents, 1);
+ }
+
+ return InspectorInstrumentationCookie();
+}
+
+void didMatchRuleImpl(const InspectorInstrumentationCookie& cookie, bool matched)
+{
+ InspectorCSSAgent* cssAgent = cookie.instrumentingAgents()->inspectorCSSAgent();
+ if (cssAgent)
+ cssAgent->didMatchRule(matched);
+}
+
+InspectorInstrumentationCookie willProcessRuleImpl(InstrumentingAgents* instrumentingAgents, StyleRule* rule, StyleResolver* styleResolver)
+{
+ InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent();
+ if (cssAgent) {
+ cssAgent->willProcessRule(rule, styleResolver);
+ return InspectorInstrumentationCookie(instrumentingAgents, 1);
+ }
+
+ return InspectorInstrumentationCookie();
+}
+
+void didProcessRuleImpl(const InspectorInstrumentationCookie& cookie)
+{
+ InspectorCSSAgent* cssAgent = cookie.instrumentingAgents()->inspectorCSSAgent();
+ if (cssAgent)
+ cssAgent->didProcessRule();
+}
+
+void applyUserAgentOverrideImpl(InstrumentingAgents* instrumentingAgents, String* userAgent)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->applyUserAgentOverride(userAgent);
+}
+
+void applyScreenWidthOverrideImpl(InstrumentingAgents* instrumentingAgents, long* width)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->applyScreenWidthOverride(width);
+}
+
+void applyScreenHeightOverrideImpl(InstrumentingAgents* instrumentingAgents, long* height)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->applyScreenHeightOverride(height);
+}
+
+bool shouldApplyScreenWidthOverrideImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent()) {
+ long width = 0;
+ pageAgent->applyScreenWidthOverride(&width);
+ return !!width;
+ }
+ return false;
+}
+
+bool shouldApplyScreenHeightOverrideImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent()) {
+ long height = 0;
+ pageAgent->applyScreenHeightOverride(&height);
+ return !!height;
+ }
+ return false;
+}
+
+void applyEmulatedMediaImpl(InstrumentingAgents* instrumentingAgents, String* media)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->applyEmulatedMedia(media);
+}
+
+void willSendRequestImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->willSendResourceRequest(identifier, loader, request, redirectResponse);
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->willSendResourceRequest(identifier, loader, request, redirectResponse);
+}
+
+void continueAfterPingLoaderImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& response)
+{
+ willSendRequestImpl(instrumentingAgents, identifier, loader, request, response);
+}
+
+void markResourceAsCachedImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->markResourceAsCached(identifier);
+}
+
+void didLoadResourceFromMemoryCacheImpl(InstrumentingAgents* instrumentingAgents, DocumentLoader* loader, CachedResource* cachedResource)
+{
+ InspectorAgent* inspectorAgent = instrumentingAgents->inspectorAgent();
+ if (!inspectorAgent)
+ return;
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didLoadResourceFromMemoryCache(loader, cachedResource);
+}
+
+InspectorInstrumentationCookie willReceiveResourceDataImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, unsigned long identifier, int length)
+{
+ int timelineAgentId = 0;
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent()) {
+ if (timelineAgent->willReceiveResourceData(frame, identifier, length))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didReceiveResourceDataImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didReceiveResourceData();
+}
+
+InspectorInstrumentationCookie willReceiveResourceResponseImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, unsigned long identifier, const ResourceResponse& response)
+{
+ int timelineAgentId = 0;
+ InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent();
+ if (timelineAgent) {
+ if (timelineAgent->willReceiveResourceResponse(frame, identifier, response))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didReceiveResourceResponseImpl(const InspectorInstrumentationCookie& cookie, unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didReceiveResourceResponse(identifier, loader, response, resourceLoader);
+ if (InspectorResourceAgent* resourceAgent = cookie.instrumentingAgents()->inspectorResourceAgent())
+ resourceAgent->didReceiveResourceResponse(identifier, loader, response, resourceLoader);
+ if (InspectorConsoleAgent* consoleAgent = cookie.instrumentingAgents()->inspectorConsoleAgent())
+ consoleAgent->didReceiveResourceResponse(identifier, loader, response, resourceLoader); // This should come AFTER resource notification, front-end relies on this.
+}
+
+void didReceiveResourceResponseButCanceledImpl(Frame* frame, DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r)
+{
+ InspectorInstrumentationCookie cookie = willReceiveResourceResponse(frame, identifier, r);
+ didReceiveResourceResponse(cookie, identifier, loader, r, 0);
+}
+
+void continueAfterXFrameOptionsDeniedImpl(Frame* frame, DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r)
+{
+ didReceiveResourceResponseButCanceledImpl(frame, loader, identifier, r);
+}
+
+void continueWithPolicyDownloadImpl(Frame* frame, DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r)
+{
+ didReceiveResourceResponseButCanceledImpl(frame, loader, identifier, r);
+}
+
+void continueWithPolicyIgnoreImpl(Frame* frame, DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r)
+{
+ didReceiveResourceResponseButCanceledImpl(frame, loader, identifier, r);
+}
+
+void didReceiveDataImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didReceiveData(identifier, data, dataLength, encodedDataLength);
+}
+
+void didFinishLoadingImpl(InstrumentingAgents* instrumentingAgents, DocumentLoader* loader, unsigned long identifier, double monotonicFinishTime)
+{
+ InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent();
+ InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent();
+ if (!timelineAgent && !resourceAgent)
+ return;
+
+ double finishTime = 0.0;
+ // FIXME: Expose all of the timing details to inspector and have it calculate finishTime.
+ if (monotonicFinishTime)
+ finishTime = loader->timing()->monotonicTimeToPseudoWallTime(monotonicFinishTime);
+
+ if (timelineAgent)
+ timelineAgent->didFinishLoadingResource(identifier, false, finishTime, loader->frame());
+ if (resourceAgent)
+ resourceAgent->didFinishLoading(identifier, loader, finishTime);
+}
+
+void didFailLoadingImpl(InstrumentingAgents* instrumentingAgents, DocumentLoader* loader, unsigned long identifier, const ResourceError& error)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didFailLoading(identifier, loader, error);
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didFailLoading(identifier, loader, error);
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->didFailLoading(identifier, loader, error); // This should come AFTER resource notification, front-end relies on this.
+}
+
+void documentThreadableLoaderStartedLoadingForClientImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, ThreadableLoaderClient* client)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->documentThreadableLoaderStartedLoadingForClient(identifier, client);
+}
+
+void willLoadXHRImpl(InstrumentingAgents* instrumentingAgents, ThreadableLoaderClient* client, const String& method, const KURL& url, bool async, PassRefPtr<FormData> formData, const HTTPHeaderMap& headers, bool includeCredentials)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->willLoadXHR(client, method, url, async, formData, headers, includeCredentials);
+}
+
+void didFailXHRLoadingImpl(InstrumentingAgents* instrumentingAgents, ThreadableLoaderClient* client)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didFailXHRLoading(client);
+}
+
+void didFinishXHRLoadingImpl(InstrumentingAgents* instrumentingAgents, ThreadableLoaderClient* client, unsigned long identifier, const String& sourceString, const String& url, const String& sendURL, unsigned sendLineNumber)
+{
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->didFinishXHRLoading(client, identifier, sourceString, url, sendURL, sendLineNumber);
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didFinishXHRLoading(client, identifier, sourceString, url, sendURL, sendLineNumber);
+}
+
+void didReceiveXHRResponseImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didReceiveXHRResponse(identifier);
+}
+
+void willLoadXHRSynchronouslyImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->willLoadXHRSynchronously();
+}
+
+void didLoadXHRSynchronouslyImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didLoadXHRSynchronously();
+}
+
+void scriptImportedImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, const String& sourceString)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->scriptImported(identifier, sourceString);
+}
+
+void scriptExecutionBlockedByCSPImpl(InstrumentingAgents* instrumentingAgents, const String& directiveText)
+{
+ if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents->inspectorDebuggerAgent())
+ debuggerAgent->scriptExecutionBlockedByCSP(directiveText);
+}
+
+void didReceiveScriptResponseImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didReceiveScriptResponse(identifier);
+}
+
+void domContentLoadedEventFiredImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didMarkDOMContentEvent(frame);
+
+ if (frame->page()->mainFrame() != frame)
+ return;
+
+ if (InspectorAgent* inspectorAgent = instrumentingAgents->inspectorAgent())
+ inspectorAgent->domContentLoadedEventFired();
+
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->mainFrameDOMContentLoaded();
+
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->domContentEventFired();
+}
+
+void loadEventFiredImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->loadEventFired(frame->document());
+
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didMarkLoadEvent(frame);
+
+ if (frame->page()->mainFrame() != frame)
+ return;
+
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->loadEventFired();
+}
+
+void frameDetachedFromParentImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+ canvasAgent->frameDetachedFromParent(frame);
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->frameDetachedFromParent(frame);
+}
+
+void didCommitLoadImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, DocumentLoader* loader)
+{
+ InspectorAgent* inspectorAgent = instrumentingAgents->inspectorAgent();
+ if (!inspectorAgent)
+ return;
+
+ Frame* mainFrame = frame->page()->mainFrame();
+ if (loader->frame() == mainFrame) {
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->reset();
+
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->mainFrameNavigated(loader);
+ if (InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent())
+ cssAgent->reset();
+ if (InspectorDatabaseAgent* databaseAgent = instrumentingAgents->inspectorDatabaseAgent())
+ databaseAgent->clearResources();
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->setDocument(mainFrame->document());
+ if (InspectorLayerTreeAgent* layerTreeAgent = instrumentingAgents->inspectorLayerTreeAgent())
+ layerTreeAgent->reset();
+ inspectorAgent->didCommitLoad();
+ }
+ if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+ canvasAgent->frameNavigated(loader->frame());
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ pageAgent->frameNavigated(loader);
+}
+
+void frameDocumentUpdatedImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ InspectorAgent* inspectorAgent = instrumentingAgents->inspectorAgent();
+ if (!inspectorAgent)
+ return;
+
+ if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
+ domAgent->frameDocumentUpdated(frame);
+}
+
+void loaderDetachedFromFrameImpl(InstrumentingAgents* instrumentingAgents, DocumentLoader* loader)
+{
+ if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents->inspectorPageAgent())
+ inspectorPageAgent->loaderDetachedFromFrame(loader);
+}
+
+void frameStartedLoadingImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents->inspectorPageAgent())
+ inspectorPageAgent->frameStartedLoading(frame);
+}
+
+void frameStoppedLoadingImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents->inspectorPageAgent())
+ inspectorPageAgent->frameStoppedLoading(frame);
+}
+
+void frameScheduledNavigationImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, double delay)
+{
+ if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents->inspectorPageAgent())
+ inspectorPageAgent->frameScheduledNavigation(frame, delay);
+}
+
+void frameClearedScheduledNavigationImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents->inspectorPageAgent())
+ inspectorPageAgent->frameClearedScheduledNavigation(frame);
+}
+
+InspectorInstrumentationCookie willRunJavaScriptDialogImpl(InstrumentingAgents* instrumentingAgents, const String& message)
+{
+ if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents->inspectorPageAgent())
+ inspectorPageAgent->willRunJavaScriptDialog(message);
+ return InspectorInstrumentationCookie(instrumentingAgents, 0);
+}
+
+void didRunJavaScriptDialogImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorPageAgent* inspectorPageAgent = cookie.instrumentingAgents()->inspectorPageAgent())
+ inspectorPageAgent->didRunJavaScriptDialog();
+}
+
+void willDestroyCachedResourceImpl(CachedResource* cachedResource)
+{
+ if (!instrumentingAgentsSet)
+ return;
+ HashSet<InstrumentingAgents*>::iterator end = instrumentingAgentsSet->end();
+ for (HashSet<InstrumentingAgents*>::iterator it = instrumentingAgentsSet->begin(); it != end; ++it) {
+ InstrumentingAgents* instrumentingAgents = *it;
+ if (InspectorResourceAgent* inspectorResourceAgent = instrumentingAgents->inspectorResourceAgent())
+ inspectorResourceAgent->willDestroyCachedResource(cachedResource);
+ }
+}
+
+InspectorInstrumentationCookie willWriteHTMLImpl(InstrumentingAgents* instrumentingAgents, Document* document, unsigned startLine)
+{
+ int timelineAgentId = 0;
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent()) {
+ if (timelineAgent->willWriteHTML(document, startLine))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didWriteHTMLImpl(const InspectorInstrumentationCookie& cookie, unsigned endLine)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didWriteHTML(endLine);
+}
+
+// FIXME: Drop this once we no longer generate stacks outside of Inspector.
+void addMessageToConsoleImpl(InstrumentingAgents* instrumentingAgents, MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier)
+{
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->addMessageToConsole(source, type, level, message, callStack, requestIdentifier);
+ if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents->inspectorDebuggerAgent())
+ debuggerAgent->addMessageToConsole(source, type);
+}
+
+void addMessageToConsoleImpl(InstrumentingAgents* instrumentingAgents, MessageSource source, MessageType type, MessageLevel level, const String& message, ScriptState* state, PassRefPtr<ScriptArguments> arguments, unsigned long requestIdentifier)
+{
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->addMessageToConsole(source, type, level, message, state, arguments, requestIdentifier);
+ if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents->inspectorDebuggerAgent())
+ debuggerAgent->addMessageToConsole(source, type);
+}
+
+void addMessageToConsoleImpl(InstrumentingAgents* instrumentingAgents, MessageSource source, MessageType type, MessageLevel level, const String& message, const String& scriptId, unsigned lineNumber, ScriptState* state, unsigned long requestIdentifier)
+{
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->addMessageToConsole(source, type, level, message, scriptId, lineNumber, state, requestIdentifier);
+}
+
+void consoleCountImpl(InstrumentingAgents* instrumentingAgents, ScriptState* state, PassRefPtr<ScriptArguments> arguments)
+{
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->count(state, arguments);
+}
+
+void startConsoleTimingImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, const String& title)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->time(frame, title);
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->startTiming(title);
+}
+
+void stopConsoleTimingImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, const String& title, PassRefPtr<ScriptCallStack> stack)
+{
+ if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent())
+ consoleAgent->stopTiming(title, stack);
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->timeEnd(frame, title);
+}
+
+void consoleTimeStampImpl(InstrumentingAgents* instrumentingAgents, Frame* frame, PassRefPtr<ScriptArguments> arguments)
+{
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent()) {
+ String message;
+ arguments->getFirstArgumentAsString(message);
+ timelineAgent->didTimeStamp(frame, message);
+ }
+}
+
+void addStartProfilingMessageToConsoleImpl(InstrumentingAgents* instrumentingAgents, const String& title, unsigned lineNumber, const String& sourceURL)
+{
+ if (InspectorProfilerAgent* profilerAgent = instrumentingAgents->inspectorProfilerAgent())
+ profilerAgent->addStartProfilingMessageToConsole(title, lineNumber, sourceURL);
+}
+
+void addProfileImpl(InstrumentingAgents* instrumentingAgents, RefPtr<ScriptProfile> profile, PassRefPtr<ScriptCallStack> callStack)
+{
+ if (InspectorProfilerAgent* profilerAgent = instrumentingAgents->inspectorProfilerAgent()) {
+ const ScriptCallFrame& lastCaller = callStack->at(0);
+ profilerAgent->addProfile(profile, lastCaller.lineNumber(), lastCaller.sourceURL());
+ }
+}
+
+String getCurrentUserInitiatedProfileNameImpl(InstrumentingAgents* instrumentingAgents, bool incrementProfileNumber)
+{
+ if (InspectorProfilerAgent* profilerAgent = instrumentingAgents->inspectorProfilerAgent())
+ return profilerAgent->getCurrentUserInitiatedProfileName(incrementProfileNumber);
+ return "";
+}
+
+bool profilerEnabledImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorProfilerAgent* profilerAgent = instrumentingAgents->inspectorProfilerAgent())
+ return profilerAgent->enabled();
+ return false;
+}
+
+void didOpenDatabaseImpl(InstrumentingAgents* instrumentingAgents, PassRefPtr<Database> database, const String& domain, const String& name, const String& version)
+{
+ InspectorAgent* inspectorAgent = instrumentingAgents->inspectorAgent();
+ if (!inspectorAgent)
+ return;
+ if (InspectorDatabaseAgent* dbAgent = instrumentingAgents->inspectorDatabaseAgent())
+ dbAgent->didOpenDatabase(database, domain, name, version);
+}
+
+void didDispatchDOMStorageEventImpl(InstrumentingAgents* instrumentingAgents, const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin, Page* page)
+{
+ if (InspectorDOMStorageAgent* domStorageAgent = instrumentingAgents->inspectorDOMStorageAgent())
+ domStorageAgent->didDispatchDOMStorageEvent(key, oldValue, newValue, storageType, securityOrigin, page);
+}
+
+bool shouldPauseDedicatedWorkerOnStartImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorWorkerAgent* workerAgent = instrumentingAgents->inspectorWorkerAgent())
+ return workerAgent->shouldPauseDedicatedWorkerOnStart();
+ return false;
+}
+
+void didStartWorkerContextImpl(InstrumentingAgents* instrumentingAgents, WorkerContextProxy* workerContextProxy, const KURL& url)
+{
+ if (InspectorWorkerAgent* workerAgent = instrumentingAgents->inspectorWorkerAgent())
+ workerAgent->didStartWorkerContext(workerContextProxy, url);
+}
+
+void willEvaluateWorkerScript(WorkerContext* workerContext, int workerThreadStartMode)
+{
+ if (workerThreadStartMode != PauseWorkerContextOnStart)
+ return;
+ InstrumentingAgents* instrumentingAgents = instrumentationForWorkerContext(workerContext);
+ if (!instrumentingAgents)
+ return;
+ if (WorkerRuntimeAgent* runtimeAgent = instrumentingAgents->workerRuntimeAgent())
+ runtimeAgent->pauseWorkerContext(workerContext);
+}
+
+void workerContextTerminatedImpl(InstrumentingAgents* instrumentingAgents, WorkerContextProxy* proxy)
+{
+ if (InspectorWorkerAgent* workerAgent = instrumentingAgents->inspectorWorkerAgent())
+ workerAgent->workerContextTerminated(proxy);
+}
+
+void didCreateWebSocketImpl(InstrumentingAgents* instrumentingAgents, Document* document, unsigned long identifier, const KURL& requestURL, const KURL&, const String& protocol)
+{
+ InspectorAgent* inspectorAgent = instrumentingAgents->inspectorAgent();
+ if (!inspectorAgent)
+ return;
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didCreateWebSocket(document, identifier, requestURL, protocol);
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didCreateWebSocket(document, identifier, requestURL, protocol);
+}
+
+void willSendWebSocketHandshakeRequestImpl(InstrumentingAgents* instrumentingAgents, Document* document, unsigned long identifier, const WebSocketHandshakeRequest& request)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->willSendWebSocketHandshakeRequest(document, identifier, request);
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->willSendWebSocketHandshakeRequest(document, identifier, request);
+}
+
+void didReceiveWebSocketHandshakeResponseImpl(InstrumentingAgents* instrumentingAgents, Document* document, unsigned long identifier, const WebSocketHandshakeResponse& response)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didReceiveWebSocketHandshakeResponse(document, identifier, response);
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didReceiveWebSocketHandshakeResponse(document, identifier, response);
+}
+
+void didCloseWebSocketImpl(InstrumentingAgents* instrumentingAgents, Document* document, unsigned long identifier)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didCloseWebSocket(document, identifier);
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didCloseWebSocket(document, identifier);
+}
+
+void didReceiveWebSocketFrameImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, const WebSocketFrame& frame)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didReceiveWebSocketFrame(identifier, frame);
+}
+void didReceiveWebSocketFrameErrorImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, const String& errorMessage)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didReceiveWebSocketFrameError(identifier, errorMessage);
+}
+void didSendWebSocketFrameImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, const WebSocketFrame& frame)
+{
+ if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+ resourceAgent->didSendWebSocketFrame(identifier, frame);
+}
+
+void networkStateChangedImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorApplicationCacheAgent* applicationCacheAgent = instrumentingAgents->inspectorApplicationCacheAgent())
+ applicationCacheAgent->networkStateChanged();
+}
+
+void updateApplicationCacheStatusImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
+{
+ if (InspectorApplicationCacheAgent* applicationCacheAgent = instrumentingAgents->inspectorApplicationCacheAgent())
+ applicationCacheAgent->updateApplicationCacheStatus(frame);
+}
+
+bool collectingHTMLParseErrorsImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorAgent* inspectorAgent = instrumentingAgents->inspectorAgent())
+ return inspectorAgent->hasFrontend();
+ return false;
+}
+
+bool canvasAgentEnabled(ScriptExecutionContext* scriptExecutionContext)
+{
+ InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(scriptExecutionContext);
+ return instrumentingAgents && instrumentingAgents->inspectorCanvasAgent();
+}
+
+bool consoleAgentEnabled(ScriptExecutionContext* scriptExecutionContext)
+{
+ InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(scriptExecutionContext);
+ InspectorConsoleAgent* consoleAgent = instrumentingAgents ? instrumentingAgents->inspectorConsoleAgent() : 0;
+ return consoleAgent && consoleAgent->enabled();
+}
+
+bool timelineAgentEnabled(ScriptExecutionContext* scriptExecutionContext)
+{
+ InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(scriptExecutionContext);
+ return instrumentingAgents && instrumentingAgents->inspectorTimelineAgent();
+}
+
+void pauseOnNativeEventIfNeeded(InstrumentingAgents* instrumentingAgents, bool isDOMEvent, const String& eventName, bool synchronous)
+{
+ if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents->inspectorDOMDebuggerAgent())
+ domDebuggerAgent->pauseOnNativeEventIfNeeded(isDOMEvent, eventName, synchronous);
+}
+
+void cancelPauseOnNativeEvent(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents->inspectorDebuggerAgent())
+ debuggerAgent->cancelPauseOnNextStatement();
+}
+
+void didRequestAnimationFrameImpl(InstrumentingAgents* instrumentingAgents, Document* document, int callbackId)
+{
+ pauseOnNativeEventIfNeeded(instrumentingAgents, false, requestAnimationFrameEventName, true);
+
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didRequestAnimationFrame(document, callbackId);
+}
+
+void didCancelAnimationFrameImpl(InstrumentingAgents* instrumentingAgents, Document* document, int callbackId)
+{
+ pauseOnNativeEventIfNeeded(instrumentingAgents, false, cancelAnimationFrameEventName, true);
+
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent())
+ timelineAgent->didCancelAnimationFrame(document, callbackId);
+}
+
+InspectorInstrumentationCookie willFireAnimationFrameImpl(InstrumentingAgents* instrumentingAgents, Document* document, int callbackId)
+{
+ pauseOnNativeEventIfNeeded(instrumentingAgents, false, animationFrameFiredEventName, false);
+
+ int timelineAgentId = 0;
+ if (InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent()) {
+ if (timelineAgent->willFireAnimationFrame(document, callbackId))
+ timelineAgentId = timelineAgent->id();
+ }
+ return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
+}
+
+void didFireAnimationFrameImpl(const InspectorInstrumentationCookie& cookie)
+{
+ if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
+ timelineAgent->didFireAnimationFrame();
+}
+
+void registerInstrumentingAgents(InstrumentingAgents* instrumentingAgents)
+{
+ if (!instrumentingAgentsSet)
+ instrumentingAgentsSet = new HashSet<InstrumentingAgents*>();
+ instrumentingAgentsSet->add(instrumentingAgents);
+}
+
+void unregisterInstrumentingAgents(InstrumentingAgents* instrumentingAgents)
+{
+ if (!instrumentingAgentsSet)
+ return;
+ instrumentingAgentsSet->remove(instrumentingAgents);
+ if (instrumentingAgentsSet->isEmpty()) {
+ delete instrumentingAgentsSet;
+ instrumentingAgentsSet = 0;
+ }
+}
+
+InspectorTimelineAgent* retrieveTimelineAgent(const InspectorInstrumentationCookie& cookie)
+{
+ if (!cookie.instrumentingAgents())
+ return 0;
+ InspectorTimelineAgent* timelineAgent = cookie.instrumentingAgents()->inspectorTimelineAgent();
+ if (timelineAgent && cookie.hasMatchingTimelineAgentId(timelineAgent->id()))
+ return timelineAgent;
+ return 0;
+}
+
+InstrumentingAgents* instrumentingAgentsForPage(Page* page)
+{
+ if (!page)
+ return 0;
+ return instrumentationForPage(page);
+}
+
+InstrumentingAgents* instrumentingAgentsForRenderer(RenderObject* renderer)
+{
+ return instrumentingAgentsForFrame(renderer->frame());
+}
+
+InstrumentingAgents* instrumentingAgentsForWorkerContext(WorkerContext* workerContext)
+{
+ if (!workerContext)
+ return 0;
+ return instrumentationForWorkerContext(workerContext);
+}
+
+InstrumentingAgents* instrumentingAgentsForNonDocumentContext(ScriptExecutionContext* context)
+{
+ if (context->isWorkerContext())
+ return instrumentationForWorkerContext(static_cast<WorkerContext*>(context));
+ return 0;
+}
+
+GeolocationPosition* overrideGeolocationPositionImpl(InstrumentingAgents* instrumentingAgents, GeolocationPosition* position)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ position = pageAgent->overrideGeolocationPosition(position);
+ return position;
+}
+
+DeviceOrientationData* overrideDeviceOrientationImpl(InstrumentingAgents* instrumentingAgents, DeviceOrientationData* deviceOrientation)
+{
+ if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
+ deviceOrientation = pageAgent->overrideDeviceOrientation(deviceOrientation);
+ return deviceOrientation;
+}
+
+void layerTreeDidChangeImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorLayerTreeAgent* layerTreeAgent = instrumentingAgents->inspectorLayerTreeAgent())
+ layerTreeAgent->layerTreeDidChange();
+}
+
+void renderLayerDestroyedImpl(InstrumentingAgents* instrumentingAgents, const RenderLayer* renderLayer)
+{
+ if (InspectorLayerTreeAgent* layerTreeAgent = instrumentingAgents->inspectorLayerTreeAgent())
+ layerTreeAgent->renderLayerDestroyed(renderLayer);
+}
+
+void pseudoElementDestroyedImpl(InstrumentingAgents* instrumentingAgents, PseudoElement* pseudoElement)
+{
+ if (InspectorLayerTreeAgent* layerTreeAgent = instrumentingAgents->inspectorLayerTreeAgent())
+ layerTreeAgent->pseudoElementDestroyed(pseudoElement);
+}
+
+} // namespace InspectorInstrumentation
+
+namespace InstrumentationEvents {
+const char PaintLayer[] = "PaintLayer";
+const char RasterTask[] = "RasterTask";
+const char Paint[] = "Paint";
+const char Layer[] = "Layer";
+const char BeginFrame[] = "BeginFrame";
+};
+
+namespace InstrumentationEventArguments {
+const char LayerId[] = "layerId";
+const char PageId[] = "pageId";
+};
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorInstrumentation.h b/Source/core/inspector/InspectorInstrumentation.h
new file mode 100644
index 0000000..df4e588
--- /dev/null
+++ b/Source/core/inspector/InspectorInstrumentation.h
@@ -0,0 +1,206 @@
+/*
+* Copyright (C) 2010 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 InspectorInstrumentation_h
+#define InspectorInstrumentation_h
+
+#include "bindings/v8/ScriptState.h"
+#include "core/css/CSSImportRule.h"
+#include "core/css/CSSRule.h"
+#include "core/css/CSSSelector.h"
+#include "core/css/CSSStyleSheet.h"
+#include "core/dom/Element.h"
+#include "core/dom/EventContext.h"
+#include "core/dom/ScriptExecutionContext.h"
+#include "core/inspector/ConsoleAPITypes.h"
+#include "core/page/ConsoleTypes.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/platform/network/FormData.h"
+#include "core/rendering/HitTestResult.h"
+#include "core/storage/StorageArea.h"
+#include "modules/websockets/WebSocketFrame.h"
+#include "modules/websockets/WebSocketHandshakeRequest.h"
+#include "modules/websockets/WebSocketHandshakeResponse.h"
+#include <wtf/RefPtr.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class CSSRule;
+class CachedResource;
+class CharacterData;
+class DOMWindow;
+class DOMWrapperWorld;
+class Database;
+class Document;
+class Element;
+class EventContext;
+class DocumentLoader;
+class DocumentStyleSheetCollection;
+class DeviceOrientationData;
+class GeolocationPosition;
+class GraphicsContext;
+class InspectorCSSAgent;
+class InspectorCSSOMWrappers;
+class InspectorTimelineAgent;
+class InstrumentingAgents;
+class KURL;
+class Node;
+class PseudoElement;
+class RenderLayer;
+class RenderLayerBacking;
+class RenderObject;
+class ResourceRequest;
+class ResourceResponse;
+class ScriptArguments;
+class ScriptCallStack;
+class ScriptExecutionContext;
+class ScriptObject;
+class ScriptProfile;
+class SecurityOrigin;
+class ShadowRoot;
+class StorageArea;
+class StyleResolver;
+class StyleRule;
+class StyleSheet;
+class ThreadableLoaderClient;
+class WorkerContext;
+class WorkerContextProxy;
+class XMLHttpRequest;
+
+#define FAST_RETURN_IF_NO_FRONTENDS(value) if (!hasFrontends()) return value;
+
+class InspectorInstrumentationCookie {
+public:
+ InspectorInstrumentationCookie();
+ InspectorInstrumentationCookie(InstrumentingAgents*, int);
+ InspectorInstrumentationCookie(const InspectorInstrumentationCookie&);
+ InspectorInstrumentationCookie& operator=(const InspectorInstrumentationCookie&);
+ ~InspectorInstrumentationCookie();
+
+ InstrumentingAgents* instrumentingAgents() const { return m_instrumentingAgents.get(); }
+ bool isValid() const { return !!m_instrumentingAgents; }
+ bool hasMatchingTimelineAgentId(int id) const { return m_timelineAgentId == id; }
+
+private:
+ RefPtr<InstrumentingAgents> m_instrumentingAgents;
+ int m_timelineAgentId;
+};
+
+namespace InspectorInstrumentation {
+
+class FrontendCounter {
+private:
+ friend void frontendCreated();
+ friend void frontendDeleted();
+ friend bool hasFrontends();
+ static int s_frontendCounter;
+};
+
+inline void frontendCreated() { FrontendCounter::s_frontendCounter += 1; }
+inline void frontendDeleted() { FrontendCounter::s_frontendCounter -= 1; }
+inline bool hasFrontends() { return FrontendCounter::s_frontendCounter; }
+
+void registerInstrumentingAgents(InstrumentingAgents*);
+void unregisterInstrumentingAgents(InstrumentingAgents*);
+
+InstrumentingAgents* instrumentingAgentsForPage(Page*);
+InstrumentingAgents* instrumentingAgentsForFrame(Frame*);
+InstrumentingAgents* instrumentingAgentsForContext(ScriptExecutionContext*);
+InstrumentingAgents* instrumentingAgentsForDocument(Document*);
+InstrumentingAgents* instrumentingAgentsForRenderer(RenderObject*);
+InstrumentingAgents* instrumentingAgentsForElement(Element*);
+
+InstrumentingAgents* instrumentingAgentsForWorkerContext(WorkerContext*);
+InstrumentingAgents* instrumentingAgentsForNonDocumentContext(ScriptExecutionContext*);
+
+} // namespace InspectorInstrumentation
+
+namespace InstrumentationEvents {
+extern const char PaintLayer[];
+extern const char RasterTask[];
+extern const char Paint[];
+extern const char Layer[];
+extern const char BeginFrame[];
+};
+
+namespace InstrumentationEventArguments {
+extern const char LayerId[];
+extern const char PageId[];
+};
+
+namespace InspectorInstrumentation {
+
+inline InstrumentingAgents* instrumentingAgentsForContext(ScriptExecutionContext* context)
+{
+ if (!context)
+ return 0;
+ if (context->isDocument())
+ return instrumentingAgentsForPage(toDocument(context)->page());
+ return instrumentingAgentsForNonDocumentContext(context);
+}
+
+inline InstrumentingAgents* instrumentingAgentsForFrame(Frame* frame)
+{
+ if (frame)
+ return instrumentingAgentsForPage(frame->page());
+ return 0;
+}
+
+inline InstrumentingAgents* instrumentingAgentsForDocument(Document* document)
+{
+ if (document) {
+ Page* page = document->page();
+ if (!page && document->templateDocumentHost())
+ page = document->templateDocumentHost()->page();
+ return instrumentingAgentsForPage(page);
+ }
+ return 0;
+}
+
+inline InstrumentingAgents* instrumentingAgentsForElement(Element* element)
+{
+ return instrumentingAgentsForDocument(element->document());
+}
+
+} // namespace InspectorInstrumentation
+
+} // namespace WebCore
+
+// This file will soon be generated
+#include "InspectorInstrumentationInl.h"
+
+#include "InspectorInstrumentationCustomInl.h"
+
+#include "InspectorOverridesInl.h"
+
+#endif // !defined(InspectorInstrumentation_h)
diff --git a/Source/core/inspector/InspectorInstrumentationCustomInl.h b/Source/core/inspector/InspectorInstrumentationCustomInl.h
new file mode 100644
index 0000000..4de1752
--- /dev/null
+++ b/Source/core/inspector/InspectorInstrumentationCustomInl.h
@@ -0,0 +1,149 @@
+/*
+* Copyright (C) 2013 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 InspectorInstrumentationCustom_inl_h
+#define InspectorInstrumentationCustom_inl_h
+
+namespace WebCore {
+
+namespace InspectorInstrumentation {
+
+bool profilerEnabledImpl(InstrumentingAgents*);
+bool isDebuggerPausedImpl(InstrumentingAgents*);
+void willRemoveDOMNodeImpl(InstrumentingAgents*, Node*);
+void didRemoveDOMNodeImpl(InstrumentingAgents*, Node*);
+void didPushShadowRootImpl(InstrumentingAgents*, Element* host, ShadowRoot*);
+void willPopShadowRootImpl(InstrumentingAgents*, Element* host, ShadowRoot*);
+InspectorInstrumentationCookie willProcessRuleImpl(InstrumentingAgents*, StyleRule*, StyleResolver*);
+void continueAfterXFrameOptionsDeniedImpl(Frame*, DocumentLoader*, unsigned long identifier, const ResourceResponse&);
+void continueWithPolicyDownloadImpl(Frame*, DocumentLoader*, unsigned long identifier, const ResourceResponse&);
+void continueWithPolicyIgnoreImpl(Frame*, DocumentLoader*, unsigned long identifier, const ResourceResponse&);
+void willDestroyCachedResourceImpl(CachedResource*);
+void didDispatchDOMStorageEventImpl(InstrumentingAgents*, const String& key, const String& oldValue, const String& newValue, StorageType, SecurityOrigin*, Page*);
+bool collectingHTMLParseErrorsImpl(InstrumentingAgents*);
+
+bool canvasAgentEnabled(ScriptExecutionContext*);
+bool consoleAgentEnabled(ScriptExecutionContext*);
+bool timelineAgentEnabled(ScriptExecutionContext*);
+void willEvaluateWorkerScript(WorkerContext*, int workerThreadStartMode);
+
+inline bool profilerEnabled(Page* page)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ return profilerEnabledImpl(instrumentingAgents);
+ return false;
+}
+
+inline bool isDebuggerPaused(Frame* frame)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(false);
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ return isDebuggerPausedImpl(instrumentingAgents);
+ return false;
+}
+
+
+inline void willRemoveDOMNode(Document* document, Node* node)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document)) {
+ willRemoveDOMNodeImpl(instrumentingAgents, node);
+ didRemoveDOMNodeImpl(instrumentingAgents, node);
+ }
+}
+
+inline void didPushShadowRoot(Element* host, ShadowRoot* root)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(host->ownerDocument()))
+ didPushShadowRootImpl(instrumentingAgents, host, root);
+}
+
+inline void willPopShadowRoot(Element* host, ShadowRoot* root)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(host->ownerDocument()))
+ willPopShadowRootImpl(instrumentingAgents, host, root);
+}
+
+inline InspectorInstrumentationCookie willProcessRule(Document* document, StyleRule* rule, StyleResolver* styleResolver)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (!rule)
+ return InspectorInstrumentationCookie();
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ return willProcessRuleImpl(instrumentingAgents, rule, styleResolver);
+ return InspectorInstrumentationCookie();
+}
+
+inline void continueAfterXFrameOptionsDenied(Frame* frame, DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ continueAfterXFrameOptionsDeniedImpl(frame, loader, identifier, r);
+}
+
+inline void continueWithPolicyDownload(Frame* frame, DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ continueWithPolicyDownloadImpl(frame, loader, identifier, r);
+}
+
+inline void continueWithPolicyIgnore(Frame* frame, DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ continueWithPolicyIgnoreImpl(frame, loader, identifier, r);
+}
+
+inline void willDestroyCachedResource(CachedResource* cachedResource)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ willDestroyCachedResourceImpl(cachedResource);
+}
+
+inline void didDispatchDOMStorageEvent(const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin, Page* page)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ didDispatchDOMStorageEventImpl(instrumentingAgents, key, oldValue, newValue, storageType, securityOrigin, page);
+}
+
+inline bool collectingHTMLParseErrors(Page* page)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(false);
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ return collectingHTMLParseErrorsImpl(instrumentingAgents);
+ return false;
+}
+
+} // namespace InspectorInstrumentation
+
+} // namespace WebCore
+
+#endif // !defined(InspectorInstrumentationCustom_inl_h)
diff --git a/Source/core/inspector/InspectorInstrumentationInl.h b/Source/core/inspector/InspectorInstrumentationInl.h
new file mode 100644
index 0000000..dffd386
--- /dev/null
+++ b/Source/core/inspector/InspectorInstrumentationInl.h
@@ -0,0 +1,887 @@
+/*
+* Copyright (C) 2013 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 InspectorInstrumentation_inl_h
+#define InspectorInstrumentation_inl_h
+
+namespace WebCore {
+
+namespace InspectorInstrumentation {
+
+void didClearWindowObjectInWorldImpl(InstrumentingAgents*, Frame*, DOMWrapperWorld*);
+void willInsertDOMNodeImpl(InstrumentingAgents*, Node* parent);
+void didInsertDOMNodeImpl(InstrumentingAgents*, Node*);
+void willModifyDOMAttrImpl(InstrumentingAgents*, Element*, const AtomicString& oldValue, const AtomicString& newValue);
+void didModifyDOMAttrImpl(InstrumentingAgents*, Element*, const AtomicString& name, const AtomicString& value);
+void didRemoveDOMAttrImpl(InstrumentingAgents*, Element*, const AtomicString& name);
+void characterDataModifiedImpl(InstrumentingAgents*, CharacterData*);
+void didInvalidateStyleAttrImpl(InstrumentingAgents*, Node*);
+void activeStyleSheetsUpdatedImpl(InstrumentingAgents*, const Vector<RefPtr<StyleSheet> >&);
+void frameWindowDiscardedImpl(InstrumentingAgents*, DOMWindow*);
+void mediaQueryResultChangedImpl(InstrumentingAgents*);
+void didCreateNamedFlowImpl(InstrumentingAgents*, Document*, NamedFlow*);
+void willRemoveNamedFlowImpl(InstrumentingAgents*, Document*, NamedFlow*);
+void didUpdateRegionLayoutImpl(InstrumentingAgents*, Document*, NamedFlow*);
+void willSendXMLHttpRequestImpl(InstrumentingAgents*, const String& url);
+void didScheduleResourceRequestImpl(InstrumentingAgents*, Document*, const String& url);
+void didInstallTimerImpl(InstrumentingAgents*, ScriptExecutionContext*, int timerId, int timeout, bool singleShot);
+void didRemoveTimerImpl(InstrumentingAgents*, ScriptExecutionContext*, int timerId);
+InspectorInstrumentationCookie willCallFunctionImpl(InstrumentingAgents*, ScriptExecutionContext*, const String& scriptName, int scriptLine);
+void didCallFunctionImpl(const InspectorInstrumentationCookie&);
+InspectorInstrumentationCookie willDispatchXHRReadyStateChangeEventImpl(InstrumentingAgents*, ScriptExecutionContext*, XMLHttpRequest*);
+void didDispatchXHRReadyStateChangeEventImpl(const InspectorInstrumentationCookie&);
+InspectorInstrumentationCookie willDispatchEventImpl(InstrumentingAgents*, Document*, const Event&, DOMWindow*, Node*, const EventPath&);
+void didDispatchEventImpl(const InspectorInstrumentationCookie&);
+InspectorInstrumentationCookie willHandleEventImpl(InstrumentingAgents*, Event*);
+void didHandleEventImpl(const InspectorInstrumentationCookie&);
+InspectorInstrumentationCookie willDispatchEventOnWindowImpl(InstrumentingAgents*, const Event&, DOMWindow*);
+void didDispatchEventOnWindowImpl(const InspectorInstrumentationCookie&);
+InspectorInstrumentationCookie willEvaluateScriptImpl(InstrumentingAgents*, Frame*, const String& url, int lineNumber);
+void didEvaluateScriptImpl(const InspectorInstrumentationCookie&);
+void scriptsEnabledImpl(InstrumentingAgents*, bool isEnabled);
+void didCreateIsolatedContextImpl(InstrumentingAgents*, Frame*, ScriptState*, SecurityOrigin*);
+InspectorInstrumentationCookie willFireTimerImpl(InstrumentingAgents*, ScriptExecutionContext*, int timerId);
+void didFireTimerImpl(const InspectorInstrumentationCookie&);
+void didInvalidateLayoutImpl(InstrumentingAgents*, Frame*);
+InspectorInstrumentationCookie willLayoutImpl(InstrumentingAgents*, Frame*);
+void didLayoutImpl(const InspectorInstrumentationCookie&, RenderObject*);
+void didScrollImpl(InstrumentingAgents*);
+void didResizeMainFrameImpl(InstrumentingAgents*);
+InspectorInstrumentationCookie willDispatchXHRLoadEventImpl(InstrumentingAgents*, ScriptExecutionContext*, XMLHttpRequest*);
+void didDispatchXHRLoadEventImpl(const InspectorInstrumentationCookie&);
+void willScrollLayerImpl(InstrumentingAgents*, Frame*);
+void didScrollLayerImpl(InstrumentingAgents*);
+void willPaintImpl(InstrumentingAgents*, RenderObject*);
+void didPaintImpl(InstrumentingAgents*, RenderObject*, GraphicsContext*, const LayoutRect&);
+InspectorInstrumentationCookie willRecalculateStyleImpl(InstrumentingAgents*, Document*);
+void didRecalculateStyleImpl(const InspectorInstrumentationCookie&);
+void didRecalculateStyleForElementImpl(InstrumentingAgents*);
+void didScheduleStyleRecalculationImpl(InstrumentingAgents*, Document*);
+InspectorInstrumentationCookie willMatchRuleImpl(InstrumentingAgents*, StyleRule*, InspectorCSSOMWrappers&, DocumentStyleSheetCollection*);
+void didMatchRuleImpl(const InspectorInstrumentationCookie&, bool matched);
+void didProcessRuleImpl(const InspectorInstrumentationCookie&);
+void applyUserAgentOverrideImpl(InstrumentingAgents*, String*);
+void applyScreenWidthOverrideImpl(InstrumentingAgents*, long*);
+void applyScreenHeightOverrideImpl(InstrumentingAgents*, long*);
+void applyEmulatedMediaImpl(InstrumentingAgents*, String*);
+void willSendRequestImpl(InstrumentingAgents*, unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse);
+void continueAfterPingLoaderImpl(InstrumentingAgents*, unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse&);
+void markResourceAsCachedImpl(InstrumentingAgents*, unsigned long identifier);
+void didLoadResourceFromMemoryCacheImpl(InstrumentingAgents*, DocumentLoader*, CachedResource*);
+InspectorInstrumentationCookie willReceiveResourceDataImpl(InstrumentingAgents*, Frame*, unsigned long identifier, int length);
+void didReceiveResourceDataImpl(const InspectorInstrumentationCookie&);
+InspectorInstrumentationCookie willReceiveResourceResponseImpl(InstrumentingAgents*, Frame*, unsigned long identifier, const ResourceResponse&);
+void didReceiveResourceResponseImpl(const InspectorInstrumentationCookie&, unsigned long identifier, DocumentLoader*, const ResourceResponse&, ResourceLoader*);
+void didReceiveDataImpl(InstrumentingAgents*, unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
+void didFinishLoadingImpl(InstrumentingAgents*, DocumentLoader*, unsigned long identifier, double finishTime);
+void didFailLoadingImpl(InstrumentingAgents*, DocumentLoader*, unsigned long identifier, const ResourceError&);
+void documentThreadableLoaderStartedLoadingForClientImpl(InstrumentingAgents*, unsigned long identifier, ThreadableLoaderClient*);
+void willLoadXHRImpl(InstrumentingAgents*, ThreadableLoaderClient*, const String&, const KURL&, bool, PassRefPtr<FormData>, const HTTPHeaderMap&, bool);
+void didFailXHRLoadingImpl(InstrumentingAgents*, ThreadableLoaderClient*);
+void didFinishXHRLoadingImpl(InstrumentingAgents*, ThreadableLoaderClient*, unsigned long identifier, const String& sourceString, const String& url, const String& sendURL, unsigned sendLineNumber);
+void didReceiveXHRResponseImpl(InstrumentingAgents*, unsigned long identifier);
+void willLoadXHRSynchronouslyImpl(InstrumentingAgents*);
+void didLoadXHRSynchronouslyImpl(InstrumentingAgents*);
+void scriptImportedImpl(InstrumentingAgents*, unsigned long identifier, const String& sourceString);
+void scriptExecutionBlockedByCSPImpl(InstrumentingAgents*, const String& directiveText);
+void didReceiveScriptResponseImpl(InstrumentingAgents*, unsigned long identifier);
+void domContentLoadedEventFiredImpl(InstrumentingAgents*, Frame*);
+void loadEventFiredImpl(InstrumentingAgents*, Frame*);
+void frameDetachedFromParentImpl(InstrumentingAgents*, Frame*);
+void didCommitLoadImpl(InstrumentingAgents*, Frame*, DocumentLoader*);
+void frameDocumentUpdatedImpl(InstrumentingAgents*, Frame*);
+void loaderDetachedFromFrameImpl(InstrumentingAgents*, DocumentLoader*);
+void frameStartedLoadingImpl(InstrumentingAgents*, Frame*);
+void frameStoppedLoadingImpl(InstrumentingAgents*, Frame*);
+void frameScheduledNavigationImpl(InstrumentingAgents*, Frame*, double delay);
+void frameClearedScheduledNavigationImpl(InstrumentingAgents*, Frame*);
+InspectorInstrumentationCookie willRunJavaScriptDialogImpl(InstrumentingAgents*, const String& message);
+void didRunJavaScriptDialogImpl(const InspectorInstrumentationCookie&);
+InspectorInstrumentationCookie willWriteHTMLImpl(InstrumentingAgents*, Document*, unsigned startLine);
+void didWriteHTMLImpl(const InspectorInstrumentationCookie&, unsigned endLine);
+void didRequestAnimationFrameImpl(InstrumentingAgents*, Document*, int callbackId);
+void didCancelAnimationFrameImpl(InstrumentingAgents*, Document*, int callbackId);
+InspectorInstrumentationCookie willFireAnimationFrameImpl(InstrumentingAgents*, Document*, int callbackId);
+void didFireAnimationFrameImpl(const InspectorInstrumentationCookie&);
+void didStartWorkerContextImpl(InstrumentingAgents*, WorkerContextProxy*, const KURL&);
+void workerContextTerminatedImpl(InstrumentingAgents*, WorkerContextProxy*);
+void didCreateWebSocketImpl(InstrumentingAgents*, Document*, unsigned long identifier, const KURL& requestURL, const KURL& documentURL, const String& protocol);
+void willSendWebSocketHandshakeRequestImpl(InstrumentingAgents*, Document*, unsigned long identifier, const WebSocketHandshakeRequest&);
+void didReceiveWebSocketHandshakeResponseImpl(InstrumentingAgents*, Document*, unsigned long identifier, const WebSocketHandshakeResponse&);
+void didCloseWebSocketImpl(InstrumentingAgents*, Document*, unsigned long identifier);
+void didReceiveWebSocketFrameImpl(InstrumentingAgents*, unsigned long identifier, const WebSocketFrame&);
+void didSendWebSocketFrameImpl(InstrumentingAgents*, unsigned long identifier, const WebSocketFrame&);
+void didReceiveWebSocketFrameErrorImpl(InstrumentingAgents*, unsigned long identifier, const String&);
+void networkStateChangedImpl(InstrumentingAgents*);
+void updateApplicationCacheStatusImpl(InstrumentingAgents*, Frame*);
+void layerTreeDidChangeImpl(InstrumentingAgents*);
+void renderLayerDestroyedImpl(InstrumentingAgents*, const RenderLayer*);
+void pseudoElementDestroyedImpl(InstrumentingAgents*, PseudoElement*);
+
+inline void didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld* world)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didClearWindowObjectInWorldImpl(instrumentingAgents, frame, world);
+}
+
+inline void willInsertDOMNode(Document* document, Node* parent)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ willInsertDOMNodeImpl(instrumentingAgents, parent);
+}
+
+inline void didInsertDOMNode(Document* document, Node* node)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didInsertDOMNodeImpl(instrumentingAgents, node);
+}
+
+
+inline void willModifyDOMAttr(Document* document, Element* element, const AtomicString& oldValue, const AtomicString& newValue)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ willModifyDOMAttrImpl(instrumentingAgents, element, oldValue, newValue);
+}
+
+inline void didModifyDOMAttr(Document* document, Element* element, const AtomicString& name, const AtomicString& value)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didModifyDOMAttrImpl(instrumentingAgents, element, name, value);
+}
+
+inline void didRemoveDOMAttr(Document* document, Element* element, const AtomicString& name)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didRemoveDOMAttrImpl(instrumentingAgents, element, name);
+}
+inline void characterDataModified(Document* document, CharacterData* characterData)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ characterDataModifiedImpl(instrumentingAgents, characterData);
+}
+
+inline void didInvalidateStyleAttr(Document* document, Node* node)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didInvalidateStyleAttrImpl(instrumentingAgents, node);
+}
+
+inline void activeStyleSheetsUpdated(Document* document, const Vector<RefPtr<StyleSheet> >& newSheets)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ activeStyleSheetsUpdatedImpl(instrumentingAgents, newSheets);
+}
+
+inline void frameWindowDiscarded(Frame* frame, DOMWindow* domWindow)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ frameWindowDiscardedImpl(instrumentingAgents, domWindow);
+}
+
+inline void mediaQueryResultChanged(Document* document)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ mediaQueryResultChangedImpl(instrumentingAgents);
+}
+
+
+inline void didCreateNamedFlow(Document* document, NamedFlow* namedFlow)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didCreateNamedFlowImpl(instrumentingAgents, document, namedFlow);
+}
+inline void willRemoveNamedFlow(Document* document, NamedFlow* namedFlow)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ willRemoveNamedFlowImpl(instrumentingAgents, document, namedFlow);
+}
+
+inline void didUpdateRegionLayout(Document* document, NamedFlow* namedFlow)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didUpdateRegionLayoutImpl(instrumentingAgents, document, namedFlow);
+}
+
+inline void willSendXMLHttpRequest(ScriptExecutionContext* context, const String& url)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ willSendXMLHttpRequestImpl(instrumentingAgents, url);
+}
+
+inline void didScheduleResourceRequest(Document* document, const String& url)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didScheduleResourceRequestImpl(instrumentingAgents, document, url);
+}
+
+inline void didInstallTimer(ScriptExecutionContext* context, int timerId, int timeout, bool singleShot)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ didInstallTimerImpl(instrumentingAgents, context, timerId, timeout, singleShot);
+}
+
+inline void didRemoveTimer(ScriptExecutionContext* context, int timerId)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ didRemoveTimerImpl(instrumentingAgents, context, timerId);
+}
+
+inline InspectorInstrumentationCookie willCallFunction(ScriptExecutionContext* context, const String& scriptName, int scriptLine)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ return willCallFunctionImpl(instrumentingAgents, context, scriptName, scriptLine);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didCallFunction(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didCallFunctionImpl(cookie);
+}
+
+inline InspectorInstrumentationCookie willDispatchXHRReadyStateChangeEvent(ScriptExecutionContext* context, XMLHttpRequest* request)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ return willDispatchXHRReadyStateChangeEventImpl(instrumentingAgents, context, request);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didDispatchXHRReadyStateChangeEvent(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didDispatchXHRReadyStateChangeEventImpl(cookie);
+}
+
+inline InspectorInstrumentationCookie willDispatchEvent(Document* document, const Event& event, DOMWindow* window, Node* node, const EventPath& eventPath)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ return willDispatchEventImpl(instrumentingAgents, document, event, window, node, eventPath);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didDispatchEvent(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didDispatchEventImpl(cookie);
+}
+
+inline InspectorInstrumentationCookie willHandleEvent(ScriptExecutionContext* context, Event* event)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ return willHandleEventImpl(instrumentingAgents, event);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didHandleEvent(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didHandleEventImpl(cookie);
+}
+
+inline InspectorInstrumentationCookie willDispatchEventOnWindow(Frame* frame, const Event& event, DOMWindow* window)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ return willDispatchEventOnWindowImpl(instrumentingAgents, event, window);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didDispatchEventOnWindow(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didDispatchEventOnWindowImpl(cookie);
+}
+
+inline InspectorInstrumentationCookie willEvaluateScript(Frame* frame, const String& url, int lineNumber)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ return willEvaluateScriptImpl(instrumentingAgents, frame, url, lineNumber);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didEvaluateScript(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didEvaluateScriptImpl(cookie);
+}
+
+inline void scriptsEnabled(Page* page, bool isEnabled)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ scriptsEnabledImpl(instrumentingAgents, isEnabled);
+}
+
+inline void didCreateIsolatedContext(Frame* frame, ScriptState* scriptState, SecurityOrigin* origin)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didCreateIsolatedContextImpl(instrumentingAgents, frame, scriptState, origin);
+}
+
+inline InspectorInstrumentationCookie willFireTimer(ScriptExecutionContext* context, int timerId)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ return willFireTimerImpl(instrumentingAgents, context, timerId);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didFireTimer(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didFireTimerImpl(cookie);
+}
+
+inline void didInvalidateLayout(Frame* frame)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didInvalidateLayoutImpl(instrumentingAgents, frame);
+}
+
+inline InspectorInstrumentationCookie willLayout(Frame* frame)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ return willLayoutImpl(instrumentingAgents, frame);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didLayout(const InspectorInstrumentationCookie& cookie, RenderObject* root)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didLayoutImpl(cookie, root);
+}
+
+inline void didScroll(Page* page)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ didScrollImpl(instrumentingAgents);
+}
+
+inline void didResizeMainFrame(Page* page)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ didResizeMainFrameImpl(instrumentingAgents);
+}
+
+inline InspectorInstrumentationCookie willDispatchXHRLoadEvent(ScriptExecutionContext* context, XMLHttpRequest* request)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ return willDispatchXHRLoadEventImpl(instrumentingAgents, context, request);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didDispatchXHRLoadEvent(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didDispatchXHRLoadEventImpl(cookie);
+}
+
+inline void willScrollLayer(Frame* frame)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ willScrollLayerImpl(instrumentingAgents, frame);
+}
+
+inline void didScrollLayer(Frame* frame)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didScrollLayerImpl(instrumentingAgents);
+}
+
+inline void willPaint(RenderObject* renderer)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForRenderer(renderer))
+ willPaintImpl(instrumentingAgents, renderer);
+}
+
+inline void didPaint(RenderObject* renderer, GraphicsContext* context, const LayoutRect& rect)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForRenderer(renderer))
+ didPaintImpl(instrumentingAgents, renderer, context, rect);
+}
+
+inline InspectorInstrumentationCookie willRecalculateStyle(Document* document)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ return willRecalculateStyleImpl(instrumentingAgents, document);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didRecalculateStyle(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didRecalculateStyleImpl(cookie);
+}
+
+inline void didRecalculateStyleForElement(Element* element)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForElement(element))
+ didRecalculateStyleForElementImpl(instrumentingAgents);
+}
+
+inline void didScheduleStyleRecalculation(Document* document)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didScheduleStyleRecalculationImpl(instrumentingAgents, document);
+}
+
+inline InspectorInstrumentationCookie willMatchRule(Document* document, StyleRule* rule, InspectorCSSOMWrappers& inspectorCSSOMWrappers, DocumentStyleSheetCollection* styleSheetCollection)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ return willMatchRuleImpl(instrumentingAgents, rule, inspectorCSSOMWrappers, styleSheetCollection);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didMatchRule(const InspectorInstrumentationCookie& cookie, bool matched)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didMatchRuleImpl(cookie, matched);
+}
+
+inline void didProcessRule(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didProcessRuleImpl(cookie);
+}
+
+inline void applyUserAgentOverride(Frame* frame, String* userAgent)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ applyUserAgentOverrideImpl(instrumentingAgents, userAgent);
+}
+
+inline void applyScreenWidthOverride(Frame* frame, long* width)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ applyScreenWidthOverrideImpl(instrumentingAgents, width);
+}
+
+inline void applyScreenHeightOverride(Frame* frame, long* height)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ applyScreenHeightOverrideImpl(instrumentingAgents, height);
+}
+
+inline void applyEmulatedMedia(Frame* frame, String* media)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ applyEmulatedMediaImpl(instrumentingAgents, media);
+}
+
+inline void willSendRequest(Frame* frame, unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ willSendRequestImpl(instrumentingAgents, identifier, loader, request, redirectResponse);
+}
+
+inline void continueAfterPingLoader(Frame* frame, unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& response)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ continueAfterPingLoaderImpl(instrumentingAgents, identifier, loader, request, response);
+}
+
+inline void markResourceAsCached(Page* page, unsigned long identifier)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ markResourceAsCachedImpl(instrumentingAgents, identifier);
+}
+
+inline void didLoadResourceFromMemoryCache(Page* page, DocumentLoader* loader, CachedResource* resource)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ didLoadResourceFromMemoryCacheImpl(instrumentingAgents, loader, resource);
+}
+
+inline void didReceiveResourceData(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didReceiveResourceDataImpl(cookie);
+}
+
+inline InspectorInstrumentationCookie willReceiveResourceData(Frame* frame, unsigned long identifier, int length)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ return willReceiveResourceDataImpl(instrumentingAgents, frame, identifier, length);
+ return InspectorInstrumentationCookie();
+}
+
+inline InspectorInstrumentationCookie willReceiveResourceResponse(Frame* frame, unsigned long identifier, const ResourceResponse& response)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ return willReceiveResourceResponseImpl(instrumentingAgents, frame, identifier, response);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didReceiveResourceResponse(const InspectorInstrumentationCookie& cookie, unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
+{
+ // Call this unconditionally so that we're able to log to console with no front-end attached.
+ if (cookie.isValid())
+ didReceiveResourceResponseImpl(cookie, identifier, loader, response, resourceLoader);
+}
+
+inline void didReceiveData(Frame* frame, unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didReceiveDataImpl(instrumentingAgents, identifier, data, dataLength, encodedDataLength);
+}
+
+inline void didFinishLoading(Frame* frame, DocumentLoader* loader, unsigned long identifier, double finishTime)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didFinishLoadingImpl(instrumentingAgents, loader, identifier, finishTime);
+}
+
+inline void didFailLoading(Frame* frame, DocumentLoader* loader, unsigned long identifier, const ResourceError& error)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didFailLoadingImpl(instrumentingAgents, loader, identifier, error);
+}
+
+inline void documentThreadableLoaderStartedLoadingForClient(ScriptExecutionContext* context, unsigned long identifier, ThreadableLoaderClient* client)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ documentThreadableLoaderStartedLoadingForClientImpl(instrumentingAgents, identifier, client);
+}
+
+inline void willLoadXHR(ScriptExecutionContext* context, ThreadableLoaderClient* client, const String& method, const KURL& url, bool async, PassRefPtr<FormData> formData, const HTTPHeaderMap& headers, bool includeCredentials)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ willLoadXHRImpl(instrumentingAgents, client, method, url, async, formData, headers, includeCredentials);
+}
+
+inline void didFailXHRLoading(ScriptExecutionContext* context, ThreadableLoaderClient* client)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ didFailXHRLoadingImpl(instrumentingAgents, client);
+}
+
+inline void didFinishXHRLoading(ScriptExecutionContext* context, ThreadableLoaderClient* client, unsigned long identifier, const String& sourceString, const String& url, const String& sendURL, unsigned sendLineNumber)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ didFinishXHRLoadingImpl(instrumentingAgents, client, identifier, sourceString, url, sendURL, sendLineNumber);
+}
+
+inline void didReceiveXHRResponse(ScriptExecutionContext* context, unsigned long identifier)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ didReceiveXHRResponseImpl(instrumentingAgents, identifier);
+}
+
+inline void willLoadXHRSynchronously(ScriptExecutionContext* context)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ willLoadXHRSynchronouslyImpl(instrumentingAgents);
+}
+
+inline void didLoadXHRSynchronously(ScriptExecutionContext* context)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ didLoadXHRSynchronouslyImpl(instrumentingAgents);
+}
+
+inline void scriptImported(ScriptExecutionContext* context, unsigned long identifier, const String& sourceString)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ scriptImportedImpl(instrumentingAgents, identifier, sourceString);
+}
+
+inline void scriptExecutionBlockedByCSP(ScriptExecutionContext* context, const String& directiveText)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ scriptExecutionBlockedByCSPImpl(instrumentingAgents, directiveText);
+}
+
+inline void didReceiveScriptResponse(ScriptExecutionContext* context, unsigned long identifier)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ didReceiveScriptResponseImpl(instrumentingAgents, identifier);
+}
+
+inline void domContentLoadedEventFired(Frame* frame)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ domContentLoadedEventFiredImpl(instrumentingAgents, frame);
+}
+
+inline void loadEventFired(Frame* frame)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ loadEventFiredImpl(instrumentingAgents, frame);
+}
+
+inline void frameDetachedFromParent(Frame* frame)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ frameDetachedFromParentImpl(instrumentingAgents, frame);
+}
+
+inline void didCommitLoad(Frame* frame, DocumentLoader* loader)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didCommitLoadImpl(instrumentingAgents, frame, loader);
+}
+
+inline void frameDocumentUpdated(Frame* frame)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ frameDocumentUpdatedImpl(instrumentingAgents, frame);
+}
+
+inline void loaderDetachedFromFrame(Frame* frame, DocumentLoader* loader)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ loaderDetachedFromFrameImpl(instrumentingAgents, loader);
+}
+
+inline void frameStartedLoading(Frame* frame)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ frameStartedLoadingImpl(instrumentingAgents, frame);
+}
+
+inline void frameStoppedLoading(Frame* frame)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ frameStoppedLoadingImpl(instrumentingAgents, frame);
+}
+
+inline void frameScheduledNavigation(Frame* frame, double delay)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ frameScheduledNavigationImpl(instrumentingAgents, frame, delay);
+}
+
+inline void frameClearedScheduledNavigation(Frame* frame)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ frameClearedScheduledNavigationImpl(instrumentingAgents, frame);
+}
+
+inline InspectorInstrumentationCookie willRunJavaScriptDialog(Page* page, const String& message)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ return willRunJavaScriptDialogImpl(instrumentingAgents, message);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didRunJavaScriptDialog(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didRunJavaScriptDialogImpl(cookie);
+}
+
+inline InspectorInstrumentationCookie willWriteHTML(Document* document, unsigned startLine)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ return willWriteHTMLImpl(instrumentingAgents, document, startLine);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didWriteHTML(const InspectorInstrumentationCookie& cookie, unsigned endLine)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didWriteHTMLImpl(cookie, endLine);
+}
+
+inline void didRequestAnimationFrame(Document* document, int callbackId)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didRequestAnimationFrameImpl(instrumentingAgents, document, callbackId);
+}
+
+inline void didCancelAnimationFrame(Document* document, int callbackId)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didCancelAnimationFrameImpl(instrumentingAgents, document, callbackId);
+}
+
+inline InspectorInstrumentationCookie willFireAnimationFrame(Document* document, int callbackId)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ return willFireAnimationFrameImpl(instrumentingAgents, document, callbackId);
+ return InspectorInstrumentationCookie();
+}
+
+inline void didFireAnimationFrame(const InspectorInstrumentationCookie& cookie)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (cookie.isValid())
+ didFireAnimationFrameImpl(cookie);
+}
+
+inline void didStartWorkerContext(ScriptExecutionContext* context, WorkerContextProxy* proxy, const KURL& url)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ didStartWorkerContextImpl(instrumentingAgents, proxy, url);
+}
+
+inline void workerContextTerminated(ScriptExecutionContext* context, WorkerContextProxy* proxy)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ workerContextTerminatedImpl(instrumentingAgents, proxy);
+}
+
+inline void didCreateWebSocket(Document* document, unsigned long identifier, const KURL& requestURL, const KURL& documentURL, const String& protocol)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didCreateWebSocketImpl(instrumentingAgents, document, identifier, requestURL, documentURL, protocol);
+}
+
+inline void willSendWebSocketHandshakeRequest(Document* document, unsigned long identifier, const WebSocketHandshakeRequest& request)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ willSendWebSocketHandshakeRequestImpl(instrumentingAgents, document, identifier, request);
+}
+
+inline void didReceiveWebSocketHandshakeResponse(Document* document, unsigned long identifier, const WebSocketHandshakeResponse& response)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didReceiveWebSocketHandshakeResponseImpl(instrumentingAgents, document, identifier, response);
+}
+
+inline void didCloseWebSocket(Document* document, unsigned long identifier)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didCloseWebSocketImpl(instrumentingAgents, document, identifier);
+}
+
+inline void didReceiveWebSocketFrame(Document* document, unsigned long identifier, const WebSocketFrame& frame)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didReceiveWebSocketFrameImpl(instrumentingAgents, identifier, frame);
+}
+
+inline void didSendWebSocketFrame(Document* document, unsigned long identifier, const WebSocketFrame& frame)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didSendWebSocketFrameImpl(instrumentingAgents, identifier, frame);
+}
+
+inline void didReceiveWebSocketFrameError(Document* document, unsigned long identifier, const String& errorMessage)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+ didReceiveWebSocketFrameErrorImpl(instrumentingAgents, identifier, errorMessage);
+}
+
+inline void networkStateChanged(Page* page)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ networkStateChangedImpl(instrumentingAgents);
+}
+
+inline void updateApplicationCacheStatus(Frame* frame)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ updateApplicationCacheStatusImpl(instrumentingAgents, frame);
+}
+
+inline void layerTreeDidChange(Page* page)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ layerTreeDidChangeImpl(instrumentingAgents);
+}
+
+inline void renderLayerDestroyed(Page* page, const RenderLayer* renderLayer)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ renderLayerDestroyedImpl(instrumentingAgents, renderLayer);
+}
+
+inline void pseudoElementDestroyed(Page* page, PseudoElement* pseudoElement)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ pseudoElementDestroyedImpl(instrumentingAgents, pseudoElement);
+}
+
+} // namespace InspectorInstrumentation
+
+} // namespace WebCore
+
+#endif // !defined(InspectorInstrumentation_inl_h)
diff --git a/Source/core/inspector/InspectorLayerTreeAgent.cpp b/Source/core/inspector/InspectorLayerTreeAgent.cpp
new file mode 100644
index 0000000..9b2f06e
--- /dev/null
+++ b/Source/core/inspector/InspectorLayerTreeAgent.cpp
@@ -0,0 +1,351 @@
+/*
+ * 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorLayerTreeAgent.h"
+
+#include "InspectorFrontend.h"
+#include "core/dom/PseudoElement.h"
+#include "core/inspector/IdentifiersFactory.h"
+#include "core/inspector/InspectorDOMAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/platform/graphics/IntRect.h"
+#include "core/rendering/RenderLayer.h"
+#include "core/rendering/RenderLayerBacking.h"
+#include "core/rendering/RenderLayerCompositor.h"
+#include "core/rendering/RenderView.h"
+
+namespace WebCore {
+
+namespace LayerTreeAgentState {
+static const char layerTreeAgentEnabled[] = "layerTreeAgentEnabled";
+};
+
+InspectorLayerTreeAgent::InspectorLayerTreeAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state)
+ : InspectorBaseAgent<InspectorLayerTreeAgent>("LayerTree", instrumentingAgents, state)
+ , m_frontend(0)
+{
+}
+
+InspectorLayerTreeAgent::~InspectorLayerTreeAgent()
+{
+ reset();
+}
+
+void InspectorLayerTreeAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->layertree();
+}
+
+void InspectorLayerTreeAgent::clearFrontend()
+{
+ m_frontend = 0;
+ disable(0);
+}
+
+void InspectorLayerTreeAgent::restore()
+{
+ if (m_state->getBoolean(LayerTreeAgentState::layerTreeAgentEnabled))
+ enable(0);
+}
+
+void InspectorLayerTreeAgent::reset()
+{
+ m_documentLayerToIdMap.clear();
+ m_idToLayer.clear();
+ m_pseudoElementToIdMap.clear();
+ m_idToPseudoElement.clear();
+}
+
+void InspectorLayerTreeAgent::enable(ErrorString*)
+{
+ m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, true);
+ m_instrumentingAgents->setInspectorLayerTreeAgent(this);
+}
+
+void InspectorLayerTreeAgent::disable(ErrorString*)
+{
+ if (!m_state->getBoolean(LayerTreeAgentState::layerTreeAgentEnabled))
+ return;
+ m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, false);
+ m_instrumentingAgents->setInspectorLayerTreeAgent(0);
+}
+
+void InspectorLayerTreeAgent::layerTreeDidChange()
+{
+ m_frontend->layerTreeDidChange();
+}
+
+void InspectorLayerTreeAgent::renderLayerDestroyed(const RenderLayer* renderLayer)
+{
+ unbind(renderLayer);
+}
+
+void InspectorLayerTreeAgent::pseudoElementDestroyed(PseudoElement* pseudoElement)
+{
+ unbindPseudoElement(pseudoElement);
+}
+
+void InspectorLayerTreeAgent::layersForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
+{
+ layers = TypeBuilder::Array<TypeBuilder::LayerTree::Layer>::create();
+
+ Node* node = m_instrumentingAgents->inspectorDOMAgent()->nodeForId(nodeId);
+ if (!node) {
+ *errorString = "Provided node id doesn't match any known node";
+ return;
+ }
+
+ RenderObject* renderer = node->renderer();
+ if (!renderer) {
+ *errorString = "Node for provided node id doesn't have a renderer";
+ return;
+ }
+
+ gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers);
+}
+
+void InspectorLayerTreeAgent::gatherLayersUsingRenderObjectHierarchy(ErrorString* errorString, RenderObject* renderer, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
+{
+ if (renderer->hasLayer()) {
+ gatherLayersUsingRenderLayerHierarchy(errorString, toRenderLayerModelObject(renderer)->layer(), layers);
+ return;
+ }
+
+ for (renderer = renderer->firstChild(); renderer; renderer = renderer->nextSibling())
+ gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers);
+}
+
+void InspectorLayerTreeAgent::gatherLayersUsingRenderLayerHierarchy(ErrorString* errorString, RenderLayer* renderLayer, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
+{
+ if (renderLayer->isComposited())
+ layers->addItem(buildObjectForLayer(errorString, renderLayer));
+
+ for (renderLayer = renderLayer->firstChild(); renderLayer; renderLayer = renderLayer->nextSibling())
+ gatherLayersUsingRenderLayerHierarchy(errorString, renderLayer, layers);
+}
+
+PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(ErrorString* errorString, RenderLayer* renderLayer)
+{
+ RenderObject* renderer = renderLayer->renderer();
+ RenderLayerBacking* backing = renderLayer->backing();
+ Node* node = renderer->node();
+
+ bool isReflection = renderLayer->isReflection();
+ bool isGenerated = (isReflection ? renderer->parent() : renderer)->isBeforeOrAfterContent();
+
+ if (isReflection && isGenerated)
+ node = renderer->parent()->generatingNode();
+ else if (isGenerated)
+ node = renderer->generatingNode();
+ else if (isReflection)
+ node = renderer->parent()->node();
+
+ // Basic set of properties.
+ RefPtr<TypeBuilder::LayerTree::Layer> layerObject = TypeBuilder::LayerTree::Layer::create()
+ .setLayerId(bind(renderLayer))
+ .setNodeId(idForNode(errorString, node))
+ .setBounds(buildObjectForIntRect(enclosingIntRect(renderer->absoluteBoundingBoxRect())))
+ .setMemory(backing->backingStoreMemoryEstimate())
+ .setCompositedBounds(buildObjectForIntRect(backing->compositedBounds()))
+ .setPaintCount(backing->graphicsLayer()->repaintCount());
+
+ if (node && node->shadowHost())
+ layerObject->setIsInShadowTree(true);
+
+ if (isReflection)
+ layerObject->setIsReflection(true);
+
+ if (isGenerated) {
+ if (isReflection)
+ renderer = renderer->parent();
+ layerObject->setIsGeneratedContent(true);
+ layerObject->setPseudoElementId(bindPseudoElement(static_cast<PseudoElement*>(renderer->node())));
+ if (renderer->isBeforeContent())
+ layerObject->setPseudoClass("before");
+ else if (renderer->isAfterContent())
+ layerObject->setPseudoClass("after");
+ }
+
+ return layerObject;
+}
+
+int InspectorLayerTreeAgent::idForNode(ErrorString* errorString, Node* node)
+{
+ InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent();
+
+ int nodeId = domAgent->boundNodeId(node);
+ if (!nodeId)
+ nodeId = domAgent->pushNodeToFrontend(errorString, domAgent->boundNodeId(node->document()), node);
+
+ return nodeId;
+}
+
+PassRefPtr<TypeBuilder::LayerTree::IntRect> InspectorLayerTreeAgent::buildObjectForIntRect(const IntRect& rect)
+{
+ return TypeBuilder::LayerTree::IntRect::create()
+ .setX(rect.x())
+ .setY(rect.y())
+ .setWidth(rect.width())
+ .setHeight(rect.height()).release();
+}
+
+void InspectorLayerTreeAgent::reasonsForCompositingLayer(ErrorString* errorString, const String& layerId, RefPtr<TypeBuilder::LayerTree::CompositingReasons>& compositingReasons)
+{
+ const RenderLayer* renderLayer = m_idToLayer.get(layerId);
+
+ if (!renderLayer) {
+ *errorString = "Could not find a bound layer for the provided id";
+ return;
+ }
+
+ CompositingReasons reasonsBitmask = renderLayer->compositor()->reasonsForCompositing(renderLayer);
+ compositingReasons = TypeBuilder::LayerTree::CompositingReasons::create();
+
+ if (reasonsBitmask & CompositingReason3DTransform)
+ compositingReasons->setTransform3D(true);
+
+ if (reasonsBitmask & CompositingReasonVideo)
+ compositingReasons->setVideo(true);
+
+ if (reasonsBitmask & CompositingReasonCanvas)
+ compositingReasons->setCanvas(true);
+
+ if (reasonsBitmask & CompositingReasonPlugin)
+ compositingReasons->setPlugin(true);
+
+ if (reasonsBitmask & CompositingReasonIFrame)
+ compositingReasons->setIFrame(true);
+
+ if (reasonsBitmask & CompositingReasonBackfaceVisibilityHidden)
+ compositingReasons->setBackfaceVisibilityHidden(true);
+
+ if (reasonsBitmask & CompositingReasonClipsCompositingDescendants)
+ compositingReasons->setClipsCompositingDescendants(true);
+
+ if (reasonsBitmask & CompositingReasonAnimation)
+ compositingReasons->setAnimation(true);
+
+ if (reasonsBitmask & CompositingReasonFilters)
+ compositingReasons->setFilters(true);
+
+ if (reasonsBitmask & CompositingReasonPositionFixed)
+ compositingReasons->setPositionFixed(true);
+
+ if (reasonsBitmask & CompositingReasonPositionSticky)
+ compositingReasons->setPositionSticky(true);
+
+ if (reasonsBitmask & CompositingReasonOverflowScrollingTouch)
+ compositingReasons->setOverflowScrollingTouch(true);
+
+ if (reasonsBitmask & CompositingReasonStacking)
+ compositingReasons->setStacking(true);
+
+ if (reasonsBitmask & CompositingReasonOverlap)
+ compositingReasons->setOverlap(true);
+
+ if (reasonsBitmask & CompositingReasonNegativeZIndexChildren)
+ compositingReasons->setNegativeZIndexChildren(true);
+
+ if (reasonsBitmask & CompositingReasonTransformWithCompositedDescendants)
+ compositingReasons->setTransformWithCompositedDescendants(true);
+
+ if (reasonsBitmask & CompositingReasonOpacityWithCompositedDescendants)
+ compositingReasons->setOpacityWithCompositedDescendants(true);
+
+ if (reasonsBitmask & CompositingReasonMaskWithCompositedDescendants)
+ compositingReasons->setMaskWithCompositedDescendants(true);
+
+ if (reasonsBitmask & CompositingReasonReflectionWithCompositedDescendants)
+ compositingReasons->setReflectionWithCompositedDescendants(true);
+
+ if (reasonsBitmask & CompositingReasonFilterWithCompositedDescendants)
+ compositingReasons->setFilterWithCompositedDescendants(true);
+
+ if (reasonsBitmask & CompositingReasonBlendingWithCompositedDescendants)
+ compositingReasons->setBlendingWithCompositedDescendants(true);
+
+ if (reasonsBitmask & CompositingReasonPerspective)
+ compositingReasons->setPerspective(true);
+
+ if (reasonsBitmask & CompositingReasonPreserve3D)
+ compositingReasons->setPreserve3D(true);
+
+ if (reasonsBitmask & CompositingReasonRoot)
+ compositingReasons->setRoot(true);
+}
+
+String InspectorLayerTreeAgent::bind(const RenderLayer* layer)
+{
+ if (!layer)
+ return emptyString();
+ String identifier = m_documentLayerToIdMap.get(layer);
+ if (identifier.isNull()) {
+ identifier = IdentifiersFactory::createIdentifier();
+ m_documentLayerToIdMap.set(layer, identifier);
+ m_idToLayer.set(identifier, layer);
+ }
+ return identifier;
+}
+
+void InspectorLayerTreeAgent::unbind(const RenderLayer* layer)
+{
+ HashMap<const RenderLayer*, String>::iterator iterator = m_documentLayerToIdMap.find(layer);
+ if (iterator == m_documentLayerToIdMap.end())
+ return;
+ m_idToLayer.remove(iterator->value);
+ m_documentLayerToIdMap.remove(iterator);
+}
+
+String InspectorLayerTreeAgent::bindPseudoElement(PseudoElement* pseudoElement)
+{
+ if (!pseudoElement)
+ return emptyString();
+ String identifier = m_pseudoElementToIdMap.get(pseudoElement);
+ if (identifier.isNull()) {
+ identifier = IdentifiersFactory::createIdentifier();
+ m_pseudoElementToIdMap.set(pseudoElement, identifier);
+ m_idToPseudoElement.set(identifier, pseudoElement);
+ }
+ return identifier;
+}
+
+void InspectorLayerTreeAgent::unbindPseudoElement(PseudoElement* pseudoElement)
+{
+ HashMap<PseudoElement*, String>::iterator iterator = m_pseudoElementToIdMap.find(pseudoElement);
+ if (iterator == m_pseudoElementToIdMap.end())
+ return;
+ m_idToPseudoElement.remove(iterator->value);
+ m_pseudoElementToIdMap.remove(iterator);
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InspectorLayerTreeAgent.h b/Source/core/inspector/InspectorLayerTreeAgent.h
new file mode 100644
index 0000000..46ea3e4
--- /dev/null
+++ b/Source/core/inspector/InspectorLayerTreeAgent.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorLayerTreeAgent_h
+#define InspectorLayerTreeAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "InspectorTypeBuilder.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/rendering/RenderLayer.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class InspectorState;
+class InstrumentingAgents;
+
+typedef String ErrorString;
+
+class InspectorLayerTreeAgent : public InspectorBaseAgent<InspectorLayerTreeAgent>, public InspectorBackendDispatcher::LayerTreeCommandHandler {
+public:
+ static PassOwnPtr<InspectorLayerTreeAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state)
+ {
+ return adoptPtr(new InspectorLayerTreeAgent(instrumentingAgents, state));
+ }
+ ~InspectorLayerTreeAgent();
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+ void reset();
+
+ void layerTreeDidChange();
+ void renderLayerDestroyed(const RenderLayer*);
+ void pseudoElementDestroyed(PseudoElement*);
+
+ // Called from the front-end.
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void layersForNode(ErrorString*, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >&);
+ virtual void reasonsForCompositingLayer(ErrorString*, const String& layerId, RefPtr<TypeBuilder::LayerTree::CompositingReasons>&);
+
+private:
+ InspectorLayerTreeAgent(InstrumentingAgents*, InspectorCompositeState*);
+
+ // RenderLayer-related methods.
+ String bind(const RenderLayer*);
+ void unbind(const RenderLayer*);
+
+ void gatherLayersUsingRenderObjectHierarchy(ErrorString*, RenderObject*, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >&);
+ void gatherLayersUsingRenderLayerHierarchy(ErrorString*, RenderLayer*, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >&);
+
+ PassRefPtr<TypeBuilder::LayerTree::Layer> buildObjectForLayer(ErrorString*, RenderLayer*);
+ PassRefPtr<TypeBuilder::LayerTree::IntRect> buildObjectForIntRect(const IntRect&);
+
+ int idForNode(ErrorString*, Node*);
+
+ String bindPseudoElement(PseudoElement*);
+ void unbindPseudoElement(PseudoElement*);
+
+ InspectorFrontend::LayerTree* m_frontend;
+
+ HashMap<const RenderLayer*, String> m_documentLayerToIdMap;
+ HashMap<String, const RenderLayer*> m_idToLayer;
+
+ HashMap<PseudoElement*, String> m_pseudoElementToIdMap;
+ HashMap<String, PseudoElement*> m_idToPseudoElement;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorLayerTreeAgent_h)
diff --git a/Source/core/inspector/InspectorMemoryAgent.cpp b/Source/core/inspector/InspectorMemoryAgent.cpp
new file mode 100644
index 0000000..6ba4bfd
--- /dev/null
+++ b/Source/core/inspector/InspectorMemoryAgent.cpp
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorMemoryAgent.h"
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptGCEvent.h"
+#include "bindings/v8/ScriptProfiler.h"
+#include "core/dom/CharacterData.h"
+#include "core/dom/Document.h"
+#include "core/dom/EventListenerMap.h"
+#include "core/dom/Node.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/StyledElement.h"
+#include "core/inspector/BindingVisitors.h"
+#include "core/inspector/HeapGraphSerializer.h"
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorDOMStorageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/inspector/MemoryInstrumentationImpl.h"
+#include "core/loader/cache/MemoryCache.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/platform/MemoryUsageSupport.h"
+#include <wtf/ArrayBufferView.h>
+#include <wtf/HashSet.h>
+#include <wtf/MemoryInstrumentationArrayBufferView.h>
+#include <wtf/NonCopyingSort.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringImpl.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+// Use a type alias instead of 'using' here which would cause a conflict on Mac.
+typedef WebCore::TypeBuilder::Memory::MemoryBlock InspectorMemoryBlock;
+typedef WebCore::TypeBuilder::Array<InspectorMemoryBlock> InspectorMemoryBlocks;
+
+namespace WebCore {
+
+namespace {
+
+class MemoryUsageStatsGenerator {
+public:
+ MemoryUsageStatsGenerator() { }
+
+ void dump(const TypeNameToSizeMap& sizesMap, InspectorMemoryBlocks* children)
+ {
+ m_sizesMap = sizesMap;
+
+ // FIXME: We filter out Rendering type because the coverage is not good enough at the moment
+ // and report RenderArena size instead.
+ for (TypeNameToSizeMap::iterator i = m_sizesMap.begin(); i != m_sizesMap.end(); ++i) {
+ if (i->key == PlatformMemoryTypes::Rendering) {
+ m_sizesMap.remove(i);
+ break;
+ }
+ }
+ Vector<String> objectTypes;
+ objectTypes.appendRange(m_sizesMap.keys().begin(), m_sizesMap.keys().end());
+
+ for (Vector<String>::const_iterator i = objectTypes.begin(); i != objectTypes.end(); ++i)
+ updateParentSizes(*i, m_sizesMap.get(*i));
+
+ objectTypes.clear();
+ objectTypes.appendRange(m_sizesMap.keys().begin(), m_sizesMap.keys().end());
+ nonCopyingSort(objectTypes.begin(), objectTypes.end(), stringCompare);
+
+ size_t index = 0;
+ while (index < objectTypes.size())
+ index = buildObjectForIndex(index, objectTypes, children);
+
+ }
+
+private:
+ static bool stringCompare(const String& a, const String& b) { return WTF::codePointCompare(a, b) < 0; }
+
+ void updateParentSizes(String objectType, const size_t size)
+ {
+ for (size_t dotPosition = objectType.reverseFind('.'); dotPosition != notFound; dotPosition = objectType.reverseFind('.', dotPosition)) {
+ objectType = objectType.substring(0, dotPosition);
+ TypeNameToSizeMap::AddResult result = m_sizesMap.add(objectType, size);
+ if (!result.isNewEntry)
+ result.iterator->value += size;
+ }
+ }
+
+ size_t buildObjectForIndex(size_t index, const Vector<String>& objectTypes, InspectorMemoryBlocks* array)
+ {
+ String typeName = objectTypes[index];
+ size_t dotPosition = typeName.reverseFind('.');
+ String blockName = (dotPosition == notFound) ? typeName : typeName.substring(dotPosition + 1);
+ RefPtr<InspectorMemoryBlock> block = InspectorMemoryBlock::create().setName(blockName);
+ block->setSize(m_sizesMap.get(typeName));
+ String prefix = typeName;
+ prefix.append('.');
+ array->addItem(block);
+ ++index;
+ RefPtr<InspectorMemoryBlocks> children;
+ while (index < objectTypes.size() && objectTypes[index].startsWith(prefix)) {
+ if (!children)
+ children = InspectorMemoryBlocks::create();
+ index = buildObjectForIndex(index, objectTypes, children.get());
+ }
+ if (children)
+ block->setChildren(children.release());
+ return index;
+ }
+
+ TypeNameToSizeMap m_sizesMap;
+};
+
+class ExternalStringsRoot : public ExternalStringVisitor {
+public:
+ ExternalStringsRoot() : m_memoryClassInfo(0) { }
+
+ void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+ {
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::ExternalStrings);
+ m_memoryClassInfo = &info;
+ ScriptProfiler::visitExternalStrings(const_cast<ExternalStringsRoot*>(this));
+ m_memoryClassInfo = 0;
+ info.ignoreMember(m_memoryClassInfo);
+ }
+
+private:
+ virtual void visitJSExternalString(StringImpl* string)
+ {
+ m_memoryClassInfo->addMember(string, "externalString", WTF::RetainingPointer);
+ }
+
+ mutable MemoryClassInfo* m_memoryClassInfo;
+};
+
+class ExternalArraysRoot : public ExternalArrayVisitor {
+public:
+ ExternalArraysRoot() : m_memoryClassInfo(0) { }
+
+ void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+ {
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::ExternalArrays);
+ m_memoryClassInfo = &info;
+ ScriptProfiler::visitExternalArrays(const_cast<ExternalArraysRoot*>(this));
+ m_memoryClassInfo = 0;
+ info.ignoreMember(m_memoryClassInfo);
+ }
+
+private:
+ virtual void visitJSExternalArray(ArrayBufferView* arrayBufferView)
+ {
+ m_memoryClassInfo->addMember(arrayBufferView, "externalArray", WTF::RetainingPointer);
+ }
+
+ mutable MemoryClassInfo* m_memoryClassInfo;
+};
+
+} // namespace
+
+InspectorMemoryAgent::~InspectorMemoryAgent()
+{
+}
+
+void InspectorMemoryAgent::getDOMCounters(ErrorString*, int* documents, int* nodes, int* jsEventListeners)
+{
+ *documents = InspectorCounters::counterValue(InspectorCounters::DocumentCounter);
+ *nodes = InspectorCounters::counterValue(InspectorCounters::NodeCounter);
+ *jsEventListeners = ThreadLocalInspectorCounters::current().counterValue(ThreadLocalInspectorCounters::JSEventListenerCounter);
+}
+
+static void reportJSHeapInfo(WTF::MemoryInstrumentationClient& memoryInstrumentationClient)
+{
+ HeapInfo info;
+ ScriptGCEvent::getHeapSize(info);
+
+ memoryInstrumentationClient.countObjectSize(0, WebCoreMemoryTypes::JSHeapUsed, info.usedJSHeapSize);
+ memoryInstrumentationClient.countObjectSize(0, WebCoreMemoryTypes::JSHeapUnused, info.totalJSHeapSize - info.usedJSHeapSize);
+}
+
+static void reportRenderTreeInfo(WTF::MemoryInstrumentationClient& memoryInstrumentationClient, Page* page)
+{
+ ArenaSize arenaSize = page->renderTreeSize();
+
+ memoryInstrumentationClient.countObjectSize(0, WebCoreMemoryTypes::RenderTreeUsed, arenaSize.treeSize);
+ memoryInstrumentationClient.countObjectSize(0, WebCoreMemoryTypes::RenderTreeUnused, arenaSize.allocated - arenaSize.treeSize);
+}
+
+namespace {
+
+class DOMTreesIterator : public WrappedNodeVisitor {
+public:
+ DOMTreesIterator(MemoryInstrumentationImpl& memoryInstrumentation, Page* page)
+ : m_page(page)
+ , m_memoryInstrumentation(memoryInstrumentation)
+ {
+ }
+
+ virtual void visitNode(Node* node) OVERRIDE
+ {
+ if (node->document() && node->document()->frame() && m_page != node->document()->frame()->page())
+ return;
+
+ while (Node* parentNode = node->parentNode())
+ node = parentNode;
+
+ m_memoryInstrumentation.addRootObject(node);
+ }
+
+ void visitFrame(Frame* frame)
+ {
+ m_memoryInstrumentation.addRootObject(frame);
+ }
+
+ void visitBindings()
+ {
+ ScriptProfiler::collectBindingMemoryInfo(&m_memoryInstrumentation);
+ }
+
+ void visitMemoryCache()
+ {
+ m_memoryInstrumentation.addRootObject(memoryCache());
+ }
+
+
+private:
+ Page* m_page;
+ MemoryInstrumentationImpl& m_memoryInstrumentation;
+};
+
+}
+
+static void collectDomTreeInfo(MemoryInstrumentationImpl& memoryInstrumentation, Page* page)
+{
+ ExternalStringsRoot stringsRoot;
+ memoryInstrumentation.addRootObject(stringsRoot);
+
+ ExternalArraysRoot arraysRoot;
+ memoryInstrumentation.addRootObject(arraysRoot);
+
+ DOMTreesIterator domTreesIterator(memoryInstrumentation, page);
+
+ ScriptProfiler::visitNodeWrappers(&domTreesIterator);
+
+ // Make sure all documents reachable from the main frame are accounted.
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (Document* doc = frame->document()) {
+ domTreesIterator.visitNode(doc);
+ domTreesIterator.visitFrame(frame);
+ }
+ }
+
+ domTreesIterator.visitBindings();
+ domTreesIterator.visitMemoryCache();
+}
+
+static void addPlatformComponentsInfo(TypeNameToSizeMap* memoryInfo)
+{
+ Vector<MemoryUsageSupport::ComponentInfo> components;
+ MemoryUsageSupport::memoryUsageByComponents(components);
+ for (Vector<MemoryUsageSupport::ComponentInfo>::iterator it = components.begin(); it != components.end(); ++it)
+ memoryInfo->add(it->m_name, it->m_sizeInBytes);
+}
+
+static void addMemoryInstrumentationDebugData(MemoryInstrumentationClientImpl* client, TypeNameToSizeMap* memoryInfo)
+{
+ if (client->checkInstrumentedObjects()) {
+ memoryInfo->add("InstrumentedObjectsCount", client->totalCountedObjects());
+ memoryInfo->add("InstrumentedButNotAllocatedObjectsCount", client->totalObjectsNotInAllocatedSet());
+ }
+}
+
+void InspectorMemoryAgent::getProcessMemoryDistributionMap(TypeNameToSizeMap* memoryInfo)
+{
+ getProcessMemoryDistributionImpl(false, memoryInfo);
+}
+
+void InspectorMemoryAgent::getProcessMemoryDistribution(ErrorString*, const bool* reportGraph, RefPtr<InspectorMemoryBlock>& processMemory, RefPtr<InspectorObject>& graphMetaInformation)
+{
+ TypeNameToSizeMap memoryInfo;
+ graphMetaInformation = getProcessMemoryDistributionImpl(reportGraph && *reportGraph, &memoryInfo);
+
+ MemoryUsageStatsGenerator statsGenerator;
+ RefPtr<InspectorMemoryBlocks> children = InspectorMemoryBlocks::create();
+ statsGenerator.dump(memoryInfo, children.get());
+
+ processMemory = InspectorMemoryBlock::create().setName(WebCoreMemoryTypes::ProcessPrivateMemory);
+ processMemory->setChildren(children);
+
+ size_t privateBytes = 0;
+ size_t sharedBytes = 0;
+ MemoryUsageSupport::processMemorySizesInBytes(&privateBytes, &sharedBytes);
+ processMemory->setSize(privateBytes);
+}
+
+void InspectorMemoryAgent::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Inspector);
+ InspectorBaseAgent<InspectorMemoryAgent>::reportMemoryUsage(memoryObjectInfo);
+ info.addWeakPointer(m_inspectorClient);
+ info.addMember(m_page, "page");
+}
+
+namespace {
+
+class FrontendWrapper : public HeapGraphSerializer::Client {
+public:
+ explicit FrontendWrapper(InspectorFrontend::Memory* frontend) : m_frontend(frontend) { }
+ virtual void addNativeSnapshotChunk(PassRefPtr<TypeBuilder::Memory::HeapSnapshotChunk> heapSnapshotChunk) OVERRIDE
+ {
+ m_frontend->addNativeSnapshotChunk(heapSnapshotChunk);
+ }
+private:
+ InspectorFrontend::Memory* m_frontend;
+};
+
+}
+
+PassRefPtr<InspectorObject> InspectorMemoryAgent::getProcessMemoryDistributionImpl(bool reportGraph, TypeNameToSizeMap* memoryInfo)
+{
+ RefPtr<InspectorObject> meta;
+ OwnPtr<HeapGraphSerializer> graphSerializer;
+ OwnPtr<FrontendWrapper> frontendWrapper;
+
+ if (reportGraph) {
+ frontendWrapper = adoptPtr(new FrontendWrapper(m_frontend));
+ graphSerializer = adoptPtr(new HeapGraphSerializer(frontendWrapper.get()));
+ }
+
+ MemoryInstrumentationClientImpl memoryInstrumentationClient(graphSerializer.get());
+ m_inspectorClient->getAllocatedObjects(memoryInstrumentationClient.allocatedObjects());
+ MemoryInstrumentationImpl memoryInstrumentation(&memoryInstrumentationClient);
+
+ reportJSHeapInfo(memoryInstrumentationClient);
+ reportRenderTreeInfo(memoryInstrumentationClient, m_page);
+ collectDomTreeInfo(memoryInstrumentation, m_page); // FIXME: collect for all pages?
+
+ PlatformMemoryInstrumentation::reportStaticMembersMemoryUsage(&memoryInstrumentation);
+ WebCoreMemoryInstrumentation::reportStaticMembersMemoryUsage(&memoryInstrumentation);
+
+ memoryInstrumentation.addRootObject(this);
+ memoryInstrumentation.addRootObject(memoryInstrumentation);
+ memoryInstrumentation.addRootObject(memoryInstrumentationClient);
+ if (graphSerializer) {
+ memoryInstrumentation.addRootObject(graphSerializer.get());
+ meta = graphSerializer->finish();
+ graphSerializer.release(); // Release it earlier than frontendWrapper
+ frontendWrapper.release();
+ }
+
+ m_inspectorClient->dumpUncountedAllocatedObjects(memoryInstrumentationClient.countedObjects());
+
+ *memoryInfo = memoryInstrumentationClient.sizesMap();
+ addPlatformComponentsInfo(memoryInfo);
+ addMemoryInstrumentationDebugData(&memoryInstrumentationClient, memoryInfo);
+ return meta.release();
+}
+
+InspectorMemoryAgent::InspectorMemoryAgent(InstrumentingAgents* instrumentingAgents, InspectorClient* client, InspectorCompositeState* state, Page* page)
+ : InspectorBaseAgent<InspectorMemoryAgent>("Memory", instrumentingAgents, state)
+ , m_inspectorClient(client)
+ , m_page(page)
+ , m_frontend(0)
+{
+}
+
+void InspectorMemoryAgent::setFrontend(InspectorFrontend* frontend)
+{
+ ASSERT(!m_frontend);
+ m_frontend = frontend->memory();
+}
+
+void InspectorMemoryAgent::clearFrontend()
+{
+ m_frontend = 0;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorMemoryAgent.h b/Source/core/inspector/InspectorMemoryAgent.h
new file mode 100644
index 0000000..0f580c3
--- /dev/null
+++ b/Source/core/inspector/InspectorMemoryAgent.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorMemoryAgent_h
+#define InspectorMemoryAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class InspectorClient;
+class InspectorDOMStorageAgent;
+class InspectorState;
+class InstrumentingAgents;
+class Page;
+
+typedef String ErrorString;
+
+class InspectorMemoryAgent : public InspectorBaseAgent<InspectorMemoryAgent>, public InspectorBackendDispatcher::MemoryCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorMemoryAgent);
+public:
+ typedef Vector<OwnPtr<InspectorBaseAgentInterface> > InspectorAgents;
+
+ static PassOwnPtr<InspectorMemoryAgent> create(InstrumentingAgents* instrumentingAgents, InspectorClient* client, InspectorCompositeState* state, Page* page)
+ {
+ return adoptPtr(new InspectorMemoryAgent(instrumentingAgents, client, state, page));
+ }
+ virtual ~InspectorMemoryAgent();
+
+ virtual void getDOMCounters(ErrorString*, int* documents, int* nodes, int* jsEventListeners);
+ virtual void getProcessMemoryDistribution(ErrorString*, const bool* reportGraph, RefPtr<TypeBuilder::Memory::MemoryBlock>& out_processMemory, RefPtr<InspectorObject>& graphMetaInformation);
+
+ virtual void reportMemoryUsage(MemoryObjectInfo*) const;
+
+ void getProcessMemoryDistributionMap(HashMap<String, size_t>* memoryInfo);
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+
+private:
+ InspectorMemoryAgent(InstrumentingAgents*, InspectorClient*, InspectorCompositeState*, Page*);
+
+ PassRefPtr<InspectorObject> getProcessMemoryDistributionImpl(bool reportGraph, HashMap<String, size_t>* memoryInfo);
+
+ InspectorClient* m_inspectorClient;
+ Page* m_page;
+ InspectorFrontend::Memory* m_frontend;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorMemoryAgent_h)
diff --git a/Source/core/inspector/InspectorOverlay.cpp b/Source/core/inspector/InspectorOverlay.cpp
new file mode 100644
index 0000000..efd9e98
--- /dev/null
+++ b/Source/core/inspector/InspectorOverlay.cpp
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InspectorOverlay.h"
+
+#include "InspectorOverlayPage.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/ScriptSourceCode.h"
+#include "bindings/v8/ScriptValue.h"
+#include "core/dom/Element.h"
+#include "core/dom/Node.h"
+#include "core/dom/StyledElement.h"
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/EmptyClients.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/Settings.h"
+#include "core/platform/graphics/GraphicsContext.h"
+#include "core/rendering/RenderBoxModelObject.h"
+#include "core/rendering/RenderInline.h"
+#include "core/rendering/RenderObject.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+namespace {
+
+Path quadToPath(const FloatQuad& quad)
+{
+ Path quadPath;
+ quadPath.moveTo(quad.p1());
+ quadPath.addLineTo(quad.p2());
+ quadPath.addLineTo(quad.p3());
+ quadPath.addLineTo(quad.p4());
+ quadPath.closeSubpath();
+ return quadPath;
+}
+
+void drawOutlinedQuad(GraphicsContext* context, const FloatQuad& quad, const Color& fillColor, const Color& outlineColor)
+{
+ static const int outlineThickness = 2;
+
+ Path quadPath = quadToPath(quad);
+
+ // Clip out the quad, then draw with a 2px stroke to get a pixel
+ // of outline (because inflating a quad is hard)
+ {
+ context->save();
+ context->clipOut(quadPath);
+
+ context->setStrokeThickness(outlineThickness);
+ context->setStrokeColor(outlineColor, ColorSpaceDeviceRGB);
+ context->strokePath(quadPath);
+
+ context->restore();
+ }
+
+ // Now do the fill
+ context->setFillColor(fillColor, ColorSpaceDeviceRGB);
+ context->fillPath(quadPath);
+}
+
+static void contentsQuadToPage(const FrameView* mainView, const FrameView* view, FloatQuad& quad)
+{
+ quad.setP1(view->contentsToRootView(roundedIntPoint(quad.p1())));
+ quad.setP2(view->contentsToRootView(roundedIntPoint(quad.p2())));
+ quad.setP3(view->contentsToRootView(roundedIntPoint(quad.p3())));
+ quad.setP4(view->contentsToRootView(roundedIntPoint(quad.p4())));
+ quad += mainView->scrollOffset();
+}
+
+static void buildNodeHighlight(Node* node, const HighlightConfig& highlightConfig, Highlight* highlight)
+{
+ RenderObject* renderer = node->renderer();
+ Frame* containingFrame = node->document()->frame();
+
+ if (!renderer || !containingFrame)
+ return;
+
+ highlight->setDataFromConfig(highlightConfig);
+ FrameView* containingView = containingFrame->view();
+ FrameView* mainView = containingFrame->page()->mainFrame()->view();
+ IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
+ boundingBox.move(mainView->scrollOffset());
+ IntRect titleAnchorBox = boundingBox;
+
+ // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
+#if ENABLE(SVG)
+ bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();
+#else
+ bool isSVGRenderer = false;
+#endif
+
+ if (isSVGRenderer) {
+ highlight->type = HighlightTypeRects;
+ renderer->absoluteQuads(highlight->quads);
+ for (size_t i = 0; i < highlight->quads.size(); ++i)
+ contentsQuadToPage(mainView, containingView, highlight->quads[i]);
+ } else if (renderer->isBox() || renderer->isRenderInline()) {
+ LayoutRect contentBox;
+ LayoutRect paddingBox;
+ LayoutRect borderBox;
+ LayoutRect marginBox;
+
+ if (renderer->isBox()) {
+ RenderBox* renderBox = toRenderBox(renderer);
+
+ // RenderBox returns the "pure" content area box, exclusive of the scrollbars (if present), which also count towards the content area in CSS.
+ contentBox = renderBox->contentBoxRect();
+ contentBox.setWidth(contentBox.width() + renderBox->verticalScrollbarWidth());
+ contentBox.setHeight(contentBox.height() + renderBox->horizontalScrollbarHeight());
+
+ paddingBox = LayoutRect(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
+ contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
+ borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
+ paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
+ marginBox = LayoutRect(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
+ borderBox.width() + renderBox->marginWidth(), borderBox.height() + renderBox->marginHeight());
+ } else {
+ RenderInline* renderInline = toRenderInline(renderer);
+
+ // RenderInline's bounding box includes paddings and borders, excludes margins.
+ borderBox = renderInline->linesBoundingBox();
+ paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(),
+ borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom());
+ contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(),
+ paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom());
+ // Ignore marginTop and marginBottom for inlines.
+ marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(),
+ borderBox.width() + renderInline->marginWidth(), borderBox.height());
+ }
+
+ FloatQuad absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
+ FloatQuad absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
+ FloatQuad absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
+ FloatQuad absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
+
+ contentsQuadToPage(mainView, containingView, absContentQuad);
+ contentsQuadToPage(mainView, containingView, absPaddingQuad);
+ contentsQuadToPage(mainView, containingView, absBorderQuad);
+ contentsQuadToPage(mainView, containingView, absMarginQuad);
+
+ titleAnchorBox = absMarginQuad.enclosingBoundingBox();
+
+ highlight->type = HighlightTypeNode;
+ highlight->quads.append(absMarginQuad);
+ highlight->quads.append(absBorderQuad);
+ highlight->quads.append(absPaddingQuad);
+ highlight->quads.append(absContentQuad);
+ }
+}
+
+static void buildQuadHighlight(Page* page, const FloatQuad& quad, const HighlightConfig& highlightConfig, Highlight *highlight)
+{
+ if (!page)
+ return;
+ highlight->setDataFromConfig(highlightConfig);
+ highlight->type = HighlightTypeRects;
+ highlight->quads.append(quad);
+}
+
+} // anonymous namespace
+
+InspectorOverlay::InspectorOverlay(Page* page, InspectorClient* client)
+ : m_page(page)
+ , m_client(client)
+ , m_drawViewSize(false)
+ , m_timer(this, &InspectorOverlay::onTimer)
+{
+}
+
+InspectorOverlay::~InspectorOverlay()
+{
+}
+
+void InspectorOverlay::paint(GraphicsContext& context)
+{
+ if (m_pausedInDebuggerMessage.isNull() && !m_highlightNode && !m_highlightQuad && m_size.isEmpty() && !m_drawViewSize)
+ return;
+ GraphicsContextStateSaver stateSaver(context);
+ FrameView* view = overlayPage()->mainFrame()->view();
+ ASSERT(!view->needsLayout());
+ view->paint(&context, IntRect(0, 0, view->width(), view->height()));
+}
+
+void InspectorOverlay::drawOutline(GraphicsContext* context, const LayoutRect& rect, const Color& color)
+{
+ FloatRect outlineRect = rect;
+ drawOutlinedQuad(context, outlineRect, Color(), color);
+}
+
+void InspectorOverlay::getHighlight(Highlight* highlight) const
+{
+ if (!m_highlightNode && !m_highlightQuad)
+ return;
+
+ highlight->type = HighlightTypeRects;
+ if (m_highlightNode)
+ buildNodeHighlight(m_highlightNode.get(), m_nodeHighlightConfig, highlight);
+ else
+ buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, highlight);
+}
+
+void InspectorOverlay::resize(const IntSize& size)
+{
+ m_size = size;
+ update();
+}
+
+void InspectorOverlay::setPausedInDebuggerMessage(const String* message)
+{
+ m_pausedInDebuggerMessage = message ? *message : String();
+ update();
+}
+
+void InspectorOverlay::hideHighlight()
+{
+ m_highlightNode.clear();
+ m_eventTargetNode.clear();
+ m_highlightQuad.clear();
+ update();
+}
+
+void InspectorOverlay::highlightNode(Node* node, Node* eventTarget, const HighlightConfig& highlightConfig)
+{
+ m_nodeHighlightConfig = highlightConfig;
+ m_highlightNode = node;
+ m_eventTargetNode = eventTarget;
+ update();
+}
+
+void InspectorOverlay::highlightQuad(PassOwnPtr<FloatQuad> quad, const HighlightConfig& highlightConfig)
+{
+ m_quadHighlightConfig = highlightConfig;
+ m_highlightQuad = quad;
+ update();
+}
+
+void InspectorOverlay::showAndHideViewSize()
+{
+ m_drawViewSize = true;
+ update();
+ m_timer.startOneShot(1);
+}
+
+Node* InspectorOverlay::highlightedNode() const
+{
+ return m_highlightNode.get();
+}
+
+void InspectorOverlay::update()
+{
+ if (!m_highlightNode && !m_eventTargetNode && !m_highlightQuad && m_pausedInDebuggerMessage.isNull() && m_size.isEmpty() && !m_drawViewSize) {
+ m_client->hideHighlight();
+ return;
+ }
+
+ FrameView* view = m_page->mainFrame()->view();
+ if (!view)
+ return;
+ FloatRect viewRect = view->visibleContentRect();
+ FrameView* overlayView = overlayPage()->mainFrame()->view();
+ IntSize viewportSize = enclosingIntRect(viewRect).size();
+ IntSize frameViewFullSize = enclosingIntRect(view->visibleContentRect(ScrollableArea::IncludeScrollbars)).size();
+ IntSize size = m_size.isEmpty() ? frameViewFullSize : m_size;
+ size.scale(m_page->pageScaleFactor());
+ overlayView->resize(size);
+
+ // Clear canvas and paint things.
+ reset(size, m_size.isEmpty() ? IntSize() : frameViewFullSize, viewRect.x(), viewRect.y());
+
+ // Include scrollbars to avoid masking them by the gutter.
+ drawGutter();
+ drawNodeHighlight();
+ drawQuadHighlight();
+ drawPausedInDebuggerMessage();
+ drawViewSize();
+
+ // Position DOM elements.
+ overlayPage()->mainFrame()->document()->recalcStyle(Node::Force);
+ if (overlayView->needsLayout())
+ overlayView->layout();
+
+ // Kick paint.
+ m_client->highlight();
+}
+
+void InspectorOverlay::hide()
+{
+ m_timer.stop();
+ m_highlightNode.clear();
+ m_eventTargetNode.clear();
+ m_highlightQuad.clear();
+ m_pausedInDebuggerMessage = String();
+ m_size = IntSize();
+ m_drawViewSize = false;
+ update();
+}
+
+static PassRefPtr<InspectorObject> buildObjectForPoint(const FloatPoint& point)
+{
+ RefPtr<InspectorObject> object = InspectorObject::create();
+ object->setNumber("x", point.x());
+ object->setNumber("y", point.y());
+ return object.release();
+}
+
+static PassRefPtr<InspectorArray> buildArrayForQuad(const FloatQuad& quad)
+{
+ RefPtr<InspectorArray> array = InspectorArray::create();
+ array->pushObject(buildObjectForPoint(quad.p1()));
+ array->pushObject(buildObjectForPoint(quad.p2()));
+ array->pushObject(buildObjectForPoint(quad.p3()));
+ array->pushObject(buildObjectForPoint(quad.p4()));
+ return array.release();
+}
+
+static PassRefPtr<InspectorObject> buildObjectForHighlight(const Highlight& highlight)
+{
+ RefPtr<InspectorObject> object = InspectorObject::create();
+ RefPtr<InspectorArray> array = InspectorArray::create();
+ for (size_t i = 0; i < highlight.quads.size(); ++i)
+ array->pushArray(buildArrayForQuad(highlight.quads[i]));
+ object->setArray("quads", array.release());
+ object->setBoolean("showRulers", highlight.showRulers);
+ object->setString("contentColor", highlight.contentColor.serialized());
+ object->setString("contentOutlineColor", highlight.contentOutlineColor.serialized());
+ object->setString("paddingColor", highlight.paddingColor.serialized());
+ object->setString("borderColor", highlight.borderColor.serialized());
+ object->setString("marginColor", highlight.marginColor.serialized());
+ object->setString("eventTargetColor", highlight.eventTargetColor.serialized());
+ return object.release();
+}
+
+static PassRefPtr<InspectorObject> buildObjectForSize(const IntSize& size)
+{
+ RefPtr<InspectorObject> result = InspectorObject::create();
+ result->setNumber("width", size.width());
+ result->setNumber("height", size.height());
+ return result.release();
+}
+
+void InspectorOverlay::drawGutter()
+{
+ evaluateInOverlay("drawGutter", "");
+}
+
+void InspectorOverlay::drawNodeHighlight()
+{
+ if (!m_highlightNode)
+ return;
+
+ Highlight highlight;
+ buildNodeHighlight(m_highlightNode.get(), m_nodeHighlightConfig, &highlight);
+ if (m_eventTargetNode) {
+ Highlight eventTargetHighlight;
+ buildNodeHighlight(m_eventTargetNode.get(), m_nodeHighlightConfig, &eventTargetHighlight);
+ highlight.quads.append(eventTargetHighlight.quads[1]); // Add border from eventTargetNode to highlight.
+ }
+ RefPtr<InspectorObject> highlightObject = buildObjectForHighlight(highlight);
+
+ Node* node = m_highlightNode.get();
+ if (node->isElementNode() && m_nodeHighlightConfig.showInfo && node->renderer() && node->document()->frame()) {
+ RefPtr<InspectorObject> elementInfo = InspectorObject::create();
+ Element* element = toElement(node);
+ bool isXHTML = element->document()->isXHTMLDocument();
+ elementInfo->setString("tagName", isXHTML ? element->nodeName() : element->nodeName().lower());
+ elementInfo->setString("idValue", element->getIdAttribute());
+ HashSet<AtomicString> usedClassNames;
+ if (element->hasClass() && element->isStyledElement()) {
+ StringBuilder classNames;
+ const SpaceSplitString& classNamesString = static_cast<StyledElement*>(element)->classNames();
+ size_t classNameCount = classNamesString.size();
+ for (size_t i = 0; i < classNameCount; ++i) {
+ const AtomicString& className = classNamesString[i];
+ if (usedClassNames.contains(className))
+ continue;
+ usedClassNames.add(className);
+ classNames.append('.');
+ classNames.append(className);
+ }
+ elementInfo->setString("className", classNames.toString());
+ }
+
+ RenderObject* renderer = node->renderer();
+ Frame* containingFrame = node->document()->frame();
+ FrameView* containingView = containingFrame->view();
+ IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
+ RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
+ elementInfo->setString("nodeWidth", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), modelObject) : boundingBox.width()));
+ elementInfo->setString("nodeHeight", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), modelObject) : boundingBox.height()));
+ highlightObject->setObject("elementInfo", elementInfo.release());
+ }
+ evaluateInOverlay("drawNodeHighlight", highlightObject);
+}
+
+void InspectorOverlay::drawQuadHighlight()
+{
+ if (!m_highlightQuad)
+ return;
+
+ Highlight highlight;
+ buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, &highlight);
+ evaluateInOverlay("drawQuadHighlight", buildObjectForHighlight(highlight));
+}
+
+void InspectorOverlay::drawPausedInDebuggerMessage()
+{
+ if (!m_pausedInDebuggerMessage.isNull())
+ evaluateInOverlay("drawPausedInDebuggerMessage", m_pausedInDebuggerMessage);
+}
+
+void InspectorOverlay::drawViewSize()
+{
+ if (m_drawViewSize)
+ evaluateInOverlay("drawViewSize", m_pausedInDebuggerMessage);
+}
+
+Page* InspectorOverlay::overlayPage()
+{
+ if (m_overlayPage)
+ return m_overlayPage.get();
+
+ static FrameLoaderClient* dummyFrameLoaderClient = new EmptyFrameLoaderClient;
+ Page::PageClients pageClients;
+ fillWithEmptyClients(pageClients);
+ m_overlayPage = adoptPtr(new Page(pageClients));
+
+ Settings* settings = m_page->settings();
+ Settings* overlaySettings = m_overlayPage->settings();
+
+ overlaySettings->setStandardFontFamily(settings->standardFontFamily());
+ overlaySettings->setSerifFontFamily(settings->serifFontFamily());
+ overlaySettings->setSansSerifFontFamily(settings->sansSerifFontFamily());
+ overlaySettings->setCursiveFontFamily(settings->cursiveFontFamily());
+ overlaySettings->setFantasyFontFamily(settings->fantasyFontFamily());
+ overlaySettings->setPictographFontFamily(settings->pictographFontFamily());
+ overlaySettings->setMinimumFontSize(settings->minimumFontSize());
+ overlaySettings->setMinimumLogicalFontSize(settings->minimumLogicalFontSize());
+ overlaySettings->setMediaEnabled(false);
+ overlaySettings->setScriptEnabled(true);
+ overlaySettings->setPluginsEnabled(false);
+
+ RefPtr<Frame> frame = Frame::create(m_overlayPage.get(), 0, dummyFrameLoaderClient);
+ frame->setView(FrameView::create(frame.get()));
+ frame->init();
+ FrameLoader* loader = frame->loader();
+ frame->view()->setCanHaveScrollbars(false);
+ frame->view()->setTransparent(true);
+ ASSERT(loader->activeDocumentLoader());
+ loader->activeDocumentLoader()->writer()->setMIMEType("text/html");
+ loader->activeDocumentLoader()->writer()->begin();
+ loader->activeDocumentLoader()->writer()->addData(reinterpret_cast<const char*>(InspectorOverlayPage_html), sizeof(InspectorOverlayPage_html));
+ loader->activeDocumentLoader()->writer()->end();
+
+#if OS(WINDOWS)
+ evaluateInOverlay("setPlatform", "windows");
+#elif OS(DARWIN)
+ evaluateInOverlay("setPlatform", "mac");
+#elif OS(UNIX)
+ evaluateInOverlay("setPlatform", "linux");
+#endif
+
+ return m_overlayPage.get();
+}
+
+void InspectorOverlay::reset(const IntSize& viewportSize, const IntSize& frameViewFullSize, int scrollX, int scrollY)
+{
+ RefPtr<InspectorObject> resetData = InspectorObject::create();
+ resetData->setNumber("pageScaleFactor", m_page->pageScaleFactor());
+ resetData->setNumber("deviceScaleFactor", m_page->deviceScaleFactor());
+ resetData->setObject("viewportSize", buildObjectForSize(viewportSize));
+ resetData->setObject("frameViewFullSize", buildObjectForSize(frameViewFullSize));
+ resetData->setNumber("pageZoomFactor", m_page->mainFrame()->pageZoomFactor());
+ resetData->setNumber("scrollX", scrollX);
+ resetData->setNumber("scrollY", scrollY);
+ evaluateInOverlay("reset", resetData.release());
+}
+
+void InspectorOverlay::evaluateInOverlay(const String& method, const String& argument)
+{
+ RefPtr<InspectorArray> command = InspectorArray::create();
+ command->pushString(method);
+ command->pushString(argument);
+ overlayPage()->mainFrame()->script()->evaluate(ScriptSourceCode(makeString("dispatch(", command->toJSONString(), ")")));
+}
+
+void InspectorOverlay::evaluateInOverlay(const String& method, PassRefPtr<InspectorValue> argument)
+{
+ RefPtr<InspectorArray> command = InspectorArray::create();
+ command->pushString(method);
+ command->pushValue(argument);
+ overlayPage()->mainFrame()->script()->evaluate(ScriptSourceCode(makeString("dispatch(", command->toJSONString(), ")")));
+}
+
+void InspectorOverlay::onTimer(Timer<InspectorOverlay>*)
+{
+ m_drawViewSize = false;
+ update();
+}
+
+void InspectorOverlay::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorOverlay);
+ info.addMember(m_page, "page");
+ info.addWeakPointer(m_client);
+ info.addMember(m_pausedInDebuggerMessage, "pausedInDebuggerMessage");
+ info.addMember(m_highlightNode, "highlightNode");
+ info.addMember(m_nodeHighlightConfig, "nodeHighlightConfig");
+ info.addMember(m_highlightQuad, "highlightQuad");
+ info.addMember(m_overlayPage, "overlayPage");
+ info.addMember(m_quadHighlightConfig, "quadHighlightConfig");
+ info.addMember(m_size, "size");
+}
+
+void InspectorOverlay::freePage()
+{
+ m_overlayPage.clear();
+ m_timer.stop();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorOverlay.h b/Source/core/inspector/InspectorOverlay.h
new file mode 100644
index 0000000..25165f9
--- /dev/null
+++ b/Source/core/inspector/InspectorOverlay.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorOverlay_h
+#define InspectorOverlay_h
+
+#include "core/platform/graphics/Color.h"
+#include "core/platform/graphics/FloatQuad.h"
+#include "core/platform/graphics/LayoutRect.h"
+#include "core/platform/Timer.h"
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Color;
+class GraphicsContext;
+class InspectorClient;
+class InspectorValue;
+class IntRect;
+class Node;
+class Page;
+
+struct HighlightConfig {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ Color content;
+ Color contentOutline;
+ Color padding;
+ Color border;
+ Color margin;
+ Color eventTarget;
+ bool showInfo;
+ bool showRulers;
+};
+
+enum HighlightType {
+ HighlightTypeNode,
+ HighlightTypeRects,
+};
+
+struct Highlight {
+ Highlight()
+ : type(HighlightTypeNode)
+ , showRulers(false)
+ {
+ }
+
+ void setDataFromConfig(const HighlightConfig& highlightConfig)
+ {
+ contentColor = highlightConfig.content;
+ contentOutlineColor = highlightConfig.contentOutline;
+ paddingColor = highlightConfig.padding;
+ borderColor = highlightConfig.border;
+ marginColor = highlightConfig.margin;
+ eventTargetColor = highlightConfig.eventTarget;
+ showRulers = highlightConfig.showRulers;
+ }
+
+ Color contentColor;
+ Color contentOutlineColor;
+ Color paddingColor;
+ Color borderColor;
+ Color marginColor;
+ Color eventTargetColor;
+
+ // When the type is Node, there are 4 or 5 quads (margin, border, padding, content, optional eventTarget).
+ // When the type is Rects, this is just a list of quads.
+ HighlightType type;
+ Vector<FloatQuad> quads;
+ bool showRulers;
+};
+
+class InspectorOverlay {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ static PassOwnPtr<InspectorOverlay> create(Page* page, InspectorClient* client)
+ {
+ return adoptPtr(new InspectorOverlay(page, client));
+ }
+ ~InspectorOverlay();
+
+ void update();
+ void hide();
+ void paint(GraphicsContext&);
+ void drawOutline(GraphicsContext*, const LayoutRect&, const Color&);
+ void getHighlight(Highlight*) const;
+ void resize(const IntSize&);
+
+ void setPausedInDebuggerMessage(const String*);
+
+ void hideHighlight();
+ void highlightNode(Node*, Node* eventTarget, const HighlightConfig&);
+ void highlightQuad(PassOwnPtr<FloatQuad>, const HighlightConfig&);
+ void showAndHideViewSize();
+
+ Node* highlightedNode() const;
+
+ void reportMemoryUsage(MemoryObjectInfo*) const;
+
+ void freePage();
+private:
+ InspectorOverlay(Page*, InspectorClient*);
+
+ void drawGutter();
+ void drawNodeHighlight();
+ void drawQuadHighlight();
+ void drawPausedInDebuggerMessage();
+ void drawViewSize();
+
+ Page* overlayPage();
+ void reset(const IntSize& viewportSize, const IntSize& frameViewFullSize, int scrollX, int scrollY);
+ void evaluateInOverlay(const String& method, const String& argument);
+ void evaluateInOverlay(const String& method, PassRefPtr<InspectorValue> argument);
+ void onTimer(Timer<InspectorOverlay>*);
+
+ Page* m_page;
+ InspectorClient* m_client;
+ String m_pausedInDebuggerMessage;
+ RefPtr<Node> m_highlightNode;
+ RefPtr<Node> m_eventTargetNode;
+ HighlightConfig m_nodeHighlightConfig;
+ OwnPtr<FloatQuad> m_highlightQuad;
+ OwnPtr<Page> m_overlayPage;
+ HighlightConfig m_quadHighlightConfig;
+ IntSize m_size;
+ bool m_drawViewSize;
+ Timer<InspectorOverlay> m_timer;
+};
+
+} // namespace WebCore
+
+
+#endif // InspectorOverlay_h
diff --git a/Source/core/inspector/InspectorOverlayPage.html b/Source/core/inspector/InspectorOverlayPage.html
new file mode 100644
index 0000000..503aeb4
--- /dev/null
+++ b/Source/core/inspector/InspectorOverlayPage.html
@@ -0,0 +1,647 @@
+<!--
+ Copyright (C) 2012 Google 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.
+ 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+body {
+ margin: 0;
+ padding: 0;
+}
+
+body.platform-mac {
+ font-size: 11px;
+ font-family: Menlo, Monaco;
+}
+
+body.platform-windows {
+ font-size: 12px;
+ font-family: Consolas, Lucida Console;
+}
+
+body.platform-linux {
+ font-size: 11px;
+ font-family: dejavu sans mono;
+}
+
+.fill {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+}
+
+.dimmed {
+ background-color: rgba(0, 0, 0, 0.31);
+}
+
+.message-line {
+ margin: 10px 0;
+ text-align: center;
+}
+
+.message-box {
+ background-color: rgb(255, 255, 194);
+ border: 1px solid rgb(128, 128, 128);
+ display: inline-block;
+ padding: 2px 4px;
+}
+
+.px {
+ color: rgb(128, 128, 128);
+}
+
+#element-title {
+ position: absolute;
+ z-index: 10;
+}
+
+#tag-name {
+ /* Keep this in sync with view-source.css (.webkit-html-tag-name) */
+ color: rgb(136, 18, 128);
+}
+
+#node-id {
+ /* Keep this in sync with view-source.css (.webkit-html-attribute-value) */
+ color: rgb(26, 26, 166);
+}
+
+#class-name {
+ /* Keep this in sync with view-source.css (.webkit-html-attribute-name) */
+ color: rgb(153, 69, 0);
+}
+
+#right-gutter {
+ display: none;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ position: absolute;
+ background-color: darkgray;
+}
+
+#bottom-gutter {
+ display: none;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ position: absolute;
+ background-color: darkgray;
+}
+
+</style>
+<script>
+const lightGridColor = "rgba(0,0,0,0.2)";
+const darkGridColor = "rgba(0,0,0,0.7)";
+const transparentColor = "rgba(0, 0, 0, 0)";
+const gridBackgroundColor = "rgba(255, 255, 255, 0.8)";
+
+function drawPausedInDebuggerMessage(message)
+{
+ var pausedInDebugger = document.getElementById("paused-in-debugger");
+ pausedInDebugger.textContent = message;
+ pausedInDebugger.style.visibility = "visible";
+ document.body.classList.add("dimmed");
+}
+
+function _drawGrid(rulerAtRight, rulerAtBottom)
+{
+ if (window._gridPainted)
+ return;
+ window._gridPainted = true;
+
+ context.save();
+
+ var pageFactor = pageZoomFactor * pageScaleFactor;
+ function zoom(x)
+ {
+ return Math.round(x * pageFactor);
+ }
+ function unzoom(x)
+ {
+ return Math.round(x / pageFactor);
+ }
+
+ var width = canvasWidth / pageFactor;
+ var height = canvasHeight / pageFactor;
+
+ const gridSubStep = 5;
+ const gridStep = 50;
+
+ {
+ // Draw X grid background
+ context.save();
+ context.fillStyle = gridBackgroundColor;
+ if (rulerAtBottom)
+ context.fillRect(0, zoom(height) - 15, zoom(width), zoom(height));
+ else
+ context.fillRect(0, 0, zoom(width), 15);
+
+ // Clip out backgrounds intersection
+ context.globalCompositeOperation = "destination-out";
+ context.fillStyle = "red";
+ if (rulerAtRight)
+ context.fillRect(zoom(width) - 15, 0, zoom(width), zoom(height));
+ else
+ context.fillRect(0, 0, 15, zoom(height));
+ context.restore();
+
+ // Draw Y grid background
+ context.fillStyle = gridBackgroundColor;
+ if (rulerAtRight)
+ context.fillRect(zoom(width) - 15, 0, zoom(width), zoom(height));
+ else
+ context.fillRect(0, 0, 15, zoom(height));
+ }
+
+ context.lineWidth = 1;
+ context.strokeStyle = darkGridColor;
+ context.fillStyle = darkGridColor;
+ {
+ // Draw labels.
+ context.save();
+ context.translate(-scrollX, 0.5 - scrollY);
+ var maxY = height + unzoom(scrollY);
+ for (var y = 2 * gridStep; y < maxY; y += 2 * gridStep) {
+ context.save();
+ context.translate(scrollX, zoom(y));
+ context.rotate(-Math.PI / 2);
+ context.fillText(y, 2, rulerAtRight ? zoom(width) - 7 : 13);
+ context.restore();
+ }
+ context.translate(0.5, -0.5);
+ var maxX = width + unzoom(scrollX);
+ for (var x = 2 * gridStep; x < maxX; x += 2 * gridStep) {
+ context.save();
+ context.fillText(x, zoom(x) + 2, rulerAtBottom ? scrollY + zoom(height) - 7 : scrollY + 13);
+ context.restore();
+ }
+ context.restore();
+ }
+
+ {
+ // Draw vertical grid
+ context.save();
+ if (rulerAtRight) {
+ context.translate(zoom(width), 0);
+ context.scale(-1, 1);
+ }
+ context.translate(-scrollX, 0.5 - scrollY);
+ var maxY = height + unzoom(scrollY);
+ for (var y = gridStep; y < maxY; y += gridStep) {
+ context.beginPath();
+ context.moveTo(scrollX, zoom(y));
+ var markLength = (y % (gridStep * 2)) ? 5 : 8;
+ context.lineTo(scrollX + markLength, zoom(y));
+ context.stroke();
+ }
+ context.strokeStyle = lightGridColor;
+ for (var y = gridSubStep; y < maxY; y += gridSubStep) {
+ if (!(y % gridStep))
+ continue;
+ context.beginPath();
+ context.moveTo(scrollX, zoom(y));
+ context.lineTo(scrollX + gridSubStep, zoom(y));
+ context.stroke();
+ }
+ context.restore();
+ }
+
+ {
+ // Draw horizontal grid
+ context.save();
+ if (rulerAtBottom) {
+ context.translate(0, zoom(height));
+ context.scale(1, -1);
+ }
+ context.translate(0.5 - scrollX, -scrollY);
+ var maxX = width + unzoom(scrollX);
+ for (var x = gridStep; x < maxX; x += gridStep) {
+ context.beginPath();
+ context.moveTo(zoom(x), scrollY);
+ var markLength = (x % (gridStep * 2)) ? 5 : 8;
+ context.lineTo(zoom(x), scrollY + markLength);
+ context.stroke();
+ }
+ context.strokeStyle = lightGridColor;
+ for (var x = gridSubStep; x < maxX; x += gridSubStep) {
+ if (!(x % gridStep))
+ continue;
+ context.beginPath();
+ context.moveTo(zoom(x), scrollY);
+ context.lineTo(zoom(x), scrollY + gridSubStep);
+ context.stroke();
+ }
+ context.restore();
+ }
+
+ context.restore();
+}
+
+function quadToPath(quad)
+{
+ context.beginPath();
+ context.moveTo(quad[0].x, quad[0].y);
+ context.lineTo(quad[1].x, quad[1].y);
+ context.lineTo(quad[2].x, quad[2].y);
+ context.lineTo(quad[3].x, quad[3].y);
+ context.closePath();
+ return context;
+}
+
+function drawOutlinedQuad(quad, fillColor, outlineColor)
+{
+ context.save();
+ context.lineWidth = 2;
+ quadToPath(quad).clip();
+ context.fillStyle = fillColor;
+ context.fill();
+ if (outlineColor) {
+ context.strokeStyle = outlineColor;
+ context.stroke();
+ }
+ context.restore();
+}
+
+function drawOutlinedQuadWithClip(quad, clipQuad, fillColor)
+{
+ var canvas = document.getElementById("canvas");
+ context.fillStyle = fillColor;
+ context.save();
+ context.lineWidth = 0;
+ quadToPath(quad).fill();
+ context.globalCompositeOperation = "destination-out";
+ context.fillStyle = "red";
+ quadToPath(clipQuad).fill();
+ context.restore();
+}
+
+function drawUnderlyingQuad(quad, fillColor)
+{
+ context.save();
+ context.lineWidth = 2;
+ context.globalCompositeOperation = "destination-over";
+ context.fillStyle = fillColor;
+ quadToPath(quad).fill();
+ context.restore();
+}
+
+function quadEquals(quad1, quad2)
+{
+ return quad1[0].x === quad2[0].x && quad1[0].y === quad2[0].y &&
+ quad1[1].x === quad2[1].x && quad1[1].y === quad2[1].y &&
+ quad1[2].x === quad2[2].x && quad1[2].y === quad2[2].y &&
+ quad1[3].x === quad2[3].x && quad1[3].y === quad2[3].y;
+}
+
+function drawGutter()
+{
+ var frameWidth = frameViewFullSize.width;
+ var frameHeight = frameViewFullSize.height;
+
+ if (!frameWidth || document.body.offsetWidth <= frameWidth)
+ rightGutter.style.removeProperty("display");
+ else {
+ rightGutter.style.display = "block";
+ rightGutter.style.left = frameWidth + "px";
+ }
+
+ if (!frameHeight || document.body.offsetHeight <= frameHeight)
+ bottomGutter.style.removeProperty("display");
+ else {
+ bottomGutter.style.display = "block";
+ bottomGutter.style.top = frameHeight + "px";
+ }
+}
+
+function drawViewSize()
+{
+ var text = viewportSize.width + "px \u00D7 " + viewportSize.height + "px";
+ context.save();
+ context.font = "20px ";
+ switch (platform) {
+ case "windows": context.font = "14px Consolas"; break;
+ case "mac": context.font = "14px Menlo"; break;
+ case "linux": context.font = "14px dejavu sans mono"; break;
+ }
+
+ var frameWidth = frameViewFullSize.width || canvasWidth;
+ var textWidth = context.measureText(text).width;
+ context.fillStyle = gridBackgroundColor;
+ context.fillRect(frameWidth - textWidth - 12, 15, frameWidth, 25);
+ context.fillStyle = darkGridColor;
+ context.fillText(text, frameWidth - textWidth - 6, 33);
+ context.restore();
+
+ _drawGrid(false, false);
+}
+
+function reset(resetData)
+{
+ window.viewportSize = resetData.viewportSize;
+ window.frameViewFullSize = resetData.frameViewFullSize;
+ window.deviceScaleFactor = resetData.deviceScaleFactor;
+ window.pageZoomFactor = resetData.pageZoomFactor;
+ window.pageScaleFactor = resetData.pageScaleFactor;
+ window.scrollX = Math.round(resetData.scrollX * pageScaleFactor);
+ window.scrollY = Math.round(resetData.scrollY * pageScaleFactor);
+
+ window.canvas = document.getElementById("canvas");
+ window.context = canvas.getContext("2d");
+ window.rightGutter = document.getElementById("right-gutter");
+ window.bottomGutter = document.getElementById("bottom-gutter");
+
+ canvas.width = deviceScaleFactor * viewportSize.width;
+ canvas.height = deviceScaleFactor * viewportSize.height;
+ canvas.style.width = viewportSize.width + "px";
+ canvas.style.height = viewportSize.height + "px";
+ context.scale(deviceScaleFactor, deviceScaleFactor);
+ window.canvasWidth = viewportSize.width;
+ window.canvasHeight = viewportSize.height;
+
+ document.getElementById("paused-in-debugger").style.visibility = "hidden";
+ document.getElementById("element-title").style.visibility = "hidden";
+ document.body.classList.remove("dimmed");
+ window._gridPainted = false;
+}
+
+function _drawElementTitle(highlight)
+{
+ var elementInfo = highlight.elementInfo;
+ if (!highlight.elementInfo)
+ return;
+
+ document.getElementById("tag-name").textContent = elementInfo.tagName;
+ document.getElementById("node-id").textContent = elementInfo.idValue ? "#" + elementInfo.idValue : "";
+ var className = elementInfo.className;
+ if (className && className.length > 50)
+ className = className.substring(0, 50) + "\u2026";
+ document.getElementById("class-name").textContent = className || "";
+ document.getElementById("node-width").textContent = elementInfo.nodeWidth;
+ document.getElementById("node-height").textContent = elementInfo.nodeHeight;
+ var elementTitle = document.getElementById("element-title");
+
+ var marginQuad = highlight.quads[0];
+
+ var titleWidth = elementTitle.offsetWidth + 6;
+ var titleHeight = elementTitle.offsetHeight + 4;
+
+ var anchorTop = marginQuad[0].y;
+ var anchorBottom = marginQuad[3].y
+
+ const arrowHeight = 7;
+ var renderArrowUp = false;
+ var renderArrowDown = false;
+
+ var boxX = Math.max(2, marginQuad[0].x);
+ if (boxX + titleWidth > canvasWidth)
+ boxX = canvasWidth - titleWidth - 2;
+
+ var boxY;
+ if (anchorTop > canvasHeight) {
+ boxY = canvasHeight - titleHeight - arrowHeight;
+ renderArrowDown = true;
+ } else if (anchorBottom < 0) {
+ boxY = arrowHeight;
+ renderArrowUp = true;
+ } else if (anchorBottom + titleHeight + arrowHeight < canvasHeight) {
+ boxY = anchorBottom + arrowHeight - 4;
+ renderArrowUp = true;
+ } else if (anchorTop - titleHeight - arrowHeight > 0) {
+ boxY = anchorTop - titleHeight - arrowHeight + 3;
+ renderArrowDown = true;
+ } else
+ boxY = arrowHeight;
+
+ context.save();
+ context.translate(0.5, 0.5);
+ context.beginPath();
+ context.moveTo(boxX, boxY);
+ if (renderArrowUp) {
+ context.lineTo(boxX + 2 * arrowHeight, boxY);
+ context.lineTo(boxX + 3 * arrowHeight, boxY - arrowHeight);
+ context.lineTo(boxX + 4 * arrowHeight, boxY);
+ }
+ context.lineTo(boxX + titleWidth, boxY);
+ context.lineTo(boxX + titleWidth, boxY + titleHeight);
+ if (renderArrowDown) {
+ context.lineTo(boxX + 4 * arrowHeight, boxY + titleHeight);
+ context.lineTo(boxX + 3 * arrowHeight, boxY + titleHeight + arrowHeight);
+ context.lineTo(boxX + 2 * arrowHeight, boxY + titleHeight);
+ }
+ context.lineTo(boxX, boxY + titleHeight);
+ context.closePath();
+ context.fillStyle = "rgb(255, 255, 194)";
+ context.fill();
+ context.strokeStyle = "rgb(128, 128, 128)";
+ context.stroke();
+
+ context.restore();
+
+ elementTitle.style.visibility = "visible";
+ elementTitle.style.top = (boxY + 3) + "px";
+ elementTitle.style.left = (boxX + 3) + "px";
+}
+
+function _drawRulers(highlight, rulerAtRight, rulerAtBottom)
+{
+ context.save();
+ var width = canvasWidth;
+ var height = canvasHeight;
+ context.strokeStyle = "rgba(128, 128, 128, 0.3)";
+ context.lineWidth = 1;
+ context.translate(0.5, 0.5);
+ var leftmostXForY = {};
+ var rightmostXForY = {};
+ var topmostYForX = {};
+ var bottommostYForX = {};
+
+ for (var i = 0; i < highlight.quads.length; ++i) {
+ var quad = highlight.quads[i];
+ for (var j = 0; j < quad.length; ++j) {
+ var x = quad[j].x;
+ var y = quad[j].y;
+ leftmostXForY[Math.round(y)] = Math.min(leftmostXForY[y] || Number.MAX_VALUE, Math.round(quad[j].x));
+ rightmostXForY[Math.round(y)] = Math.max(rightmostXForY[y] || Number.MIN_VALUE, Math.round(quad[j].x));
+ topmostYForX[Math.round(x)] = Math.min(topmostYForX[x] || Number.MAX_VALUE, Math.round(quad[j].y));
+ bottommostYForX[Math.round(x)] = Math.max(bottommostYForX[x] || Number.MIN_VALUE, Math.round(quad[j].y));
+ }
+ }
+
+ if (rulerAtRight) {
+ for (var y in rightmostXForY) {
+ context.beginPath();
+ context.moveTo(width, y);
+ context.lineTo(rightmostXForY[y], y);
+ context.stroke();
+ }
+ } else {
+ for (var y in leftmostXForY) {
+ context.beginPath();
+ context.moveTo(0, y);
+ context.lineTo(leftmostXForY[y], y);
+ context.stroke();
+ }
+ }
+
+ if (rulerAtBottom) {
+ for (var x in bottommostYForX) {
+ context.beginPath();
+ context.moveTo(x, height);
+ context.lineTo(x, topmostYForX[x]);
+ context.stroke();
+ }
+ } else {
+ for (var x in topmostYForX) {
+ context.beginPath();
+ context.moveTo(x, 0);
+ context.lineTo(x, topmostYForX[x]);
+ context.stroke();
+ }
+ }
+
+ context.restore();
+}
+
+function drawNodeHighlight(highlight)
+{
+ {
+ for (var i = 0; i < highlight.quads.length; ++i) {
+ var quad = highlight.quads[i];
+ for (var j = 0; j < quad.length; ++j) {
+ quad[j].x = Math.round(quad[j].x * pageScaleFactor - scrollX);
+ quad[j].y = Math.round(quad[j].y * pageScaleFactor - scrollY);
+ }
+ }
+ }
+
+ if (!highlight.quads.length) {
+ if (highlight.showRulers)
+ _drawGrid(false, false);
+ return;
+ }
+
+ context.save();
+
+ var quads = highlight.quads.slice();
+ var eventTargetQuad = quads.length >= 5 ? quads.pop() : null;
+ var contentQuad = quads.pop();
+ var paddingQuad = quads.pop();
+ var borderQuad = quads.pop();
+ var marginQuad = quads.pop();
+
+ var hasContent = contentQuad && highlight.contentColor !== transparentColor || highlight.contentOutlineColor !== transparentColor;
+ var hasPadding = paddingQuad && highlight.paddingColor !== transparentColor;
+ var hasBorder = borderQuad && highlight.borderColor !== transparentColor;
+ var hasMargin = marginQuad && highlight.marginColor !== transparentColor;
+ var hasEventTarget = eventTargetQuad && highlight.eventTargetColor !== transparentColor;
+
+ var clipQuad;
+ if (hasMargin && (!hasBorder || !quadEquals(marginQuad, borderQuad))) {
+ drawOutlinedQuadWithClip(marginQuad, borderQuad, highlight.marginColor);
+ clipQuad = borderQuad;
+ }
+ if (hasBorder && (!hasPadding || !quadEquals(borderQuad, paddingQuad))) {
+ drawOutlinedQuadWithClip(borderQuad, paddingQuad, highlight.borderColor);
+ clipQuad = paddingQuad;
+ }
+ if (hasPadding && (!hasContent || !quadEquals(paddingQuad, contentQuad))) {
+ drawOutlinedQuadWithClip(paddingQuad, contentQuad, highlight.paddingColor);
+ clipQuad = contentQuad;
+ }
+ if (hasContent)
+ drawOutlinedQuad(contentQuad, highlight.contentColor, highlight.contentOutlineColor);
+ if (hasEventTarget)
+ drawUnderlyingQuad(eventTargetQuad, highlight.eventTargetColor);
+
+ var width = canvasWidth;
+ var height = canvasHeight;
+ var minX = Number.MAX_VALUE, minY = Number.MAX_VALUE, maxX = Number.MIN_VALUE; maxY = Number.MIN_VALUE;
+ for (var i = 0; i < highlight.quads.length; ++i) {
+ var quad = highlight.quads[i];
+ for (var j = 0; j < quad.length; ++j) {
+ minX = Math.min(minX, quad[j].x);
+ maxX = Math.max(maxX, quad[j].x);
+ minY = Math.min(minY, quad[j].y);
+ maxY = Math.max(maxY, quad[j].y);
+ }
+ }
+
+ var rulerAtRight = minX < 20 && maxX + 20 < width;
+ var rulerAtBottom = minY < 20 && maxY + 20 < height;
+
+ if (highlight.showRulers) {
+ _drawGrid(rulerAtRight, rulerAtBottom);
+ _drawRulers(highlight, rulerAtRight, rulerAtBottom);
+ }
+ _drawElementTitle(highlight);
+
+ context.restore();
+}
+
+function drawQuadHighlight(highlight)
+{
+ context.save();
+ drawOutlinedQuad(highlight.quads[0], highlight.contentColor, highlight.contentOutlineColor);
+ context.restore();
+}
+
+function setPlatform(platform)
+{
+ window.platform = platform;
+ document.body.classList.add("platform-" + platform);
+}
+
+function dispatch(message)
+{
+ var functionName = message.shift();
+ window[functionName].apply(null, message);
+}
+
+function log(text)
+{
+ var logEntry = document.createElement("div");
+ logEntry.textContent = text;
+ document.getElementById("log").appendChild(logEntry);
+}
+
+</script>
+</head>
+<body class="fill">
+<div class="message-line"><span class="message-box" id="paused-in-debugger"></span></div>
+</body>
+<canvas id="canvas" class="fill"></canvas>
+<div id="element-title">
+ <span id="tag-name"></span><span id="node-id"></span><span id="class-name"></span>
+ <span id="node-width"></span><span class="px">px</span><span class="px"> × </span><span id="node-height"></span><span class="px">px</span>
+</div>
+<div id="right-gutter"></div>
+<div id="bottom-gutter"></div>
+<div id="log"></div>
+</html>
diff --git a/Source/core/inspector/InspectorOverridesInl.h b/Source/core/inspector/InspectorOverridesInl.h
new file mode 100644
index 0000000..c97469b
--- /dev/null
+++ b/Source/core/inspector/InspectorOverridesInl.h
@@ -0,0 +1,105 @@
+/*
+* Copyright (C) 2013 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 InspectorOverrides_inl_h
+#define InspectorOverrides_inl_h
+
+namespace WebCore {
+
+namespace InspectorInstrumentation {
+
+bool forcePseudoStateImpl(InstrumentingAgents*, Element*, CSSSelector::PseudoType);
+bool shouldApplyScreenWidthOverrideImpl(InstrumentingAgents*);
+bool shouldApplyScreenHeightOverrideImpl(InstrumentingAgents*);
+bool shouldPauseDedicatedWorkerOnStartImpl(InstrumentingAgents*);
+GeolocationPosition* overrideGeolocationPositionImpl(InstrumentingAgents*, GeolocationPosition*);
+DeviceOrientationData* overrideDeviceOrientationImpl(InstrumentingAgents*, DeviceOrientationData*);
+String getCurrentUserInitiatedProfileNameImpl(InstrumentingAgents*, bool incrementProfileNumber);
+
+inline bool forcePseudoState(Element* element, CSSSelector::PseudoType pseudoState)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(false);
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForElement(element))
+ return forcePseudoStateImpl(instrumentingAgents, element, pseudoState);
+ return false;
+}
+
+inline bool shouldApplyScreenWidthOverride(Frame* frame)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(false);
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ return shouldApplyScreenWidthOverrideImpl(instrumentingAgents);
+ return false;
+}
+
+inline bool shouldApplyScreenHeightOverride(Frame* frame)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(false);
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ return shouldApplyScreenHeightOverrideImpl(instrumentingAgents);
+ return false;
+}
+
+inline bool shouldPauseDedicatedWorkerOnStart(ScriptExecutionContext* context)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(false);
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+ return shouldPauseDedicatedWorkerOnStartImpl(instrumentingAgents);
+ return false;
+}
+
+inline GeolocationPosition* overrideGeolocationPosition(Page* page, GeolocationPosition* position)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(position);
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ return overrideGeolocationPositionImpl(instrumentingAgents, position);
+ return position;
+}
+
+inline DeviceOrientationData* overrideDeviceOrientation(Page* page, DeviceOrientationData* deviceOrientation)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(deviceOrientation);
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ return overrideDeviceOrientationImpl(instrumentingAgents, deviceOrientation);
+ return deviceOrientation;
+}
+
+inline String getCurrentUserInitiatedProfileName(Page* page, bool incrementProfileNumber)
+{
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ return getCurrentUserInitiatedProfileNameImpl(instrumentingAgents, incrementProfileNumber);
+ return "";
+}
+
+} // namespace InspectorInstrumentation
+
+} // namespace WebCore
+
+#endif // !defined(InspectorOverrides_inl_h)
diff --git a/Source/core/inspector/InspectorPageAgent.cpp b/Source/core/inspector/InspectorPageAgent.cpp
new file mode 100644
index 0000000..e1f3066
--- /dev/null
+++ b/Source/core/inspector/InspectorPageAgent.cpp
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorPageAgent.h"
+
+#include "HTMLNames.h"
+#include "InspectorFrontend.h"
+#include "bindings/v8/DOMWrapperWorld.h"
+#include "bindings/v8/ScriptController.h"
+#include "bindings/v8/ScriptObject.h"
+#include "core/dom/DOMImplementation.h"
+#include "core/dom/DeviceOrientationController.h"
+#include "core/dom/Document.h"
+#include "core/dom/UserGestureIndicator.h"
+#include "core/html/HTMLFrameOwnerElement.h"
+#include "core/inspector/ContentSearchUtils.h"
+#include "core/inspector/DOMPatchSupport.h"
+#include "core/inspector/IdentifiersFactory.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorAgent.h"
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/InspectorOverlay.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/loader/CookieJar.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/TextResourceDecoder.h"
+#include "core/loader/cache/CachedCSSStyleSheet.h"
+#include "core/loader/cache/CachedFont.h"
+#include "core/loader/cache/CachedImage.h"
+#include "core/loader/cache/CachedResource.h"
+#include "core/loader/cache/CachedResourceLoader.h"
+#include "core/loader/cache/CachedScript.h"
+#include "core/loader/cache/MemoryCache.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/page/Page.h"
+#include "core/page/SecurityOrigin.h"
+#include "core/page/Settings.h"
+#include "core/platform/Cookie.h"
+#include "core/platform/text/RegularExpression.h"
+#include "core/platform/text/TextEncoding.h"
+#include "modules/geolocation/GeolocationController.h"
+#include "modules/geolocation/GeolocationError.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/text/Base64.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+namespace WebCore {
+
+namespace PageAgentState {
+static const char pageAgentEnabled[] = "pageAgentEnabled";
+static const char pageAgentScriptExecutionDisabled[] = "pageAgentScriptExecutionDisabled";
+static const char pageAgentScriptsToEvaluateOnLoad[] = "pageAgentScriptsToEvaluateOnLoad";
+static const char pageAgentScreenWidthOverride[] = "pageAgentScreenWidthOverride";
+static const char pageAgentScreenHeightOverride[] = "pageAgentScreenHeightOverride";
+static const char pageAgentFontScaleFactorOverride[] = "pageAgentFontScaleFactorOverride";
+static const char pageAgentFitWindow[] = "pageAgentFitWindow";
+static const char pageAgentShowFPSCounter[] = "pageAgentShowFPSCounter";
+static const char pageAgentContinuousPaintingEnabled[] = "pageAgentContinuousPaintingEnabled";
+static const char pageAgentShowPaintRects[] = "pageAgentShowPaintRects";
+static const char pageAgentShowDebugBorders[] = "pageAgentShowDebugBorders";
+static const char touchEventEmulationEnabled[] = "touchEventEmulationEnabled";
+static const char pageAgentEmulatedMedia[] = "pageAgentEmulatedMedia";
+}
+
+static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result)
+{
+ if (buffer) {
+ TextEncoding encoding(textEncodingName);
+ if (!encoding.isValid())
+ encoding = WindowsLatin1Encoding();
+ *result = encoding.decode(buffer, size);
+ return true;
+ }
+ return false;
+}
+
+static bool prepareCachedResourceBuffer(CachedResource* cachedResource, bool* hasZeroSize)
+{
+ *hasZeroSize = false;
+ if (!cachedResource)
+ return false;
+
+ // Zero-sized resources don't have data at all -- so fake the empty buffer, instead of indicating error by returning 0.
+ if (!cachedResource->encodedSize()) {
+ *hasZeroSize = true;
+ return true;
+ }
+
+ if (cachedResource->isPurgeable()) {
+ // If the resource is purgeable then make it unpurgeable to get
+ // get its data. This might fail, in which case we return an
+ // empty String.
+ // FIXME: should we do something else in the case of a purged
+ // resource that informs the user why there is no data in the
+ // inspector?
+ if (!cachedResource->makePurgeable(false))
+ return false;
+ }
+
+ return true;
+}
+
+static bool hasTextContent(CachedResource* cachedResource)
+{
+ InspectorPageAgent::ResourceType type = InspectorPageAgent::cachedResourceType(*cachedResource);
+ return type == InspectorPageAgent::DocumentResource || type == InspectorPageAgent::StylesheetResource || type == InspectorPageAgent::ScriptResource || type == InspectorPageAgent::XHRResource;
+}
+
+static PassRefPtr<TextResourceDecoder> createXHRTextDecoder(const String& mimeType, const String& textEncodingName)
+{
+ RefPtr<TextResourceDecoder> decoder;
+ if (!textEncodingName.isEmpty())
+ decoder = TextResourceDecoder::create("text/plain", textEncodingName);
+ else if (DOMImplementation::isXMLMIMEType(mimeType.lower())) {
+ decoder = TextResourceDecoder::create("application/xml");
+ decoder->useLenientXMLDecoding();
+ } else if (equalIgnoringCase(mimeType, "text/html"))
+ decoder = TextResourceDecoder::create("text/html", "UTF-8");
+ else
+ decoder = TextResourceDecoder::create("text/plain", "UTF-8");
+ return decoder;
+}
+
+bool InspectorPageAgent::cachedResourceContent(CachedResource* cachedResource, String* result, bool* base64Encoded)
+{
+ bool hasZeroSize;
+ bool prepared = prepareCachedResourceBuffer(cachedResource, &hasZeroSize);
+ if (!prepared)
+ return false;
+
+ *base64Encoded = !hasTextContent(cachedResource);
+ if (*base64Encoded) {
+ RefPtr<SharedBuffer> buffer = hasZeroSize ? SharedBuffer::create() : cachedResource->resourceBuffer();
+
+ if (!buffer)
+ return false;
+
+ *result = base64Encode(buffer->data(), buffer->size());
+ return true;
+ }
+
+ if (hasZeroSize) {
+ *result = "";
+ return true;
+ }
+
+ if (cachedResource) {
+ switch (cachedResource->type()) {
+ case CachedResource::CSSStyleSheet:
+ *result = static_cast<CachedCSSStyleSheet*>(cachedResource)->sheetText(false);
+ return true;
+ case CachedResource::Script:
+ *result = static_cast<CachedScript*>(cachedResource)->script();
+ return true;
+ case CachedResource::RawResource: {
+ SharedBuffer* buffer = cachedResource->resourceBuffer();
+ if (!buffer)
+ return false;
+ RefPtr<TextResourceDecoder> decoder = createXHRTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName());
+ // We show content for raw resources only for certain mime types (text, html and xml). Otherwise decoder will be null.
+ if (!decoder)
+ return false;
+ String content = decoder->decode(buffer->data(), buffer->size());
+ *result = content + decoder->flush();
+ return true;
+ }
+ default:
+ SharedBuffer* buffer = cachedResource->resourceBuffer();
+ return decodeBuffer(buffer ? buffer->data() : 0, buffer ? buffer->size() : 0, cachedResource->encoding(), result);
+ }
+ }
+ return false;
+}
+
+bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
+{
+ RefPtr<SharedBuffer> buffer = frame->loader()->documentLoader()->mainResourceData();
+ if (!buffer)
+ return false;
+ String textEncodingName = frame->document()->inputEncoding();
+
+ return InspectorPageAgent::dataContent(buffer->data(), buffer->size(), textEncodingName, withBase64Encode, result);
+}
+
+// static
+bool InspectorPageAgent::sharedBufferContent(PassRefPtr<SharedBuffer> buffer, const String& textEncodingName, bool withBase64Encode, String* result)
+{
+ return dataContent(buffer ? buffer->data() : 0, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result);
+}
+
+bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result)
+{
+ if (withBase64Encode) {
+ *result = base64Encode(data, size);
+ return true;
+ }
+
+ return decodeBuffer(data, size, textEncodingName, result);
+}
+
+PassOwnPtr<InspectorPageAgent> InspectorPageAgent::create(InstrumentingAgents* instrumentingAgents, Page* page, InspectorAgent* inspectorAgent, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, InspectorClient* client, InspectorOverlay* overlay)
+{
+ return adoptPtr(new InspectorPageAgent(instrumentingAgents, page, inspectorAgent, state, injectedScriptManager, client, overlay));
+}
+
+// static
+void InspectorPageAgent::resourceContent(ErrorString* errorString, Frame* frame, const KURL& url, String* result, bool* base64Encoded)
+{
+ DocumentLoader* loader = assertDocumentLoader(errorString, frame);
+ if (!loader)
+ return;
+
+ RefPtr<SharedBuffer> buffer;
+ bool success = false;
+ if (equalIgnoringFragmentIdentifier(url, loader->url())) {
+ *base64Encoded = false;
+ success = mainResourceContent(frame, *base64Encoded, result);
+ }
+
+ if (!success)
+ success = cachedResourceContent(cachedResource(frame, url), result, base64Encoded);
+
+ if (!success)
+ *errorString = "No resource with given URL found";
+}
+
+CachedResource* InspectorPageAgent::cachedResource(Frame* frame, const KURL& url)
+{
+ CachedResource* cachedResource = frame->document()->cachedResourceLoader()->cachedResource(url);
+ if (!cachedResource)
+ cachedResource = memoryCache()->resourceForURL(url);
+ return cachedResource;
+}
+
+TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType)
+{
+ switch (resourceType) {
+ case DocumentResource:
+ return TypeBuilder::Page::ResourceType::Document;
+ case ImageResource:
+ return TypeBuilder::Page::ResourceType::Image;
+ case FontResource:
+ return TypeBuilder::Page::ResourceType::Font;
+ case StylesheetResource:
+ return TypeBuilder::Page::ResourceType::Stylesheet;
+ case ScriptResource:
+ return TypeBuilder::Page::ResourceType::Script;
+ case XHRResource:
+ return TypeBuilder::Page::ResourceType::XHR;
+ case WebSocketResource:
+ return TypeBuilder::Page::ResourceType::WebSocket;
+ case OtherResource:
+ return TypeBuilder::Page::ResourceType::Other;
+ }
+ return TypeBuilder::Page::ResourceType::Other;
+}
+
+InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const CachedResource& cachedResource)
+{
+ switch (cachedResource.type()) {
+ case CachedResource::ImageResource:
+ return InspectorPageAgent::ImageResource;
+ case CachedResource::FontResource:
+ return InspectorPageAgent::FontResource;
+ case CachedResource::CSSStyleSheet:
+ // Fall through.
+ case CachedResource::XSLStyleSheet:
+ return InspectorPageAgent::StylesheetResource;
+ case CachedResource::Script:
+ return InspectorPageAgent::ScriptResource;
+ case CachedResource::RawResource:
+ return InspectorPageAgent::XHRResource;
+ case CachedResource::MainResource:
+ return InspectorPageAgent::DocumentResource;
+ default:
+ break;
+ }
+ return InspectorPageAgent::OtherResource;
+}
+
+TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::cachedResourceTypeJson(const CachedResource& cachedResource)
+{
+ return resourceTypeJson(cachedResourceType(cachedResource));
+}
+
+InspectorPageAgent::InspectorPageAgent(InstrumentingAgents* instrumentingAgents, Page* page, InspectorAgent* inspectorAgent, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager, InspectorClient* client, InspectorOverlay* overlay)
+ : InspectorBaseAgent<InspectorPageAgent>("Page", instrumentingAgents, inspectorState)
+ , m_page(page)
+ , m_inspectorAgent(inspectorAgent)
+ , m_injectedScriptManager(injectedScriptManager)
+ , m_client(client)
+ , m_frontend(0)
+ , m_overlay(overlay)
+ , m_lastScriptIdentifier(0)
+ , m_enabled(false)
+ , m_isFirstLayoutAfterOnLoad(false)
+ , m_geolocationOverridden(false)
+ , m_ignoreScriptsEnabledNotification(false)
+{
+}
+
+void InspectorPageAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->page();
+}
+
+void InspectorPageAgent::clearFrontend()
+{
+ ErrorString error;
+ disable(&error);
+ updateTouchEventEmulationInPage(false);
+ m_frontend = 0;
+}
+
+void InspectorPageAgent::restore()
+{
+ if (m_state->getBoolean(PageAgentState::pageAgentEnabled)) {
+ ErrorString error;
+ enable(&error);
+ bool scriptExecutionDisabled = m_state->getBoolean(PageAgentState::pageAgentScriptExecutionDisabled);
+ setScriptExecutionDisabled(0, scriptExecutionDisabled);
+ bool showPaintRects = m_state->getBoolean(PageAgentState::pageAgentShowPaintRects);
+ setShowPaintRects(0, showPaintRects);
+ bool showDebugBorders = m_state->getBoolean(PageAgentState::pageAgentShowDebugBorders);
+ setShowDebugBorders(0, showDebugBorders);
+ bool showFPSCounter = m_state->getBoolean(PageAgentState::pageAgentShowFPSCounter);
+ setShowFPSCounter(0, showFPSCounter);
+ String emulatedMedia = m_state->getString(PageAgentState::pageAgentEmulatedMedia);
+ setEmulatedMedia(0, emulatedMedia);
+ bool continuousPaintingEnabled = m_state->getBoolean(PageAgentState::pageAgentContinuousPaintingEnabled);
+ setContinuousPaintingEnabled(0, continuousPaintingEnabled);
+
+ int currentWidth = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenWidthOverride));
+ int currentHeight = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenHeightOverride));
+ double currentFontScaleFactor = m_state->getDouble(PageAgentState::pageAgentFontScaleFactorOverride);
+ bool currentFitWindow = m_state->getBoolean(PageAgentState::pageAgentFitWindow);
+ updateViewMetrics(currentWidth, currentHeight, currentFontScaleFactor, currentFitWindow);
+ updateTouchEventEmulationInPage(m_state->getBoolean(PageAgentState::touchEventEmulationEnabled));
+ }
+}
+
+void InspectorPageAgent::webViewResized(const IntSize& size)
+{
+ int currentWidth = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenWidthOverride));
+ m_overlay->resize(currentWidth ? size : IntSize());
+}
+
+void InspectorPageAgent::enable(ErrorString*)
+{
+ m_enabled = true;
+ m_state->setBoolean(PageAgentState::pageAgentEnabled, true);
+ m_instrumentingAgents->setInspectorPageAgent(this);
+}
+
+void InspectorPageAgent::disable(ErrorString*)
+{
+ m_enabled = false;
+ m_state->setBoolean(PageAgentState::pageAgentEnabled, false);
+ m_state->remove(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
+ m_overlay->hide();
+ m_instrumentingAgents->setInspectorPageAgent(0);
+
+ setShowPaintRects(0, false);
+ setShowDebugBorders(0, false);
+ setShowFPSCounter(0, false);
+ setEmulatedMedia(0, "");
+ setContinuousPaintingEnabled(0, false);
+
+ if (!deviceMetricsChanged(0, 0, 1, false))
+ return;
+
+ // When disabling the agent, reset the override values if necessary.
+ updateViewMetrics(0, 0, 1, false);
+ m_state->setLong(PageAgentState::pageAgentScreenWidthOverride, 0);
+ m_state->setLong(PageAgentState::pageAgentScreenHeightOverride, 0);
+ m_state->setDouble(PageAgentState::pageAgentFontScaleFactorOverride, 1);
+ m_state->setBoolean(PageAgentState::pageAgentFitWindow, false);
+}
+
+void InspectorPageAgent::addScriptToEvaluateOnLoad(ErrorString*, const String& source, String* identifier)
+{
+ RefPtr<InspectorObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
+ if (!scripts) {
+ scripts = InspectorObject::create();
+ m_state->setObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad, scripts);
+ }
+ // Assure we don't override existing ids -- m_lastScriptIdentifier could get out of sync WRT actual
+ // scripts once we restored the scripts from the cookie during navigation.
+ do {
+ *identifier = String::number(++m_lastScriptIdentifier);
+ } while (scripts->find(*identifier) != scripts->end());
+ scripts->setString(*identifier, source);
+
+ // Force cookie serialization.
+ m_state->setObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad, scripts);
+}
+
+void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString* error, const String& identifier)
+{
+ RefPtr<InspectorObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
+ if (!scripts || scripts->find(identifier) == scripts->end()) {
+ *error = "Script not found";
+ return;
+ }
+ scripts->remove(identifier);
+}
+
+void InspectorPageAgent::reload(ErrorString*, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad, const String* optionalScriptPreprocessor)
+{
+ m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : "";
+ m_pendingScriptPreprocessor = optionalScriptPreprocessor ? *optionalScriptPreprocessor : "";
+ m_page->mainFrame()->loader()->reload(optionalIgnoreCache ? *optionalIgnoreCache : false);
+}
+
+void InspectorPageAgent::navigate(ErrorString*, const String& url)
+{
+ UserGestureIndicator indicator(DefinitelyProcessingNewUserGesture);
+ Frame* frame = m_page->mainFrame();
+ frame->loader()->changeLocation(frame->document()->securityOrigin(), frame->document()->completeURL(url), "", false, false);
+}
+
+static PassRefPtr<TypeBuilder::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
+{
+ return TypeBuilder::Page::Cookie::create()
+ .setName(cookie.name)
+ .setValue(cookie.value)
+ .setDomain(cookie.domain)
+ .setPath(cookie.path)
+ .setExpires(cookie.expires)
+ .setSize((cookie.name.length() + cookie.value.length()))
+ .setHttpOnly(cookie.httpOnly)
+ .setSecure(cookie.secure)
+ .setSession(cookie.session)
+ .release();
+}
+
+static PassRefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> > buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> > cookies = TypeBuilder::Array<TypeBuilder::Page::Cookie>::create();
+
+ ListHashSet<Cookie>::iterator end = cookiesList.end();
+ ListHashSet<Cookie>::iterator it = cookiesList.begin();
+ for (int i = 0; it != end; ++it, i++)
+ cookies->addItem(buildObjectForCookie(*it));
+
+ return cookies;
+}
+
+static Vector<CachedResource*> cachedResourcesForFrame(Frame* frame)
+{
+ Vector<CachedResource*> result;
+
+ const CachedResourceLoader::DocumentResourceMap& allResources = frame->document()->cachedResourceLoader()->allCachedResources();
+ CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
+ for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
+ CachedResource* cachedResource = it->value.get();
+
+ switch (cachedResource->type()) {
+ case CachedResource::ImageResource:
+ // Skip images that were not auto loaded (images disabled in the user agent).
+ if (static_cast<CachedImage*>(cachedResource)->stillNeedsLoad())
+ continue;
+ break;
+ case CachedResource::FontResource:
+ // Skip fonts that were referenced in CSS but never used/downloaded.
+ if (static_cast<CachedFont*>(cachedResource)->stillNeedsLoad())
+ continue;
+ break;
+ default:
+ // All other CachedResource types download immediately.
+ break;
+ }
+
+ result.append(cachedResource);
+ }
+
+ return result;
+}
+
+static Vector<KURL> allResourcesURLsForFrame(Frame* frame)
+{
+ Vector<KURL> result;
+
+ result.append(frame->loader()->documentLoader()->url());
+
+ Vector<CachedResource*> allResources = cachedResourcesForFrame(frame);
+ for (Vector<CachedResource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it)
+ result.append((*it)->url());
+
+ return result;
+}
+
+void InspectorPageAgent::getCookies(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> >& cookies, WTF::String* cookiesString)
+{
+ ListHashSet<Cookie> rawCookiesList;
+
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext(mainFrame())) {
+ Document* document = frame->document();
+ Vector<KURL> allURLs = allResourcesURLsForFrame(frame);
+ for (Vector<KURL>::const_iterator it = allURLs.begin(); it != allURLs.end(); ++it) {
+ Vector<Cookie> docCookiesList;
+ getRawCookies(document, KURL(ParsedURLString, *it), docCookiesList);
+ int cookiesSize = docCookiesList.size();
+ for (int i = 0; i < cookiesSize; i++) {
+ if (!rawCookiesList.contains(docCookiesList[i]))
+ rawCookiesList.add(docCookiesList[i]);
+ }
+ }
+ }
+
+ // FIXME: Remove "cookiesString" output.
+ cookies = buildArrayForCookies(rawCookiesList);
+ *cookiesString = "";
+}
+
+void InspectorPageAgent::deleteCookie(ErrorString*, const String& cookieName, const String& url)
+{
+ KURL parsedURL(ParsedURLString, url);
+ for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext(m_page->mainFrame()))
+ WebCore::deleteCookie(frame->document(), parsedURL, cookieName);
+}
+
+void InspectorPageAgent::getResourceTree(ErrorString*, RefPtr<TypeBuilder::Page::FrameResourceTree>& object)
+{
+ object = buildObjectForFrameTree(m_page->mainFrame());
+}
+
+void InspectorPageAgent::getResourceContent(ErrorString* errorString, const String& frameId, const String& url, String* content, bool* base64Encoded)
+{
+ Frame* frame = assertFrame(errorString, frameId);
+ if (!frame)
+ return;
+
+ resourceContent(errorString, frame, KURL(ParsedURLString, url), content, base64Encoded);
+}
+
+static bool textContentForCachedResource(CachedResource* cachedResource, String* result)
+{
+ if (hasTextContent(cachedResource)) {
+ String content;
+ bool base64Encoded;
+ if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
+ ASSERT(!base64Encoded);
+ return true;
+ }
+ }
+ return false;
+}
+
+void InspectorPageAgent::searchInResource(ErrorString*, const String& frameId, const String& url, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> >& results)
+{
+ results = TypeBuilder::Array<TypeBuilder::Page::SearchMatch>::create();
+
+ bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
+ bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
+
+ Frame* frame = frameForId(frameId);
+ KURL kurl(ParsedURLString, url);
+
+ FrameLoader* frameLoader = frame ? frame->loader() : 0;
+ DocumentLoader* loader = frameLoader ? frameLoader->documentLoader() : 0;
+ if (!loader)
+ return;
+
+ String content;
+ bool success = false;
+ if (equalIgnoringFragmentIdentifier(kurl, loader->url()))
+ success = mainResourceContent(frame, false, &content);
+
+ if (!success) {
+ CachedResource* resource = cachedResource(frame, kurl);
+ if (resource)
+ success = textContentForCachedResource(resource, &content);
+ }
+
+ if (!success)
+ return;
+
+ results = ContentSearchUtils::searchInTextByLines(content, query, caseSensitive, isRegex);
+}
+
+static PassRefPtr<TypeBuilder::Page::SearchResult> buildObjectForSearchResult(const String& frameId, const String& url, int matchesCount)
+{
+ return TypeBuilder::Page::SearchResult::create()
+ .setUrl(url)
+ .setFrameId(frameId)
+ .setMatchesCount(matchesCount)
+ .release();
+}
+
+void InspectorPageAgent::searchInResources(ErrorString*, const String& text, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchResult> >& results)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchResult> > searchResults = TypeBuilder::Array<TypeBuilder::Page::SearchResult>::create();
+
+ bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
+ bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
+ OwnPtr<RegularExpression> regex = ContentSearchUtils::createSearchRegex(text, caseSensitive, isRegex);
+
+ for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext(m_page->mainFrame())) {
+ String content;
+ Vector<CachedResource*> allResources = cachedResourcesForFrame(frame);
+ for (Vector<CachedResource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it) {
+ CachedResource* cachedResource = *it;
+ if (textContentForCachedResource(cachedResource, &content)) {
+ int matchesCount = ContentSearchUtils::countRegularExpressionMatches(regex.get(), content);
+ if (matchesCount)
+ searchResults->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
+ }
+ }
+ if (mainResourceContent(frame, false, &content)) {
+ int matchesCount = ContentSearchUtils::countRegularExpressionMatches(regex.get(), content);
+ if (matchesCount)
+ searchResults->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
+ }
+ }
+
+ results = searchResults;
+}
+
+void InspectorPageAgent::setDocumentContent(ErrorString* errorString, const String& frameId, const String& html)
+{
+ Frame* frame = assertFrame(errorString, frameId);
+ if (!frame)
+ return;
+
+ Document* document = frame->document();
+ if (!document) {
+ *errorString = "No Document instance to set HTML for";
+ return;
+ }
+ DOMPatchSupport::patchDocument(document, html);
+}
+
+void InspectorPageAgent::setDeviceMetricsOverride(ErrorString* errorString, int width, int height, double fontScaleFactor, bool fitWindow)
+{
+ const static long maxDimension = 10000000;
+
+ if (width < 0 || height < 0 || width > maxDimension || height > maxDimension) {
+ *errorString = makeString("Width and height values must be positive, not greater than ", String::number(maxDimension));
+ return;
+ }
+
+ if (!width ^ !height) {
+ *errorString = "Both width and height must be either zero or non-zero at once";
+ return;
+ }
+
+ if (fontScaleFactor <= 0) {
+ *errorString = "fontScaleFactor must be positive";
+ return;
+ }
+
+ if (!deviceMetricsChanged(width, height, fontScaleFactor, fitWindow))
+ return;
+
+ m_state->setLong(PageAgentState::pageAgentScreenWidthOverride, width);
+ m_state->setLong(PageAgentState::pageAgentScreenHeightOverride, height);
+ m_state->setDouble(PageAgentState::pageAgentFontScaleFactorOverride, fontScaleFactor);
+ m_state->setBoolean(PageAgentState::pageAgentFitWindow, fitWindow);
+
+ updateViewMetrics(width, height, fontScaleFactor, fitWindow);
+}
+
+bool InspectorPageAgent::deviceMetricsChanged(int width, int height, double fontScaleFactor, bool fitWindow)
+{
+ // These two always fit an int.
+ int currentWidth = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenWidthOverride));
+ int currentHeight = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenHeightOverride));
+ double currentFontScaleFactor = m_state->getDouble(PageAgentState::pageAgentFontScaleFactorOverride);
+ bool currentFitWindow = m_state->getBoolean(PageAgentState::pageAgentFitWindow);
+
+ return width != currentWidth || height != currentHeight || fontScaleFactor != currentFontScaleFactor || fitWindow != currentFitWindow;
+}
+
+void InspectorPageAgent::setShowPaintRects(ErrorString*, bool show)
+{
+ m_state->setBoolean(PageAgentState::pageAgentShowPaintRects, show);
+ m_client->setShowPaintRects(show);
+
+ if (!show && mainFrame() && mainFrame()->view())
+ mainFrame()->view()->invalidate();
+}
+
+void InspectorPageAgent::setShowDebugBorders(ErrorString*, bool show)
+{
+ m_state->setBoolean(PageAgentState::pageAgentShowDebugBorders, show);
+ m_client->setShowDebugBorders(show);
+ if (mainFrame() && mainFrame()->view())
+ mainFrame()->view()->invalidate();
+}
+
+void InspectorPageAgent::canShowFPSCounter(ErrorString*, bool* outParam)
+{
+ *outParam = m_client->canShowFPSCounter();
+}
+
+void InspectorPageAgent::setShowFPSCounter(ErrorString*, bool show)
+{
+ m_state->setBoolean(PageAgentState::pageAgentShowFPSCounter, show);
+ m_client->setShowFPSCounter(show);
+
+ if (mainFrame() && mainFrame()->view())
+ mainFrame()->view()->invalidate();
+}
+
+void InspectorPageAgent::canContinuouslyPaint(ErrorString*, bool* outParam)
+{
+ *outParam = m_client->canContinuouslyPaint();
+}
+
+void InspectorPageAgent::setContinuousPaintingEnabled(ErrorString*, bool enabled)
+{
+ m_state->setBoolean(PageAgentState::pageAgentContinuousPaintingEnabled, enabled);
+ m_client->setContinuousPaintingEnabled(enabled);
+
+ if (!enabled && mainFrame() && mainFrame()->view())
+ mainFrame()->view()->invalidate();
+}
+
+void InspectorPageAgent::getScriptExecutionStatus(ErrorString*, PageCommandHandler::Result::Enum* status)
+{
+ bool disabledByScriptController = false;
+ bool disabledInSettings = false;
+ Frame* frame = mainFrame();
+ if (frame) {
+ disabledByScriptController = !frame->script()->canExecuteScripts(NotAboutToExecuteScript);
+ if (frame->settings())
+ disabledInSettings = !frame->settings()->isScriptEnabled();
+ }
+
+ if (!disabledByScriptController) {
+ *status = PageCommandHandler::Result::Allowed;
+ return;
+ }
+
+ if (disabledInSettings)
+ *status = PageCommandHandler::Result::Disabled;
+ else
+ *status = PageCommandHandler::Result::Forbidden;
+}
+
+void InspectorPageAgent::setScriptExecutionDisabled(ErrorString*, bool value)
+{
+ m_state->setBoolean(PageAgentState::pageAgentScriptExecutionDisabled, value);
+ if (!mainFrame())
+ return;
+
+ Settings* settings = mainFrame()->settings();
+ if (settings) {
+ m_ignoreScriptsEnabledNotification = true;
+ settings->setScriptEnabled(!value);
+ m_ignoreScriptsEnabledNotification = false;
+ }
+}
+
+void InspectorPageAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld* world)
+{
+ if (world != mainThreadNormalWorld())
+ return;
+
+ if (frame == m_page->mainFrame())
+ m_injectedScriptManager->discardInjectedScripts();
+
+ if (!m_frontend)
+ return;
+
+ RefPtr<InspectorObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
+ if (scripts) {
+ InspectorObject::const_iterator end = scripts->end();
+ for (InspectorObject::const_iterator it = scripts->begin(); it != end; ++it) {
+ String scriptText;
+ if (it->value->asString(&scriptText))
+ frame->script()->executeScript(scriptText);
+ }
+ }
+ if (!m_scriptToEvaluateOnLoadOnce.isEmpty())
+ frame->script()->executeScript(m_scriptToEvaluateOnLoadOnce);
+}
+
+void InspectorPageAgent::domContentEventFired()
+{
+ m_isFirstLayoutAfterOnLoad = true;
+ m_frontend->domContentEventFired(currentTime());
+}
+
+void InspectorPageAgent::loadEventFired()
+{
+ m_frontend->loadEventFired(currentTime());
+}
+
+void InspectorPageAgent::frameNavigated(DocumentLoader* loader)
+{
+ if (loader->frame() == m_page->mainFrame()) {
+ m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce;
+ m_scriptPreprocessor = m_pendingScriptPreprocessor;
+ m_pendingScriptToEvaluateOnLoadOnce = String();
+ m_pendingScriptPreprocessor = String();
+ }
+ m_frontend->frameNavigated(buildObjectForFrame(loader->frame()));
+}
+
+void InspectorPageAgent::frameDetachedFromParent(Frame* frame)
+{
+ HashMap<Frame*, String>::iterator iterator = m_frameToIdentifier.find(frame);
+ if (iterator != m_frameToIdentifier.end()) {
+ m_frontend->frameDetached(iterator->value);
+ m_identifierToFrame.remove(iterator->value);
+ m_frameToIdentifier.remove(iterator);
+ }
+}
+
+Frame* InspectorPageAgent::mainFrame()
+{
+ return m_page->mainFrame();
+}
+
+Frame* InspectorPageAgent::frameForId(const String& frameId)
+{
+ return frameId.isEmpty() ? 0 : m_identifierToFrame.get(frameId);
+}
+
+String InspectorPageAgent::frameId(Frame* frame)
+{
+ if (!frame)
+ return "";
+ String identifier = m_frameToIdentifier.get(frame);
+ if (identifier.isNull()) {
+ identifier = IdentifiersFactory::createIdentifier();
+ m_frameToIdentifier.set(frame, identifier);
+ m_identifierToFrame.set(identifier, frame);
+ }
+ return identifier;
+}
+
+bool InspectorPageAgent::hasIdForFrame(Frame* frame) const
+{
+ return frame && m_frameToIdentifier.contains(frame);
+}
+
+String InspectorPageAgent::loaderId(DocumentLoader* loader)
+{
+ if (!loader)
+ return "";
+ String identifier = m_loaderToIdentifier.get(loader);
+ if (identifier.isNull()) {
+ identifier = IdentifiersFactory::createIdentifier();
+ m_loaderToIdentifier.set(loader, identifier);
+ }
+ return identifier;
+}
+
+Frame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString)
+{
+ for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ RefPtr<SecurityOrigin> documentOrigin = frame->document()->securityOrigin();
+ if (documentOrigin->toRawString() == originRawString)
+ return frame;
+ }
+ return 0;
+}
+
+Frame* InspectorPageAgent::assertFrame(ErrorString* errorString, const String& frameId)
+{
+ Frame* frame = frameForId(frameId);
+ if (!frame)
+ *errorString = "No frame for given id found";
+ return frame;
+}
+
+// static
+DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString* errorString, Frame* frame)
+{
+ FrameLoader* frameLoader = frame->loader();
+ DocumentLoader* documentLoader = frameLoader ? frameLoader->documentLoader() : 0;
+ if (!documentLoader)
+ *errorString = "No documentLoader for given frame found";
+ return documentLoader;
+}
+
+void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader* loader)
+{
+ HashMap<DocumentLoader*, String>::iterator iterator = m_loaderToIdentifier.find(loader);
+ if (iterator != m_loaderToIdentifier.end())
+ m_loaderToIdentifier.remove(iterator);
+}
+
+void InspectorPageAgent::frameStartedLoading(Frame* frame)
+{
+ m_frontend->frameStartedLoading(frameId(frame));
+}
+
+void InspectorPageAgent::frameStoppedLoading(Frame* frame)
+{
+ m_frontend->frameStoppedLoading(frameId(frame));
+}
+
+void InspectorPageAgent::frameScheduledNavigation(Frame* frame, double delay)
+{
+ m_frontend->frameScheduledNavigation(frameId(frame), delay);
+}
+
+void InspectorPageAgent::frameClearedScheduledNavigation(Frame* frame)
+{
+ m_frontend->frameClearedScheduledNavigation(frameId(frame));
+}
+
+void InspectorPageAgent::willRunJavaScriptDialog(const String& message)
+{
+ m_frontend->javascriptDialogOpening(message);
+}
+
+void InspectorPageAgent::didRunJavaScriptDialog()
+{
+ m_frontend->javascriptDialogClosed();
+}
+
+void InspectorPageAgent::applyScreenWidthOverride(long* width)
+{
+ long widthOverride = m_state->getLong(PageAgentState::pageAgentScreenWidthOverride);
+ if (widthOverride)
+ *width = widthOverride;
+}
+
+void InspectorPageAgent::applyScreenHeightOverride(long* height)
+{
+ long heightOverride = m_state->getLong(PageAgentState::pageAgentScreenHeightOverride);
+ if (heightOverride)
+ *height = heightOverride;
+}
+
+void InspectorPageAgent::didPaint(RenderObject*, GraphicsContext* context, const LayoutRect& rect)
+{
+ if (!m_enabled || m_client->overridesShowPaintRects() || !m_state->getBoolean(PageAgentState::pageAgentShowPaintRects))
+ return;
+
+ static int colorSelector = 0;
+ const Color colors[] = {
+ Color(0xFF, 0, 0, 0x3F),
+ Color(0xFF, 0, 0xFF, 0x3F),
+ Color(0, 0, 0xFF, 0x3F),
+ };
+
+ LayoutRect inflatedRect(rect);
+ inflatedRect.inflate(-1);
+ m_overlay->drawOutline(context, inflatedRect, colors[colorSelector++ % WTF_ARRAY_LENGTH(colors)]);
+}
+
+void InspectorPageAgent::didLayout(RenderObject*)
+{
+ bool isFirstLayout = m_isFirstLayoutAfterOnLoad;
+ if (isFirstLayout)
+ m_isFirstLayoutAfterOnLoad = false;
+
+ if (!m_enabled)
+ return;
+
+ if (isFirstLayout) {
+ int currentWidth = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenWidthOverride));
+ int currentHeight = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenHeightOverride));
+
+ if (currentWidth && currentHeight)
+ m_client->autoZoomPageToFitWidth();
+ }
+ m_overlay->update();
+}
+
+void InspectorPageAgent::didScroll()
+{
+ if (m_enabled)
+ m_overlay->update();
+}
+
+void InspectorPageAgent::didResizeMainFrame()
+{
+ if (m_enabled)
+ m_overlay->showAndHideViewSize();
+}
+
+void InspectorPageAgent::didRecalculateStyle()
+{
+ if (m_enabled)
+ m_overlay->update();
+}
+
+void InspectorPageAgent::scriptsEnabled(bool isEnabled)
+{
+ if (m_ignoreScriptsEnabledNotification)
+ return;
+
+ m_frontend->scriptsEnabled(isEnabled);
+}
+
+PassRefPtr<TypeBuilder::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame)
+{
+ RefPtr<TypeBuilder::Page::Frame> frameObject = TypeBuilder::Page::Frame::create()
+ .setId(frameId(frame))
+ .setLoaderId(loaderId(frame->loader()->documentLoader()))
+ .setUrl(frame->document()->url().string())
+ .setMimeType(frame->loader()->documentLoader()->responseMIMEType())
+ .setSecurityOrigin(frame->document()->securityOrigin()->toRawString());
+ if (frame->tree()->parent())
+ frameObject->setParentId(frameId(frame->tree()->parent()));
+ if (frame->ownerElement()) {
+ String name = frame->ownerElement()->getNameAttribute();
+ if (name.isEmpty())
+ name = frame->ownerElement()->getAttribute(HTMLNames::idAttr);
+ frameObject->setName(name);
+ }
+
+ return frameObject;
+}
+
+PassRefPtr<TypeBuilder::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(Frame* frame)
+{
+ RefPtr<TypeBuilder::Page::Frame> frameObject = buildObjectForFrame(frame);
+ RefPtr<TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree::Resources> > subresources = TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree::Resources>::create();
+ RefPtr<TypeBuilder::Page::FrameResourceTree> result = TypeBuilder::Page::FrameResourceTree::create()
+ .setFrame(frameObject)
+ .setResources(subresources);
+
+ Vector<CachedResource*> allResources = cachedResourcesForFrame(frame);
+ for (Vector<CachedResource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it) {
+ CachedResource* cachedResource = *it;
+
+ RefPtr<TypeBuilder::Page::FrameResourceTree::Resources> resourceObject = TypeBuilder::Page::FrameResourceTree::Resources::create()
+ .setUrl(cachedResource->url())
+ .setType(cachedResourceTypeJson(*cachedResource))
+ .setMimeType(cachedResource->response().mimeType());
+ if (cachedResource->wasCanceled())
+ resourceObject->setCanceled(true);
+ else if (cachedResource->status() == CachedResource::LoadError)
+ resourceObject->setFailed(true);
+ subresources->addItem(resourceObject);
+ }
+
+ RefPtr<TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree> > childrenArray;
+ for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
+ if (!childrenArray) {
+ childrenArray = TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree>::create();
+ result->setChildFrames(childrenArray);
+ }
+ childrenArray->addItem(buildObjectForFrameTree(child));
+ }
+ return result;
+}
+
+void InspectorPageAgent::updateViewMetrics(int width, int height, double fontScaleFactor, bool fitWindow)
+{
+ m_client->overrideDeviceMetrics(width, height, static_cast<float>(fontScaleFactor), fitWindow);
+
+ Document* document = mainFrame()->document();
+ if (document)
+ document->styleResolverChanged(RecalcStyleImmediately);
+ InspectorInstrumentation::mediaQueryResultChanged(document);
+}
+
+void InspectorPageAgent::updateTouchEventEmulationInPage(bool enabled)
+{
+ m_state->setBoolean(PageAgentState::touchEventEmulationEnabled, enabled);
+ if (mainFrame() && mainFrame()->settings())
+ mainFrame()->settings()->setTouchEventEmulationEnabled(enabled);
+}
+
+void InspectorPageAgent::setGeolocationOverride(ErrorString* error, const double* latitude, const double* longitude, const double* accuracy)
+{
+ GeolocationController* controller = GeolocationController::from(m_page);
+ GeolocationPosition* position = 0;
+ if (!controller) {
+ *error = "Internal error: unable to override geolocation";
+ return;
+ }
+ position = controller->lastPosition();
+ if (!m_geolocationOverridden && position)
+ m_platformGeolocationPosition = position;
+
+ m_geolocationOverridden = true;
+ if (latitude && longitude && accuracy)
+ m_geolocationPosition = GeolocationPosition::create(currentTimeMS(), *latitude, *longitude, *accuracy);
+ else
+ m_geolocationPosition.clear();
+
+ controller->positionChanged(0); // Kick location update.
+}
+
+void InspectorPageAgent::clearGeolocationOverride(ErrorString*)
+{
+ if (!m_geolocationOverridden)
+ return;
+ m_geolocationOverridden = false;
+ m_geolocationPosition.clear();
+
+ GeolocationController* controller = GeolocationController::from(m_page);
+ if (controller && m_platformGeolocationPosition.get())
+ controller->positionChanged(m_platformGeolocationPosition.get());
+}
+
+GeolocationPosition* InspectorPageAgent::overrideGeolocationPosition(GeolocationPosition* position)
+{
+ if (m_geolocationOverridden) {
+ if (position)
+ m_platformGeolocationPosition = position;
+ return m_geolocationPosition.get();
+ }
+ return position;
+}
+
+void InspectorPageAgent::setDeviceOrientationOverride(ErrorString* error, double alpha, double beta, double gamma)
+{
+ DeviceOrientationController* controller = DeviceOrientationController::from(m_page);
+ if (!controller) {
+ *error = "Internal error: unable to override device orientation";
+ return;
+ }
+
+ ErrorString clearError;
+ clearDeviceOrientationOverride(&clearError);
+
+ m_deviceOrientation = DeviceOrientationData::create(true, alpha, true, beta, true, gamma);
+ controller->didChangeDeviceOrientation(m_deviceOrientation.get());
+}
+
+void InspectorPageAgent::clearDeviceOrientationOverride(ErrorString*)
+{
+ m_deviceOrientation.clear();
+}
+
+DeviceOrientationData* InspectorPageAgent::overrideDeviceOrientation(DeviceOrientationData* deviceOrientation)
+{
+ if (m_deviceOrientation)
+ deviceOrientation = m_deviceOrientation.get();
+ return deviceOrientation;
+}
+
+void InspectorPageAgent::setTouchEmulationEnabled(ErrorString* error, bool enabled)
+{
+ if (m_state->getBoolean(PageAgentState::touchEventEmulationEnabled) == enabled)
+ return;
+ UNUSED_PARAM(error);
+ updateTouchEventEmulationInPage(enabled);
+}
+
+void InspectorPageAgent::setEmulatedMedia(ErrorString*, const String& media)
+{
+ String currentMedia = m_state->getString(PageAgentState::pageAgentEmulatedMedia);
+ if (media == currentMedia)
+ return;
+
+ m_state->setString(PageAgentState::pageAgentEmulatedMedia, media);
+ Document* document = 0;
+ if (m_page->mainFrame())
+ document = m_page->mainFrame()->document();
+ if (document) {
+ document->styleResolverChanged(RecalcStyleImmediately);
+ document->updateLayout();
+ }
+}
+
+void InspectorPageAgent::applyEmulatedMedia(String* media)
+{
+ String emulatedMedia = m_state->getString(PageAgentState::pageAgentEmulatedMedia);
+ if (!emulatedMedia.isEmpty())
+ *media = emulatedMedia;
+}
+
+void InspectorPageAgent::getCompositingBordersVisible(ErrorString* error, bool* outParam)
+{
+ Settings* settings = m_page->settings();
+ if (!settings) {
+ *error = "Internal error: unable to read settings";
+ return;
+ }
+
+ *outParam = settings->showDebugBorders() || settings->showRepaintCounter();
+}
+
+void InspectorPageAgent::setCompositingBordersVisible(ErrorString*, bool visible)
+{
+ Settings* settings = m_page->settings();
+ if (!settings)
+ return;
+
+ settings->setShowDebugBorders(visible);
+ settings->setShowRepaintCounter(visible);
+}
+
+void InspectorPageAgent::captureScreenshot(ErrorString*, String*)
+{
+ // Handled on the browser level.
+}
+
+void InspectorPageAgent::handleJavaScriptDialog(ErrorString* errorString, bool accept, const String* promptText)
+{
+ // Handled on the browser level.
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorPageAgent.h b/Source/core/inspector/InspectorPageAgent.h
new file mode 100644
index 0000000..6d9cf83
--- /dev/null
+++ b/Source/core/inspector/InspectorPageAgent.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorPageAgent_h
+#define InspectorPageAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "core/dom/DeviceOrientationData.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/page/Frame.h"
+#include "modules/geolocation/GeolocationPosition.h"
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class CachedResource;
+class DOMWrapperWorld;
+class DocumentLoader;
+class Frame;
+class Frontend;
+class GraphicsContext;
+class InjectedScriptManager;
+class InspectorAgent;
+class InspectorArray;
+class InspectorClient;
+class InspectorObject;
+class InspectorOverlay;
+class InspectorState;
+class InstrumentingAgents;
+class KURL;
+class Page;
+class RenderObject;
+class RegularExpression;
+class SharedBuffer;
+class TextResourceDecoder;
+
+typedef String ErrorString;
+
+class InspectorPageAgent : public InspectorBaseAgent<InspectorPageAgent>, public InspectorBackendDispatcher::PageCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorPageAgent);
+public:
+ enum ResourceType {
+ DocumentResource,
+ StylesheetResource,
+ ImageResource,
+ FontResource,
+ ScriptResource,
+ XHRResource,
+ WebSocketResource,
+ OtherResource
+ };
+
+ static PassOwnPtr<InspectorPageAgent> create(InstrumentingAgents*, Page*, InspectorAgent*, InspectorCompositeState*, InjectedScriptManager*, InspectorClient*, InspectorOverlay*);
+
+ static bool cachedResourceContent(CachedResource*, String* result, bool* base64Encoded);
+ static bool sharedBufferContent(PassRefPtr<SharedBuffer>, const String& textEncodingName, bool withBase64Encode, String* result);
+ static void resourceContent(ErrorString*, Frame*, const KURL&, String* result, bool* base64Encoded);
+
+ static PassRefPtr<SharedBuffer> resourceData(Frame*, const KURL&, String* textEncodingName);
+ static CachedResource* cachedResource(Frame*, const KURL&);
+ static TypeBuilder::Page::ResourceType::Enum resourceTypeJson(ResourceType);
+ static ResourceType cachedResourceType(const CachedResource&);
+ static TypeBuilder::Page::ResourceType::Enum cachedResourceTypeJson(const CachedResource&);
+
+ // Page API for InspectorFrontend
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void addScriptToEvaluateOnLoad(ErrorString*, const String& source, String* result);
+ virtual void removeScriptToEvaluateOnLoad(ErrorString*, const String& identifier);
+ virtual void reload(ErrorString*, const bool* optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad, const String* optionalScriptPreprocessor);
+ virtual void navigate(ErrorString*, const String& url);
+ virtual void getCookies(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> >& cookies, WTF::String* cookiesString);
+ virtual void deleteCookie(ErrorString*, const String& cookieName, const String& url);
+ virtual void getResourceTree(ErrorString*, RefPtr<TypeBuilder::Page::FrameResourceTree>&);
+ virtual void getResourceContent(ErrorString*, const String& frameId, const String& url, String* content, bool* base64Encoded);
+ virtual void searchInResource(ErrorString*, const String& frameId, const String& url, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> >&);
+ virtual void searchInResources(ErrorString*, const String&, const bool* caseSensitive, const bool* isRegex, RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchResult> >&);
+ virtual void setDocumentContent(ErrorString*, const String& frameId, const String& html);
+ virtual void setDeviceMetricsOverride(ErrorString*, int width, int height, double fontScaleFactor, bool fitWindow);
+ virtual void setShowPaintRects(ErrorString*, bool show);
+ virtual void setShowDebugBorders(ErrorString*, bool show);
+ virtual void canShowFPSCounter(ErrorString*, bool*);
+ virtual void setShowFPSCounter(ErrorString*, bool show);
+ virtual void canContinuouslyPaint(ErrorString*, bool*);
+ virtual void setContinuousPaintingEnabled(ErrorString*, bool enabled);
+ virtual void getScriptExecutionStatus(ErrorString*, PageCommandHandler::Result::Enum*);
+ virtual void setScriptExecutionDisabled(ErrorString*, bool);
+ virtual void setGeolocationOverride(ErrorString*, const double*, const double*, const double*);
+ virtual void clearGeolocationOverride(ErrorString*);
+ virtual void setDeviceOrientationOverride(ErrorString*, double, double, double);
+ virtual void clearDeviceOrientationOverride(ErrorString*);
+ virtual void setTouchEmulationEnabled(ErrorString*, bool);
+ virtual void setEmulatedMedia(ErrorString*, const String&);
+ virtual void getCompositingBordersVisible(ErrorString*, bool* out_param);
+ virtual void setCompositingBordersVisible(ErrorString*, bool);
+ virtual void captureScreenshot(ErrorString*, String* data);
+ virtual void handleJavaScriptDialog(ErrorString*, bool accept, const String* promptText);
+
+ // Geolocation override helpers.
+ GeolocationPosition* overrideGeolocationPosition(GeolocationPosition*);
+
+ // DeviceOrientation helper
+ DeviceOrientationData* overrideDeviceOrientation(DeviceOrientationData*);
+
+ // InspectorInstrumentation API
+ void didClearWindowObjectInWorld(Frame*, DOMWrapperWorld*);
+ void domContentEventFired();
+ void loadEventFired();
+ void frameNavigated(DocumentLoader*);
+ void frameDetachedFromParent(Frame*);
+ void loaderDetachedFromFrame(DocumentLoader*);
+ void frameStartedLoading(Frame*);
+ void frameStoppedLoading(Frame*);
+ void frameScheduledNavigation(Frame*, double delay);
+ void frameClearedScheduledNavigation(Frame*);
+ void willRunJavaScriptDialog(const String& message);
+ void didRunJavaScriptDialog();
+ void applyScreenWidthOverride(long*);
+ void applyScreenHeightOverride(long*);
+ void applyEmulatedMedia(String*);
+ void didPaint(RenderObject*, GraphicsContext*, const LayoutRect&);
+ void didLayout(RenderObject*);
+ void didScroll();
+ void didResizeMainFrame();
+ void didRecalculateStyle();
+ void scriptsEnabled(bool isEnabled);
+
+ // Inspector Controller API
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ void webViewResized(const IntSize&);
+
+ // Cross-agents API
+ Page* page() { return m_page; }
+ Frame* mainFrame();
+ String createIdentifier();
+ Frame* frameForId(const String& frameId);
+ String frameId(Frame*);
+ bool hasIdForFrame(Frame*) const;
+ String loaderId(DocumentLoader*);
+ Frame* findFrameWithSecurityOrigin(const String& originRawString);
+ Frame* assertFrame(ErrorString*, const String& frameId);
+ String scriptPreprocessor() { return m_scriptPreprocessor; }
+ static DocumentLoader* assertDocumentLoader(ErrorString*, Frame*);
+
+private:
+ InspectorPageAgent(InstrumentingAgents*, Page*, InspectorAgent*, InspectorCompositeState*, InjectedScriptManager*, InspectorClient*, InspectorOverlay*);
+ bool deviceMetricsChanged(int width, int height, double fontScaleFactor, bool fitWindow);
+ void updateViewMetrics(int, int, double, bool);
+ void updateTouchEventEmulationInPage(bool);
+
+ static bool mainResourceContent(Frame*, bool withBase64Encode, String* result);
+ static bool dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result);
+
+ PassRefPtr<TypeBuilder::Page::Frame> buildObjectForFrame(Frame*);
+ PassRefPtr<TypeBuilder::Page::FrameResourceTree> buildObjectForFrameTree(Frame*);
+ Page* m_page;
+ InspectorAgent* m_inspectorAgent;
+ InjectedScriptManager* m_injectedScriptManager;
+ InspectorClient* m_client;
+ InspectorFrontend::Page* m_frontend;
+ InspectorOverlay* m_overlay;
+ long m_lastScriptIdentifier;
+ String m_pendingScriptToEvaluateOnLoadOnce;
+ String m_scriptToEvaluateOnLoadOnce;
+ String m_pendingScriptPreprocessor;
+ String m_scriptPreprocessor;
+ HashMap<Frame*, String> m_frameToIdentifier;
+ HashMap<String, Frame*> m_identifierToFrame;
+ HashMap<DocumentLoader*, String> m_loaderToIdentifier;
+ bool m_enabled;
+ bool m_isFirstLayoutAfterOnLoad;
+ bool m_geolocationOverridden;
+ bool m_ignoreScriptsEnabledNotification;
+ RefPtr<GeolocationPosition> m_geolocationPosition;
+ RefPtr<GeolocationPosition> m_platformGeolocationPosition;
+ RefPtr<DeviceOrientationData> m_deviceOrientation;
+};
+
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorPagerAgent_h)
diff --git a/Source/core/inspector/InspectorProfilerAgent.cpp b/Source/core/inspector/InspectorProfilerAgent.cpp
new file mode 100644
index 0000000..0d38b5d
--- /dev/null
+++ b/Source/core/inspector/InspectorProfilerAgent.cpp
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "core/inspector/InspectorProfilerAgent.h"
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/PageScriptDebugServer.h"
+#include "bindings/v8/ScriptObject.h"
+#include "bindings/v8/ScriptProfiler.h"
+#include "bindings/v8/WorkerScriptDebugServer.h"
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include "core/inspector/ConsoleAPITypes.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptHost.h"
+#include "core/inspector/InspectorConsoleAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/inspector/ScriptProfile.h"
+#include "core/page/Console.h"
+#include "core/page/ConsoleTypes.h"
+#include "core/page/Page.h"
+#include "core/platform/KURL.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/MemoryInstrumentationHashMap.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/text/StringConcatenate.h>
+
+namespace WebCore {
+
+namespace ProfilerAgentState {
+static const char userInitiatedProfiling[] = "userInitiatedProfiling";
+static const char profilerEnabled[] = "profilerEnabled";
+static const char profileHeadersRequested[] = "profileHeadersRequested";
+}
+
+static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
+static const char* const CPUProfileType = "CPU";
+
+
+class PageProfilerAgent : public InspectorProfilerAgent {
+public:
+ PageProfilerAgent(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, Page* inspectedPage, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager)
+ : InspectorProfilerAgent(instrumentingAgents, consoleAgent, state, injectedScriptManager), m_inspectedPage(inspectedPage) { }
+ virtual ~PageProfilerAgent() { }
+
+private:
+ virtual void startProfiling(const String& title)
+ {
+ ScriptProfiler::startForPage(m_inspectedPage, title);
+ }
+
+ virtual PassRefPtr<ScriptProfile> stopProfiling(const String& title)
+ {
+ return ScriptProfiler::stopForPage(m_inspectedPage, title);
+ }
+
+ Page* m_inspectedPage;
+};
+
+PassOwnPtr<InspectorProfilerAgent> InspectorProfilerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, Page* inspectedPage, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager)
+{
+ return adoptPtr(new PageProfilerAgent(instrumentingAgents, consoleAgent, inspectedPage, inspectorState, injectedScriptManager));
+}
+
+class WorkerProfilerAgent : public InspectorProfilerAgent {
+public:
+ WorkerProfilerAgent(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, WorkerContext* workerContext, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager)
+ : InspectorProfilerAgent(instrumentingAgents, consoleAgent, state, injectedScriptManager), m_workerContext(workerContext) { }
+ virtual ~WorkerProfilerAgent() { }
+
+private:
+ virtual void startProfiling(const String& title)
+ {
+ ScriptProfiler::startForWorkerContext(m_workerContext, title);
+ }
+
+ virtual PassRefPtr<ScriptProfile> stopProfiling(const String& title)
+ {
+ return ScriptProfiler::stopForWorkerContext(m_workerContext, title);
+ }
+
+ WorkerContext* m_workerContext;
+};
+
+PassOwnPtr<InspectorProfilerAgent> InspectorProfilerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, WorkerContext* workerContext, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager)
+{
+ return adoptPtr(new WorkerProfilerAgent(instrumentingAgents, consoleAgent, workerContext, inspectorState, injectedScriptManager));
+}
+
+InspectorProfilerAgent::InspectorProfilerAgent(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager)
+ : InspectorBaseAgent<InspectorProfilerAgent>("Profiler", instrumentingAgents, inspectorState)
+ , m_consoleAgent(consoleAgent)
+ , m_injectedScriptManager(injectedScriptManager)
+ , m_frontend(0)
+ , m_enabled(false)
+ , m_recordingCPUProfile(false)
+ , m_currentUserInitiatedProfileNumber(-1)
+ , m_nextUserInitiatedProfileNumber(1)
+ , m_profileNameIdleTimeMap(ScriptProfiler::currentProfileNameIdleTimeMap())
+ , m_previousTaskEndTime(0.0)
+{
+ m_instrumentingAgents->setInspectorProfilerAgent(this);
+}
+
+InspectorProfilerAgent::~InspectorProfilerAgent()
+{
+ m_instrumentingAgents->setInspectorProfilerAgent(0);
+}
+
+void InspectorProfilerAgent::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
+{
+ RefPtr<ScriptProfile> profile = prpProfile;
+ m_profiles.add(profile->uid(), profile);
+ if (m_frontend && m_state->getBoolean(ProfilerAgentState::profileHeadersRequested))
+ m_frontend->addProfileHeader(createProfileHeader(*profile));
+ addProfileFinishedMessageToConsole(profile, lineNumber, sourceURL);
+}
+
+void InspectorProfilerAgent::addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
+{
+ if (!m_frontend)
+ return;
+ RefPtr<ScriptProfile> profile = prpProfile;
+ String message = makeString(profile->title(), '#', String::number(profile->uid()));
+ m_consoleAgent->addMessageToConsole(ConsoleAPIMessageSource, ProfileEndMessageType, DebugMessageLevel, message, sourceURL, lineNumber);
+}
+
+void InspectorProfilerAgent::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL)
+{
+ if (!m_frontend)
+ return;
+ m_consoleAgent->addMessageToConsole(ConsoleAPIMessageSource, ProfileMessageType, DebugMessageLevel, title, sourceURL, lineNumber);
+}
+
+PassRefPtr<TypeBuilder::Profiler::ProfileHeader> InspectorProfilerAgent::createProfileHeader(const ScriptProfile& profile)
+{
+ return TypeBuilder::Profiler::ProfileHeader::create()
+ .setTypeId(TypeBuilder::Profiler::ProfileHeader::TypeId::CPU)
+ .setUid(profile.uid())
+ .setTitle(profile.title())
+ .release();
+}
+
+void InspectorProfilerAgent::enable(ErrorString*)
+{
+ if (enabled())
+ return;
+ m_state->setBoolean(ProfilerAgentState::profilerEnabled, true);
+ enable(false);
+}
+
+void InspectorProfilerAgent::disable(ErrorString*)
+{
+ m_state->setBoolean(ProfilerAgentState::profilerEnabled, false);
+ disable();
+}
+
+void InspectorProfilerAgent::disable()
+{
+ if (!m_enabled)
+ return;
+ m_enabled = false;
+ m_state->setBoolean(ProfilerAgentState::profileHeadersRequested, false);
+}
+
+void InspectorProfilerAgent::enable(bool skipRecompile)
+{
+ if (m_enabled)
+ return;
+ m_enabled = true;
+}
+
+String InspectorProfilerAgent::getCurrentUserInitiatedProfileName(bool incrementProfileNumber)
+{
+ if (incrementProfileNumber)
+ m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
+
+ return makeString(UserInitiatedProfileName, '.', String::number(m_currentUserInitiatedProfileNumber));
+}
+
+void InspectorProfilerAgent::getProfileHeaders(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader> >& headers)
+{
+ m_state->setBoolean(ProfilerAgentState::profileHeadersRequested, true);
+ headers = TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader>::create();
+
+ ProfilesMap::iterator profilesEnd = m_profiles.end();
+ for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it)
+ headers->addItem(createProfileHeader(*it->value));
+}
+
+void InspectorProfilerAgent::getCPUProfile(ErrorString* errorString, int rawUid, RefPtr<TypeBuilder::Profiler::CPUProfile>& profileObject)
+{
+ unsigned uid = static_cast<unsigned>(rawUid);
+ ProfilesMap::iterator it = m_profiles.find(uid);
+ if (it == m_profiles.end()) {
+ *errorString = "Profile wasn't found";
+ return;
+ }
+ profileObject = TypeBuilder::Profiler::CPUProfile::create();
+ profileObject->setHead(it->value->buildInspectorObjectForHead());
+ profileObject->setIdleTime(it->value->idleTime());
+ profileObject->setSamples(it->value->buildInspectorObjectForSamples());
+}
+
+void InspectorProfilerAgent::removeProfile(ErrorString*, const String& type, int rawUid)
+{
+ unsigned uid = static_cast<unsigned>(rawUid);
+ if (type == CPUProfileType) {
+ if (m_profiles.contains(uid))
+ m_profiles.remove(uid);
+ }
+}
+
+void InspectorProfilerAgent::clearProfiles(ErrorString*)
+{
+ stop();
+ m_profiles.clear();
+ m_currentUserInitiatedProfileNumber = 1;
+ m_nextUserInitiatedProfileNumber = 1;
+ resetFrontendProfiles();
+ m_injectedScriptManager->injectedScriptHost()->clearInspectedObjects();
+}
+
+void InspectorProfilerAgent::resetFrontendProfiles()
+{
+ if (!m_frontend)
+ return;
+ if (!m_state->getBoolean(ProfilerAgentState::profileHeadersRequested))
+ return;
+ if (m_profiles.isEmpty())
+ m_frontend->resetProfiles();
+}
+
+void InspectorProfilerAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->profiler();
+}
+
+void InspectorProfilerAgent::clearFrontend()
+{
+ m_frontend = 0;
+ stop();
+ ErrorString error;
+ disable(&error);
+}
+
+void InspectorProfilerAgent::restore()
+{
+ // Need to restore enablement state here as in setFrontend m_state wasn't loaded yet.
+ restoreEnablement();
+ resetFrontendProfiles();
+ if (m_state->getBoolean(ProfilerAgentState::userInitiatedProfiling))
+ start();
+}
+
+void InspectorProfilerAgent::restoreEnablement()
+{
+ if (m_state->getBoolean(ProfilerAgentState::profilerEnabled)) {
+ ErrorString error;
+ enable(&error);
+ }
+}
+
+void InspectorProfilerAgent::start(ErrorString*)
+{
+ if (m_recordingCPUProfile)
+ return;
+ if (!enabled()) {
+ enable(true);
+ }
+ m_recordingCPUProfile = true;
+ String title = getCurrentUserInitiatedProfileName(true);
+ startProfiling(title);
+ addStartProfilingMessageToConsole(title, 0, String());
+ toggleRecordButton(true);
+ m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true);
+}
+
+void InspectorProfilerAgent::stop(ErrorString* errorString, RefPtr<TypeBuilder::Profiler::ProfileHeader>& header)
+{
+ header = stop(errorString);
+}
+
+PassRefPtr<TypeBuilder::Profiler::ProfileHeader> InspectorProfilerAgent::stop(ErrorString* errorString)
+{
+ if (!m_recordingCPUProfile)
+ return 0;
+ m_recordingCPUProfile = false;
+ String title = getCurrentUserInitiatedProfileName();
+ RefPtr<ScriptProfile> profile = stopProfiling(title);
+ RefPtr<TypeBuilder::Profiler::ProfileHeader> profileHeader;
+ if (profile) {
+ addProfile(profile, 0, String());
+ profileHeader = createProfileHeader(*profile);
+ } else if (errorString)
+ *errorString = "Profile wasn't found";
+ toggleRecordButton(false);
+ m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false);
+ return profileHeader;
+}
+
+void InspectorProfilerAgent::toggleRecordButton(bool isProfiling)
+{
+ if (m_frontend)
+ m_frontend->setRecordingProfile(isProfiling);
+}
+
+void InspectorProfilerAgent::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorProfilerAgent);
+ InspectorBaseAgent<InspectorProfilerAgent>::reportMemoryUsage(memoryObjectInfo);
+ info.addMember(m_consoleAgent, "consoleAgent");
+ info.addMember(m_injectedScriptManager, "injectedScriptManager");
+ info.addWeakPointer(m_frontend);
+ info.addMember(m_profiles, "profiles");
+ info.addMember(m_profileNameIdleTimeMap, "profileNameIdleTimeMap");
+}
+
+void InspectorProfilerAgent::willProcessTask()
+{
+ if (!m_profileNameIdleTimeMap || !m_profileNameIdleTimeMap->size())
+ return;
+ if (!m_previousTaskEndTime)
+ return;
+
+ double idleTime = WTF::monotonicallyIncreasingTime() - m_previousTaskEndTime;
+ m_previousTaskEndTime = 0.0;
+ ProfileNameIdleTimeMap::iterator end = m_profileNameIdleTimeMap->end();
+ for (ProfileNameIdleTimeMap::iterator it = m_profileNameIdleTimeMap->begin(); it != end; ++it)
+ it->value += idleTime;
+}
+
+void InspectorProfilerAgent::didProcessTask()
+{
+ if (!m_profileNameIdleTimeMap || !m_profileNameIdleTimeMap->size())
+ return;
+ m_previousTaskEndTime = WTF::monotonicallyIncreasingTime();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorProfilerAgent.h b/Source/core/inspector/InspectorProfilerAgent.h
new file mode 100644
index 0000000..aaa2e54
--- /dev/null
+++ b/Source/core/inspector/InspectorProfilerAgent.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorProfilerAgent_h
+#define InspectorProfilerAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InjectedScriptManager;
+class InspectorArray;
+class InspectorConsoleAgent;
+class InspectorFrontend;
+class InspectorObject;
+class InspectorState;
+class InstrumentingAgents;
+class Page;
+class ScriptProfile;
+class WorkerContext;
+
+typedef String ErrorString;
+
+class InspectorProfilerAgent : public InspectorBaseAgent<InspectorProfilerAgent>, public InspectorBackendDispatcher::ProfilerCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorProfilerAgent); WTF_MAKE_FAST_ALLOCATED;
+public:
+ static PassOwnPtr<InspectorProfilerAgent> create(InstrumentingAgents*, InspectorConsoleAgent*, Page*, InspectorCompositeState*, InjectedScriptManager*);
+ static PassOwnPtr<InspectorProfilerAgent> create(InstrumentingAgents*, InspectorConsoleAgent*, WorkerContext*, InspectorCompositeState*, InjectedScriptManager*);
+ virtual ~InspectorProfilerAgent();
+
+ void addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL);
+ void addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL);
+ void addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL);
+ virtual void clearProfiles(ErrorString*);
+
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void start(ErrorString* = 0);
+ virtual void stop(ErrorString*, RefPtr<TypeBuilder::Profiler::ProfileHeader>& header);
+
+ void disable();
+ void enable(bool skipRecompile);
+ bool enabled() { return m_enabled; }
+ String getCurrentUserInitiatedProfileName(bool incrementProfileNumber = false);
+ virtual void getProfileHeaders(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader> >&);
+ virtual void getCPUProfile(ErrorString*, int uid, RefPtr<TypeBuilder::Profiler::CPUProfile>&);
+ virtual void removeProfile(ErrorString*, const String& type, int uid);
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ void toggleRecordButton(bool isProfiling);
+
+ virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+
+ void willProcessTask();
+ void didProcessTask();
+
+protected:
+ InspectorProfilerAgent(InstrumentingAgents*, InspectorConsoleAgent*, InspectorCompositeState*, InjectedScriptManager*);
+ virtual void startProfiling(const String& title) = 0;
+ virtual PassRefPtr<ScriptProfile> stopProfiling(const String& title) = 0;
+
+private:
+ typedef HashMap<unsigned int, RefPtr<ScriptProfile> > ProfilesMap;
+
+ void resetFrontendProfiles();
+ void restoreEnablement();
+ PassRefPtr<TypeBuilder::Profiler::ProfileHeader> stop(ErrorString* = 0);
+
+ PassRefPtr<TypeBuilder::Profiler::ProfileHeader> createProfileHeader(const ScriptProfile&);
+
+ InspectorConsoleAgent* m_consoleAgent;
+ InjectedScriptManager* m_injectedScriptManager;
+ InspectorFrontend::Profiler* m_frontend;
+ bool m_enabled;
+ bool m_recordingCPUProfile;
+ int m_currentUserInitiatedProfileNumber;
+ unsigned m_nextUserInitiatedProfileNumber;
+ ProfilesMap m_profiles;
+
+ typedef HashMap<String, double> ProfileNameIdleTimeMap;
+ ProfileNameIdleTimeMap* m_profileNameIdleTimeMap;
+ double m_previousTaskEndTime;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorProfilerAgent_h)
diff --git a/Source/core/inspector/InspectorResourceAgent.cpp b/Source/core/inspector/InspectorResourceAgent.cpp
new file mode 100644
index 0000000..b80f5b3
--- /dev/null
+++ b/Source/core/inspector/InspectorResourceAgent.cpp
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorResourceAgent.h"
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptCallStackFactory.h"
+#include "core/dom/Document.h"
+#include "core/dom/ExceptionCodePlaceholder.h"
+#include "core/dom/ScriptableDocumentParser.h"
+#include "core/inspector/IdentifiersFactory.h"
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/inspector/NetworkResourcesData.h"
+#include "core/inspector/ScriptCallStack.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/loader/FrameLoader.h"
+#include "core/loader/ResourceLoader.h"
+#include "core/loader/UniqueIdentifier.h"
+#include "core/loader/cache/CachedRawResource.h"
+#include "core/loader/cache/CachedResource.h"
+#include "core/loader/cache/CachedResourceLoader.h"
+#include "core/loader/cache/MemoryCache.h"
+#include "core/page/Frame.h"
+#include "core/page/Page.h"
+#include "core/platform/KURL.h"
+#include "core/platform/network/HTTPHeaderMap.h"
+#include "core/platform/network/ResourceError.h"
+#include "core/platform/network/ResourceRequest.h"
+#include "core/platform/network/ResourceResponse.h"
+#include "core/xml/XMLHttpRequest.h"
+#include "modules/websockets/WebSocketFrame.h"
+#include "modules/websockets/WebSocketHandshakeRequest.h"
+#include "modules/websockets/WebSocketHandshakeResponse.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/HexNumber.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/MemoryInstrumentationHashMap.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+namespace ResourceAgentState {
+static const char resourceAgentEnabled[] = "resourceAgentEnabled";
+static const char extraRequestHeaders[] = "extraRequestHeaders";
+static const char cacheDisabled[] = "cacheDisabled";
+static const char userAgentOverride[] = "userAgentOverride";
+}
+
+void InspectorResourceAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->network();
+}
+
+void InspectorResourceAgent::clearFrontend()
+{
+ m_frontend = 0;
+ ErrorString error;
+ disable(&error);
+}
+
+void InspectorResourceAgent::restore()
+{
+ if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled))
+ enable();
+}
+
+static PassRefPtr<InspectorObject> buildObjectForHeaders(const HTTPHeaderMap& headers)
+{
+ RefPtr<InspectorObject> headersObject = InspectorObject::create();
+ HTTPHeaderMap::const_iterator end = headers.end();
+ for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it)
+ headersObject->setString(it->key.string(), it->value);
+ return headersObject;
+}
+
+static PassRefPtr<TypeBuilder::Network::ResourceTiming> buildObjectForTiming(const ResourceLoadTiming& timing, DocumentLoader* loader)
+{
+ return TypeBuilder::Network::ResourceTiming::create()
+ .setRequestTime(loader->timing()->monotonicTimeToPseudoWallTime(timing.convertResourceLoadTimeToMonotonicTime(0)))
+ .setProxyStart(timing.proxyStart)
+ .setProxyEnd(timing.proxyEnd)
+ .setDnsStart(timing.dnsStart)
+ .setDnsEnd(timing.dnsEnd)
+ .setConnectStart(timing.connectStart)
+ .setConnectEnd(timing.connectEnd)
+ .setSslStart(timing.sslStart)
+ .setSslEnd(timing.sslEnd)
+ .setSendStart(timing.sendStart)
+ .setSendEnd(timing.sendEnd)
+ .setReceiveHeadersEnd(timing.receiveHeadersEnd)
+ .release();
+}
+
+static PassRefPtr<TypeBuilder::Network::Request> buildObjectForResourceRequest(const ResourceRequest& request)
+{
+ RefPtr<TypeBuilder::Network::Request> requestObject = TypeBuilder::Network::Request::create()
+ .setUrl(request.url().string())
+ .setMethod(request.httpMethod())
+ .setHeaders(buildObjectForHeaders(request.httpHeaderFields()));
+ if (request.httpBody() && !request.httpBody()->isEmpty())
+ requestObject->setPostData(request.httpBody()->flattenToString());
+ return requestObject;
+}
+
+static PassRefPtr<TypeBuilder::Network::Response> buildObjectForResourceResponse(const ResourceResponse& response, DocumentLoader* loader)
+{
+ if (response.isNull())
+ return 0;
+
+
+ double status;
+ String statusText;
+ if (response.resourceLoadInfo() && response.resourceLoadInfo()->httpStatusCode) {
+ status = response.resourceLoadInfo()->httpStatusCode;
+ statusText = response.resourceLoadInfo()->httpStatusText;
+ } else {
+ status = response.httpStatusCode();
+ statusText = response.httpStatusText();
+ }
+ RefPtr<InspectorObject> headers;
+ if (response.resourceLoadInfo())
+ headers = buildObjectForHeaders(response.resourceLoadInfo()->responseHeaders);
+ else
+ headers = buildObjectForHeaders(response.httpHeaderFields());
+
+ RefPtr<TypeBuilder::Network::Response> responseObject = TypeBuilder::Network::Response::create()
+ .setUrl(response.url().string())
+ .setStatus(status)
+ .setStatusText(statusText)
+ .setHeaders(headers)
+ .setMimeType(response.mimeType())
+ .setConnectionReused(response.connectionReused())
+ .setConnectionId(response.connectionID());
+
+ responseObject->setFromDiskCache(response.wasCached());
+ if (response.resourceLoadTiming())
+ responseObject->setTiming(buildObjectForTiming(*response.resourceLoadTiming(), loader));
+
+ if (response.resourceLoadInfo()) {
+ if (!response.resourceLoadInfo()->responseHeadersText.isEmpty())
+ responseObject->setHeadersText(response.resourceLoadInfo()->responseHeadersText);
+
+ responseObject->setRequestHeaders(buildObjectForHeaders(response.resourceLoadInfo()->requestHeaders));
+ if (!response.resourceLoadInfo()->requestHeadersText.isEmpty())
+ responseObject->setRequestHeadersText(response.resourceLoadInfo()->requestHeadersText);
+ }
+
+ return responseObject;
+}
+
+static PassRefPtr<TypeBuilder::Network::CachedResource> buildObjectForCachedResource(const CachedResource& cachedResource, DocumentLoader* loader)
+{
+ RefPtr<TypeBuilder::Network::CachedResource> resourceObject = TypeBuilder::Network::CachedResource::create()
+ .setUrl(cachedResource.url())
+ .setType(InspectorPageAgent::cachedResourceTypeJson(cachedResource))
+ .setBodySize(cachedResource.encodedSize());
+ RefPtr<TypeBuilder::Network::Response> resourceResponse = buildObjectForResourceResponse(cachedResource.response(), loader);
+ if (resourceResponse)
+ resourceObject->setResponse(resourceResponse);
+ return resourceObject;
+}
+
+InspectorResourceAgent::~InspectorResourceAgent()
+{
+ if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled)) {
+ ErrorString error;
+ disable(&error);
+ }
+ ASSERT(!m_instrumentingAgents->inspectorResourceAgent());
+}
+
+void InspectorResourceAgent::willSendResourceRequest(unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse)
+{
+ String requestId = IdentifiersFactory::requestId(identifier);
+ m_resourcesData->resourceCreated(requestId, m_pageAgent->loaderId(loader));
+
+ RefPtr<InspectorObject> headers = m_state->getObject(ResourceAgentState::extraRequestHeaders);
+
+ if (headers) {
+ InspectorObject::const_iterator end = headers->end();
+ for (InspectorObject::const_iterator it = headers->begin(); it != end; ++it) {
+ String value;
+ if (it->value->asString(&value))
+ request.setHTTPHeaderField(it->key, value);
+ }
+ }
+
+ request.setReportLoadTiming(true);
+ request.setReportRawHeaders(true);
+
+ if (m_state->getBoolean(ResourceAgentState::cacheDisabled)) {
+ request.setHTTPHeaderField("Pragma", "no-cache");
+ request.setCachePolicy(ReloadIgnoringCacheData);
+ request.setHTTPHeaderField("Cache-Control", "no-cache");
+ }
+
+ RefPtr<TypeBuilder::Network::Initiator> initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : 0);
+ m_frontend->requestWillBeSent(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), loader->url().string(), buildObjectForResourceRequest(request), currentTime(), initiatorObject, buildObjectForResourceResponse(redirectResponse, loader));
+}
+
+void InspectorResourceAgent::markResourceAsCached(unsigned long identifier)
+{
+ m_frontend->requestServedFromCache(IdentifiersFactory::requestId(identifier));
+}
+
+void InspectorResourceAgent::didReceiveResourceResponse(unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
+{
+ if (!loader)
+ return;
+
+ String requestId = IdentifiersFactory::requestId(identifier);
+ RefPtr<TypeBuilder::Network::Response> resourceResponse = buildObjectForResourceResponse(response, loader);
+
+ bool isNotModified = response.httpStatusCode() == 304;
+
+ CachedResource* cachedResource = 0;
+ if (resourceLoader && !isNotModified)
+ cachedResource = resourceLoader->cachedResource();
+ if (!cachedResource)
+ cachedResource = InspectorPageAgent::cachedResource(loader->frame(), response.url());
+
+ if (cachedResource) {
+ // Use mime type from cached resource in case the one in response is empty.
+ if (resourceResponse && response.mimeType().isEmpty())
+ resourceResponse->setString(TypeBuilder::Network::Response::MimeType, cachedResource->response().mimeType());
+ m_resourcesData->addCachedResource(requestId, cachedResource);
+ }
+
+ InspectorPageAgent::ResourceType type = cachedResource ? InspectorPageAgent::cachedResourceType(*cachedResource) : InspectorPageAgent::OtherResource;
+ if (m_loadingXHRSynchronously || m_resourcesData->resourceType(requestId) == InspectorPageAgent::XHRResource)
+ type = InspectorPageAgent::XHRResource;
+ else if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::ScriptResource)
+ type = InspectorPageAgent::ScriptResource;
+ else if (equalIgnoringFragmentIdentifier(response.url(), loader->url()) && !loader->isCommitted())
+ type = InspectorPageAgent::DocumentResource;
+
+ m_resourcesData->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), response);
+ m_resourcesData->setResourceType(requestId, type);
+ m_frontend->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), currentTime(), InspectorPageAgent::resourceTypeJson(type), resourceResponse);
+ // If we revalidated the resource and got Not modified, send content length following didReceiveResponse
+ // as there will be no calls to didReceiveData from the network stack.
+ if (isNotModified && cachedResource && cachedResource->encodedSize())
+ didReceiveData(identifier, 0, cachedResource->encodedSize(), 0);
+}
+
+static bool isErrorStatusCode(int statusCode)
+{
+ return statusCode >= 400;
+}
+
+void InspectorResourceAgent::didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
+{
+ String requestId = IdentifiersFactory::requestId(identifier);
+
+ if (data) {
+ NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
+ if (resourceData && !m_loadingXHRSynchronously && (!resourceData->cachedResource() || resourceData->cachedResource()->dataBufferingPolicy() == DoNotBufferData || isErrorStatusCode(resourceData->httpStatusCode())))
+ m_resourcesData->maybeAddResourceData(requestId, data, dataLength);
+ }
+
+ m_frontend->dataReceived(requestId, currentTime(), dataLength, encodedDataLength);
+}
+
+void InspectorResourceAgent::didFinishLoading(unsigned long identifier, DocumentLoader* loader, double finishTime)
+{
+ String requestId = IdentifiersFactory::requestId(identifier);
+ if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource) {
+ RefPtr<SharedBuffer> buffer = loader->frameLoader()->documentLoader()->mainResourceData();
+ m_resourcesData->addResourceSharedBuffer(requestId, buffer, loader->frame()->document()->inputEncoding());
+ }
+
+ m_resourcesData->maybeDecodeDataToContent(requestId);
+
+ if (!finishTime)
+ finishTime = currentTime();
+
+ m_frontend->loadingFinished(requestId, finishTime);
+}
+
+void InspectorResourceAgent::didFailLoading(unsigned long identifier, DocumentLoader* loader, const ResourceError& error)
+{
+ String requestId = IdentifiersFactory::requestId(identifier);
+
+ if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource) {
+ Frame* frame = loader ? loader->frame() : 0;
+ if (frame && frame->loader()->documentLoader() && frame->document()) {
+ RefPtr<SharedBuffer> buffer = frame->loader()->documentLoader()->mainResourceData();
+ m_resourcesData->addResourceSharedBuffer(requestId, buffer, frame->document()->inputEncoding());
+ }
+ }
+
+ bool canceled = error.isCancellation();
+ m_frontend->loadingFailed(requestId, currentTime(), error.localizedDescription(), canceled ? &canceled : 0);
+}
+
+void InspectorResourceAgent::didLoadResourceFromMemoryCache(DocumentLoader* loader, CachedResource* resource)
+{
+ String loaderId = m_pageAgent->loaderId(loader);
+ String frameId = m_pageAgent->frameId(loader->frame());
+ unsigned long identifier = createUniqueIdentifier();
+ String requestId = IdentifiersFactory::requestId(identifier);
+ m_resourcesData->resourceCreated(requestId, loaderId);
+ m_resourcesData->addCachedResource(requestId, resource);
+ if (resource->type() == CachedResource::RawResource) {
+ CachedRawResource* rawResource = static_cast<CachedRawResource*>(resource);
+ String rawRequestId = IdentifiersFactory::requestId(rawResource->identifier());
+ m_resourcesData->reuseXHRReplayData(requestId, rawRequestId);
+ }
+
+ RefPtr<TypeBuilder::Network::Initiator> initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : 0);
+
+ m_frontend->requestServedFromMemoryCache(requestId, frameId, loaderId, loader->url().string(), currentTime(), initiatorObject, buildObjectForCachedResource(*resource, loader));
+}
+
+void InspectorResourceAgent::scriptImported(unsigned long identifier, const String& sourceString)
+{
+ m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
+}
+
+void InspectorResourceAgent::didReceiveScriptResponse(unsigned long identifier)
+{
+ m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::ScriptResource);
+}
+
+void InspectorResourceAgent::documentThreadableLoaderStartedLoadingForClient(unsigned long identifier, ThreadableLoaderClient* client)
+{
+ if (!client)
+ return;
+
+ PendingXHRReplayDataMap::iterator it = m_pendingXHRReplayData.find(client);
+ if (it == m_pendingXHRReplayData.end())
+ return;
+
+ XHRReplayData* xhrReplayData = it->value.get();
+ String requestId = IdentifiersFactory::requestId(identifier);
+ m_resourcesData->setXHRReplayData(requestId, xhrReplayData);
+}
+
+void InspectorResourceAgent::willLoadXHR(ThreadableLoaderClient* client, const String& method, const KURL& url, bool async, PassRefPtr<FormData> formData, const HTTPHeaderMap& headers, bool includeCredentials)
+{
+ RefPtr<XHRReplayData> xhrReplayData = XHRReplayData::create(method, url, async, formData, includeCredentials);
+ HTTPHeaderMap::const_iterator end = headers.end();
+ for (HTTPHeaderMap::const_iterator it = headers.begin(); it!= end; ++it)
+ xhrReplayData->addHeader(it->key, it->value);
+ m_pendingXHRReplayData.set(client, xhrReplayData);
+}
+
+void InspectorResourceAgent::didFailXHRLoading(ThreadableLoaderClient* client)
+{
+ m_pendingXHRReplayData.remove(client);
+}
+
+void InspectorResourceAgent::didFinishXHRLoading(ThreadableLoaderClient* client, unsigned long identifier, const String& sourceString, const String&, const String&, unsigned)
+{
+ // For Asynchronous XHRs, the inspector can grab the data directly off of the CachedResource. For sync XHRs, we need to
+ // provide the data here, since no CachedResource was involved.
+ if (m_loadingXHRSynchronously)
+ m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
+ m_pendingXHRReplayData.remove(client);
+}
+
+void InspectorResourceAgent::didReceiveXHRResponse(unsigned long identifier)
+{
+ m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::XHRResource);
+}
+
+void InspectorResourceAgent::willLoadXHRSynchronously()
+{
+ m_loadingXHRSynchronously = true;
+}
+
+void InspectorResourceAgent::didLoadXHRSynchronously()
+{
+ m_loadingXHRSynchronously = false;
+}
+
+void InspectorResourceAgent::willDestroyCachedResource(CachedResource* cachedResource)
+{
+ Vector<String> requestIds = m_resourcesData->removeCachedResource(cachedResource);
+ if (!requestIds.size())
+ return;
+
+ String content;
+ bool base64Encoded;
+ if (!InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded))
+ return;
+ Vector<String>::iterator end = requestIds.end();
+ for (Vector<String>::iterator it = requestIds.begin(); it != end; ++it)
+ m_resourcesData->setResourceContent(*it, content, base64Encoded);
+}
+
+void InspectorResourceAgent::applyUserAgentOverride(String* userAgent)
+{
+ String userAgentOverride = m_state->getString(ResourceAgentState::userAgentOverride);
+ if (!userAgentOverride.isEmpty())
+ *userAgent = userAgentOverride;
+}
+
+void InspectorResourceAgent::willRecalculateStyle(Document*)
+{
+ m_isRecalculatingStyle = true;
+}
+
+void InspectorResourceAgent::didRecalculateStyle()
+{
+ m_isRecalculatingStyle = false;
+ m_styleRecalculationInitiator = nullptr;
+}
+
+void InspectorResourceAgent::didScheduleStyleRecalculation(Document* document)
+{
+ if (!m_styleRecalculationInitiator)
+ m_styleRecalculationInitiator = buildInitiatorObject(document);
+}
+
+PassRefPtr<TypeBuilder::Network::Initiator> InspectorResourceAgent::buildInitiatorObject(Document* document)
+{
+ RefPtr<ScriptCallStack> stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
+ if (stackTrace && stackTrace->size() > 0) {
+ RefPtr<TypeBuilder::Network::Initiator> initiatorObject = TypeBuilder::Network::Initiator::create()
+ .setType(TypeBuilder::Network::Initiator::Type::Script);
+ initiatorObject->setStackTrace(stackTrace->buildInspectorArray());
+ return initiatorObject;
+ }
+
+ if (document && document->scriptableDocumentParser()) {
+ RefPtr<TypeBuilder::Network::Initiator> initiatorObject = TypeBuilder::Network::Initiator::create()
+ .setType(TypeBuilder::Network::Initiator::Type::Parser);
+ initiatorObject->setUrl(document->url().string());
+ initiatorObject->setLineNumber(document->scriptableDocumentParser()->lineNumber().oneBasedInt());
+ return initiatorObject;
+ }
+
+ if (m_isRecalculatingStyle && m_styleRecalculationInitiator)
+ return m_styleRecalculationInitiator;
+
+ return TypeBuilder::Network::Initiator::create()
+ .setType(TypeBuilder::Network::Initiator::Type::Other)
+ .release();
+}
+
+void InspectorResourceAgent::didCreateWebSocket(Document*, unsigned long identifier, const KURL& requestURL, const String&)
+{
+ m_frontend->webSocketCreated(IdentifiersFactory::requestId(identifier), requestURL.string());
+}
+
+void InspectorResourceAgent::willSendWebSocketHandshakeRequest(Document*, unsigned long identifier, const WebSocketHandshakeRequest& request)
+{
+ RefPtr<TypeBuilder::Network::WebSocketRequest> requestObject = TypeBuilder::Network::WebSocketRequest::create()
+ .setHeaders(buildObjectForHeaders(request.headerFields()));
+ m_frontend->webSocketWillSendHandshakeRequest(IdentifiersFactory::requestId(identifier), currentTime(), requestObject);
+}
+
+void InspectorResourceAgent::didReceiveWebSocketHandshakeResponse(Document*, unsigned long identifier, const WebSocketHandshakeResponse& response)
+{
+ RefPtr<TypeBuilder::Network::WebSocketResponse> responseObject = TypeBuilder::Network::WebSocketResponse::create()
+ .setStatus(response.statusCode())
+ .setStatusText(response.statusText())
+ .setHeaders(buildObjectForHeaders(response.headerFields()));
+ m_frontend->webSocketHandshakeResponseReceived(IdentifiersFactory::requestId(identifier), currentTime(), responseObject);
+}
+
+void InspectorResourceAgent::didCloseWebSocket(Document*, unsigned long identifier)
+{
+ m_frontend->webSocketClosed(IdentifiersFactory::requestId(identifier), currentTime());
+}
+
+void InspectorResourceAgent::didReceiveWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
+{
+ RefPtr<TypeBuilder::Network::WebSocketFrame> frameObject = TypeBuilder::Network::WebSocketFrame::create()
+ .setOpcode(frame.opCode)
+ .setMask(frame.masked)
+ .setPayloadData(String(frame.payload, frame.payloadLength));
+ m_frontend->webSocketFrameReceived(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
+}
+
+void InspectorResourceAgent::didSendWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
+{
+ RefPtr<TypeBuilder::Network::WebSocketFrame> frameObject = TypeBuilder::Network::WebSocketFrame::create()
+ .setOpcode(frame.opCode)
+ .setMask(frame.masked)
+ .setPayloadData(String(frame.payload, frame.payloadLength));
+ m_frontend->webSocketFrameSent(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
+}
+
+void InspectorResourceAgent::didReceiveWebSocketFrameError(unsigned long identifier, const String& errorMessage)
+{
+ m_frontend->webSocketFrameError(IdentifiersFactory::requestId(identifier), currentTime(), errorMessage);
+}
+
+// called from Internals for layout test purposes.
+void InspectorResourceAgent::setResourcesDataSizeLimitsFromInternals(int maximumResourcesContentSize, int maximumSingleResourceContentSize)
+{
+ m_resourcesData->setResourcesDataSizeLimits(maximumResourcesContentSize, maximumSingleResourceContentSize);
+}
+
+void InspectorResourceAgent::enable(ErrorString*)
+{
+ enable();
+}
+
+void InspectorResourceAgent::enable()
+{
+ if (!m_frontend)
+ return;
+ m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, true);
+ m_instrumentingAgents->setInspectorResourceAgent(this);
+}
+
+void InspectorResourceAgent::disable(ErrorString*)
+{
+ m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, false);
+ m_state->setString(ResourceAgentState::userAgentOverride, "");
+ m_instrumentingAgents->setInspectorResourceAgent(0);
+ m_resourcesData->clear();
+}
+
+void InspectorResourceAgent::setUserAgentOverride(ErrorString*, const String& userAgent)
+{
+ m_state->setString(ResourceAgentState::userAgentOverride, userAgent);
+}
+
+void InspectorResourceAgent::setExtraHTTPHeaders(ErrorString*, const RefPtr<InspectorObject>& headers)
+{
+ m_state->setObject(ResourceAgentState::extraRequestHeaders, headers);
+}
+
+void InspectorResourceAgent::getResponseBody(ErrorString* errorString, const String& requestId, String* content, bool* base64Encoded)
+{
+ NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
+ if (!resourceData) {
+ *errorString = "No resource with given identifier found";
+ return;
+ }
+
+ if (resourceData->hasContent()) {
+ *base64Encoded = resourceData->base64Encoded();
+ *content = resourceData->content();
+ return;
+ }
+
+ if (resourceData->isContentEvicted()) {
+ *errorString = "Request content was evicted from inspector cache";
+ return;
+ }
+
+ if (resourceData->buffer() && !resourceData->textEncodingName().isNull()) {
+ *base64Encoded = false;
+ if (InspectorPageAgent::sharedBufferContent(resourceData->buffer(), resourceData->textEncodingName(), *base64Encoded, content))
+ return;
+ }
+
+ if (resourceData->cachedResource()) {
+ if (InspectorPageAgent::cachedResourceContent(resourceData->cachedResource(), content, base64Encoded))
+ return;
+ }
+
+ *errorString = "No data found for resource with given identifier";
+}
+
+void InspectorResourceAgent::replayXHR(ErrorString*, const String& requestId)
+{
+ RefPtr<XMLHttpRequest> xhr = XMLHttpRequest::create(m_pageAgent->mainFrame()->document());
+ String actualRequestId = requestId;
+
+ XHRReplayData* xhrReplayData = m_resourcesData->xhrReplayData(requestId);
+ if (!xhrReplayData)
+ return;
+
+ CachedResource* cachedResource = memoryCache()->resourceForURL(xhrReplayData->url());
+ if (cachedResource)
+ memoryCache()->remove(cachedResource);
+
+ xhr->open(xhrReplayData->method(), xhrReplayData->url(), xhrReplayData->async(), IGNORE_EXCEPTION);
+ HTTPHeaderMap::const_iterator end = xhrReplayData->headers().end();
+ for (HTTPHeaderMap::const_iterator it = xhrReplayData->headers().begin(); it!= end; ++it)
+ xhr->setRequestHeader(it->key, it->value, IGNORE_EXCEPTION);
+ xhr->sendFromInspector(xhrReplayData->formData(), IGNORE_EXCEPTION);
+}
+
+void InspectorResourceAgent::canClearBrowserCache(ErrorString*, bool* result)
+{
+ *result = true;
+}
+
+void InspectorResourceAgent::clearBrowserCache(ErrorString*)
+{
+ m_client->clearBrowserCache();
+}
+
+void InspectorResourceAgent::canClearBrowserCookies(ErrorString*, bool* result)
+{
+ *result = true;
+}
+
+void InspectorResourceAgent::clearBrowserCookies(ErrorString*)
+{
+ m_client->clearBrowserCookies();
+}
+
+void InspectorResourceAgent::setCacheDisabled(ErrorString*, bool cacheDisabled)
+{
+ m_state->setBoolean(ResourceAgentState::cacheDisabled, cacheDisabled);
+ if (cacheDisabled)
+ memoryCache()->evictResources();
+}
+
+void InspectorResourceAgent::mainFrameNavigated(DocumentLoader* loader)
+{
+ if (m_state->getBoolean(ResourceAgentState::cacheDisabled))
+ memoryCache()->evictResources();
+
+ m_resourcesData->clear(m_pageAgent->loaderId(loader));
+}
+
+void InspectorResourceAgent::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorResourceAgent);
+ InspectorBaseAgent<InspectorResourceAgent>::reportMemoryUsage(memoryObjectInfo);
+ info.addWeakPointer(m_pageAgent);
+ info.addWeakPointer(m_client);
+ info.addWeakPointer(m_frontend);
+ info.addMember(m_userAgentOverride, "userAgentOverride");
+ info.addMember(m_resourcesData, "resourcesData");
+ info.addMember(m_pendingXHRReplayData, "pendingXHRReplayData");
+ info.addMember(m_styleRecalculationInitiator, "styleRecalculationInitiator");
+}
+
+InspectorResourceAgent::InspectorResourceAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorClient* client, InspectorCompositeState* state)
+ : InspectorBaseAgent<InspectorResourceAgent>("Network", instrumentingAgents, state)
+ , m_pageAgent(pageAgent)
+ , m_client(client)
+ , m_frontend(0)
+ , m_resourcesData(adoptPtr(new NetworkResourcesData()))
+ , m_loadingXHRSynchronously(false)
+ , m_isRecalculatingStyle(false)
+{
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorResourceAgent.h b/Source/core/inspector/InspectorResourceAgent.h
new file mode 100644
index 0000000..cece633
--- /dev/null
+++ b/Source/core/inspector/InspectorResourceAgent.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorResourceAgent_h
+#define InspectorResourceAgent_h
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorBaseAgent.h"
+
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+
+namespace WTF {
+class String;
+}
+
+namespace WebCore {
+
+class CachedResource;
+class Document;
+class DocumentLoader;
+class FormData;
+class Frame;
+class HTTPHeaderMap;
+class InspectorArray;
+class InspectorClient;
+class InspectorFrontend;
+class InspectorObject;
+class InspectorPageAgent;
+class InspectorState;
+class InstrumentingAgents;
+class KURL;
+class NetworkResourcesData;
+class Page;
+class ResourceError;
+class ResourceLoader;
+class ResourceRequest;
+class ResourceResponse;
+class SharedBuffer;
+class ThreadableLoaderClient;
+class XHRReplayData;
+class XMLHttpRequest;
+
+struct WebSocketFrame;
+class WebSocketHandshakeRequest;
+class WebSocketHandshakeResponse;
+
+typedef String ErrorString;
+
+class InspectorResourceAgent : public InspectorBaseAgent<InspectorResourceAgent>, public InspectorBackendDispatcher::NetworkCommandHandler {
+public:
+ static PassOwnPtr<InspectorResourceAgent> create(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorClient* client, InspectorCompositeState* state)
+ {
+ return adoptPtr(new InspectorResourceAgent(instrumentingAgents, pageAgent, client, state));
+ }
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ static PassRefPtr<InspectorResourceAgent> restore(Page*, InspectorCompositeState*, InspectorFrontend*);
+
+ ~InspectorResourceAgent();
+
+ void willSendResourceRequest(unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse);
+ void markResourceAsCached(unsigned long identifier);
+ void didReceiveResourceResponse(unsigned long identifier, DocumentLoader* laoder, const ResourceResponse&, ResourceLoader*);
+ void didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
+ void didFinishLoading(unsigned long identifier, DocumentLoader*, double finishTime);
+ void didFailLoading(unsigned long identifier, DocumentLoader*, const ResourceError&);
+ void didLoadResourceFromMemoryCache(DocumentLoader*, CachedResource*);
+ void mainFrameNavigated(DocumentLoader*);
+ void scriptImported(unsigned long identifier, const String& sourceString);
+ void didReceiveScriptResponse(unsigned long identifier);
+
+ void documentThreadableLoaderStartedLoadingForClient(unsigned long identifier, ThreadableLoaderClient*);
+ void willLoadXHR(ThreadableLoaderClient*, const String& method, const KURL&, bool async, PassRefPtr<FormData> body, const HTTPHeaderMap& headers, bool includeCrendentials);
+ void didFailXHRLoading(ThreadableLoaderClient*);
+ void didFinishXHRLoading(ThreadableLoaderClient*, unsigned long identifier, const String& sourceString, const String&, const String&, unsigned);
+ void didReceiveXHRResponse(unsigned long identifier);
+ void willLoadXHRSynchronously();
+ void didLoadXHRSynchronously();
+
+ void willDestroyCachedResource(CachedResource*);
+
+ void applyUserAgentOverride(String* userAgent);
+
+ // FIXME: InspectorResourceAgent should now be aware of style recalculation.
+ void willRecalculateStyle(Document*);
+ void didRecalculateStyle();
+ void didScheduleStyleRecalculation(Document*);
+
+ PassRefPtr<TypeBuilder::Network::Initiator> buildInitiatorObject(Document*);
+
+ void didCreateWebSocket(Document*, unsigned long identifier, const KURL& requestURL, const String&);
+ void willSendWebSocketHandshakeRequest(Document*, unsigned long identifier, const WebSocketHandshakeRequest&);
+ void didReceiveWebSocketHandshakeResponse(Document*, unsigned long identifier, const WebSocketHandshakeResponse&);
+ void didCloseWebSocket(Document*, unsigned long identifier);
+ void didReceiveWebSocketFrame(unsigned long identifier, const WebSocketFrame&);
+ void didSendWebSocketFrame(unsigned long identifier, const WebSocketFrame&);
+ void didReceiveWebSocketFrameError(unsigned long identifier, const String&);
+
+ // called from Internals for layout test purposes.
+ void setResourcesDataSizeLimitsFromInternals(int maximumResourcesContentSize, int maximumSingleResourceContentSize);
+
+ // Called from frontend
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void setUserAgentOverride(ErrorString*, const String& userAgent);
+ virtual void setExtraHTTPHeaders(ErrorString*, const RefPtr<InspectorObject>&);
+ virtual void getResponseBody(ErrorString*, const String& requestId, String* content, bool* base64Encoded);
+
+ virtual void replayXHR(ErrorString*, const String& requestId);
+
+ virtual void canClearBrowserCache(ErrorString*, bool*);
+ virtual void clearBrowserCache(ErrorString*);
+ virtual void canClearBrowserCookies(ErrorString*, bool*);
+ virtual void clearBrowserCookies(ErrorString*);
+ virtual void setCacheDisabled(ErrorString*, bool cacheDisabled);
+
+ virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+
+private:
+ InspectorResourceAgent(InstrumentingAgents*, InspectorPageAgent*, InspectorClient*, InspectorCompositeState*);
+
+ void enable();
+
+ InspectorPageAgent* m_pageAgent;
+ InspectorClient* m_client;
+ InspectorFrontend::Network* m_frontend;
+ String m_userAgentOverride;
+ OwnPtr<NetworkResourcesData> m_resourcesData;
+ bool m_loadingXHRSynchronously;
+
+ typedef HashMap<ThreadableLoaderClient*, RefPtr<XHRReplayData> > PendingXHRReplayDataMap;
+ PendingXHRReplayDataMap m_pendingXHRReplayData;
+ // FIXME: InspectorResourceAgent should now be aware of style recalculation.
+ RefPtr<TypeBuilder::Network::Initiator> m_styleRecalculationInitiator;
+ bool m_isRecalculatingStyle;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorResourceAgent_h)
diff --git a/Source/core/inspector/InspectorRuntimeAgent.cpp b/Source/core/inspector/InspectorRuntimeAgent.cpp
new file mode 100644
index 0000000..e119823
--- /dev/null
+++ b/Source/core/inspector/InspectorRuntimeAgent.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorRuntimeAgent.h"
+
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorValues.h"
+#include <wtf/PassRefPtr.h>
+
+
+#include "bindings/v8/ScriptDebugServer.h"
+
+namespace WebCore {
+
+static bool asBool(const bool* const b)
+{
+ return b ? *b : false;
+}
+
+InspectorRuntimeAgent::InspectorRuntimeAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager)
+ : InspectorBaseAgent<InspectorRuntimeAgent>("Runtime", instrumentingAgents, state)
+ , m_enabled(false)
+ , m_injectedScriptManager(injectedScriptManager)
+ , m_scriptDebugServer(0)
+{
+}
+
+InspectorRuntimeAgent::~InspectorRuntimeAgent()
+{
+}
+
+static ScriptDebugServer::PauseOnExceptionsState setPauseOnExceptionsState(ScriptDebugServer* scriptDebugServer, ScriptDebugServer::PauseOnExceptionsState newState)
+{
+ ASSERT(scriptDebugServer);
+ ScriptDebugServer::PauseOnExceptionsState presentState = scriptDebugServer->pauseOnExceptionsState();
+ if (presentState != newState)
+ scriptDebugServer->setPauseOnExceptionsState(newState);
+ return presentState;
+}
+
+void InspectorRuntimeAgent::evaluate(ErrorString* errorString, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* const returnByValue, const bool* generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown)
+{
+ InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId);
+ if (injectedScript.hasNoValue())
+ return;
+ ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = ScriptDebugServer::DontPauseOnExceptions;
+ if (asBool(doNotPauseOnExceptionsAndMuteConsole))
+ previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
+ if (asBool(doNotPauseOnExceptionsAndMuteConsole))
+ muteConsole();
+
+ injectedScript.evaluate(errorString, expression, objectGroup ? *objectGroup : "", asBool(includeCommandLineAPI), asBool(returnByValue), asBool(generatePreview), &result, wasThrown);
+
+ if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
+ unmuteConsole();
+ setPauseOnExceptionsState(m_scriptDebugServer, previousPauseOnExceptionsState);
+ }
+}
+
+void InspectorRuntimeAgent::callFunctionOn(ErrorString* errorString, const String& objectId, const String& expression, const RefPtr<InspectorArray>* const optionalArguments, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown)
+{
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected frame has gone";
+ return;
+ }
+ String arguments;
+ if (optionalArguments)
+ arguments = (*optionalArguments)->toJSONString();
+
+ ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = ScriptDebugServer::DontPauseOnExceptions;
+ if (asBool(doNotPauseOnExceptionsAndMuteConsole))
+ previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
+ if (asBool(doNotPauseOnExceptionsAndMuteConsole))
+ muteConsole();
+
+ injectedScript.callFunctionOn(errorString, objectId, expression, arguments, asBool(returnByValue), asBool(generatePreview), &result, wasThrown);
+
+ if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
+ unmuteConsole();
+ setPauseOnExceptionsState(m_scriptDebugServer, previousPauseOnExceptionsState);
+ }
+}
+
+void InspectorRuntimeAgent::getProperties(ErrorString* errorString, const String& objectId, const bool* const ownProperties, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::PropertyDescriptor> >& result, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::InternalPropertyDescriptor> >& internalProperties)
+{
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected frame has gone";
+ return;
+ }
+
+ ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
+ muteConsole();
+
+ injectedScript.getProperties(errorString, objectId, ownProperties ? *ownProperties : false, &result);
+ injectedScript.getInternalProperties(errorString, objectId, &internalProperties);
+
+ unmuteConsole();
+ setPauseOnExceptionsState(m_scriptDebugServer, previousPauseOnExceptionsState);
+}
+
+void InspectorRuntimeAgent::releaseObject(ErrorString*, const String& objectId)
+{
+ InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
+ if (!injectedScript.hasNoValue())
+ injectedScript.releaseObject(objectId);
+}
+
+void InspectorRuntimeAgent::releaseObjectGroup(ErrorString*, const String& objectGroup)
+{
+ m_injectedScriptManager->releaseObjectGroup(objectGroup);
+}
+
+void InspectorRuntimeAgent::run(ErrorString*)
+{
+}
+
+void InspectorRuntimeAgent::setScriptDebugServer(ScriptDebugServer* scriptDebugServer)
+{
+ m_scriptDebugServer = scriptDebugServer;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorRuntimeAgent.h b/Source/core/inspector/InspectorRuntimeAgent.h
new file mode 100644
index 0000000..2034795
--- /dev/null
+++ b/Source/core/inspector/InspectorRuntimeAgent.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorRuntimeAgent_h
+#define InspectorRuntimeAgent_h
+
+
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class InjectedScript;
+class InjectedScriptManager;
+class InspectorArray;
+class InspectorFrontend;
+class InspectorObject;
+class InspectorValue;
+class InstrumentingAgents;
+class ScriptDebugServer;
+class WorkerContext;
+
+typedef String ErrorString;
+
+class InspectorRuntimeAgent : public InspectorBaseAgent<InspectorRuntimeAgent>, public InspectorBackendDispatcher::RuntimeCommandHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorRuntimeAgent);
+public:
+ virtual ~InspectorRuntimeAgent();
+
+ bool enabled() { return m_enabled; }
+ // Part of the protocol.
+ virtual void enable(ErrorString*) { m_enabled = true; }
+ virtual void disable(ErrorString*) { m_enabled = false; }
+ virtual void evaluate(ErrorString*,
+ const String& expression,
+ const String* objectGroup,
+ const bool* includeCommandLineAPI,
+ const bool* doNotPauseOnExceptionsAndMuteConsole,
+ const int* executionContextId,
+ const bool* returnByValue,
+ const bool* generatePreview,
+ RefPtr<TypeBuilder::Runtime::RemoteObject>& result,
+ TypeBuilder::OptOutput<bool>* wasThrown);
+ virtual void callFunctionOn(ErrorString*,
+ const String& objectId,
+ const String& expression,
+ const RefPtr<InspectorArray>* optionalArguments,
+ const bool* doNotPauseOnExceptionsAndMuteConsole,
+ const bool* returnByValue,
+ const bool* generatePreview,
+ RefPtr<TypeBuilder::Runtime::RemoteObject>& result,
+ TypeBuilder::OptOutput<bool>* wasThrown);
+ virtual void releaseObject(ErrorString*, const String& objectId);
+ virtual void getProperties(ErrorString*, const String& objectId, const bool* ownProperties, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::PropertyDescriptor> >& result, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::InternalPropertyDescriptor> >& internalProperties);
+ virtual void releaseObjectGroup(ErrorString*, const String& objectGroup);
+ virtual void run(ErrorString*);
+
+ void setScriptDebugServer(ScriptDebugServer*);
+
+protected:
+ InspectorRuntimeAgent(InstrumentingAgents*, InspectorCompositeState*, InjectedScriptManager*);
+ virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId) = 0;
+
+ virtual void muteConsole() = 0;
+ virtual void unmuteConsole() = 0;
+
+ InjectedScriptManager* injectedScriptManager() { return m_injectedScriptManager; }
+ bool m_enabled;
+
+private:
+ InjectedScriptManager* m_injectedScriptManager;
+ ScriptDebugServer* m_scriptDebugServer;
+};
+
+} // namespace WebCore
+
+#endif // InspectorRuntimeAgent_h
diff --git a/Source/core/inspector/InspectorState.cpp b/Source/core/inspector/InspectorState.cpp
new file mode 100644
index 0000000..fc3124f
--- /dev/null
+++ b/Source/core/inspector/InspectorState.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2011 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE 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 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 "core/inspector/InspectorState.h"
+
+#include "core/inspector/InspectorStateClient.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+InspectorState::InspectorState(InspectorStateUpdateListener* listener, PassRefPtr<InspectorObject> properties)
+ : m_listener(listener)
+ , m_properties(properties)
+{
+}
+
+void InspectorState::updateCookie()
+{
+ if (m_listener)
+ m_listener->inspectorStateUpdated();
+}
+
+void InspectorState::setFromCookie(PassRefPtr<InspectorObject> properties)
+{
+ m_properties = properties;
+}
+
+void InspectorState::setValue(const String& propertyName, PassRefPtr<InspectorValue> value)
+{
+ m_properties->setValue(propertyName, value);
+ updateCookie();
+}
+
+void InspectorState::remove(const String& propertyName)
+{
+ m_properties->remove(propertyName);
+ updateCookie();
+}
+
+bool InspectorState::getBoolean(const String& propertyName)
+{
+ InspectorObject::iterator it = m_properties->find(propertyName);
+ bool value = false;
+ if (it != m_properties->end())
+ it->value->asBoolean(&value);
+ return value;
+}
+
+String InspectorState::getString(const String& propertyName)
+{
+ InspectorObject::iterator it = m_properties->find(propertyName);
+ String value;
+ if (it != m_properties->end())
+ it->value->asString(&value);
+ return value;
+}
+
+long InspectorState::getLong(const String& propertyName)
+{
+ InspectorObject::iterator it = m_properties->find(propertyName);
+ long value = 0;
+ if (it != m_properties->end())
+ it->value->asNumber(&value);
+ return value;
+}
+
+double InspectorState::getDouble(const String& propertyName)
+{
+ InspectorObject::iterator it = m_properties->find(propertyName);
+ double value = 0;
+ if (it != m_properties->end())
+ it->value->asNumber(&value);
+ return value;
+}
+
+PassRefPtr<InspectorObject> InspectorState::getObject(const String& propertyName)
+{
+ InspectorObject::iterator it = m_properties->find(propertyName);
+ if (it == m_properties->end()) {
+ m_properties->setObject(propertyName, InspectorObject::create());
+ it = m_properties->find(propertyName);
+ }
+ return it->value->asObject();
+}
+
+InspectorState* InspectorCompositeState::createAgentState(const String& agentName)
+{
+ ASSERT(m_stateObject->find(agentName) == m_stateObject->end());
+ ASSERT(m_inspectorStateMap.find(agentName) == m_inspectorStateMap.end());
+ RefPtr<InspectorObject> stateProperties = InspectorObject::create();
+ m_stateObject->setObject(agentName, stateProperties);
+ OwnPtr<InspectorState> statePtr = adoptPtr(new InspectorState(this, stateProperties));
+ InspectorState* state = statePtr.get();
+ m_inspectorStateMap.add(agentName, statePtr.release());
+ return state;
+}
+
+void InspectorCompositeState::loadFromCookie(const String& inspectorCompositeStateCookie)
+{
+ RefPtr<InspectorValue> cookie = InspectorValue::parseJSON(inspectorCompositeStateCookie);
+ if (cookie)
+ m_stateObject = cookie->asObject();
+ if (!m_stateObject)
+ m_stateObject = InspectorObject::create();
+
+ InspectorStateMap::iterator end = m_inspectorStateMap.end();
+ for (InspectorStateMap::iterator it = m_inspectorStateMap.begin(); it != end; ++it) {
+ RefPtr<InspectorObject> agentStateObject = m_stateObject->getObject(it->key);
+ if (!agentStateObject) {
+ agentStateObject = InspectorObject::create();
+ m_stateObject->setObject(it->key, agentStateObject);
+ }
+ it->value->setFromCookie(agentStateObject);
+ }
+}
+
+void InspectorCompositeState::mute()
+{
+ m_isMuted = true;
+}
+
+void InspectorCompositeState::unmute()
+{
+ m_isMuted = false;
+}
+
+void InspectorCompositeState::inspectorStateUpdated()
+{
+ if (m_client && !m_isMuted)
+ m_client->updateInspectorStateCookie(m_stateObject->toJSONString());
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorState.h b/Source/core/inspector/InspectorState.h
new file mode 100644
index 0000000..7952f2b
--- /dev/null
+++ b/Source/core/inspector/InspectorState.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorState_h
+#define InspectorState_h
+
+
+#include "core/inspector/InspectorValues.h"
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InspectorStateClient;
+
+class InspectorStateUpdateListener {
+public:
+ virtual ~InspectorStateUpdateListener() { }
+ virtual void inspectorStateUpdated() = 0;
+};
+
+class InspectorState {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ InspectorState(InspectorStateUpdateListener*, PassRefPtr<InspectorObject>);
+ virtual ~InspectorState() {}
+
+ void loadFromCookie(const String& inspectorStateCookie);
+
+ void mute();
+ void unmute();
+
+ bool getBoolean(const String& propertyName);
+ String getString(const String& propertyName);
+ long getLong(const String& propertyName);
+ double getDouble(const String& propertyName);
+ PassRefPtr<InspectorObject> getObject(const String& propertyName);
+
+ void setBoolean(const String& propertyName, bool value) { setValue(propertyName, InspectorBasicValue::create(value)); }
+ void setString(const String& propertyName, const String& value) { setValue(propertyName, InspectorString::create(value)); }
+ void setLong(const String& propertyName, long value) { setValue(propertyName, InspectorBasicValue::create((double)value)); }
+ void setDouble(const String& propertyName, double value) { setValue(propertyName, InspectorBasicValue::create(value)); }
+ void setObject(const String& propertyName, PassRefPtr<InspectorObject> value) { setValue(propertyName, value); }
+
+ void remove(const String&);
+private:
+ void updateCookie();
+ void setValue(const String& propertyName, PassRefPtr<InspectorValue>);
+
+ // Gets called from InspectorCompositeState::loadFromCookie().
+ void setFromCookie(PassRefPtr<InspectorObject>);
+
+ friend class InspectorCompositeState;
+
+ InspectorStateUpdateListener* m_listener;
+ RefPtr<InspectorObject> m_properties;
+};
+
+class InspectorCompositeState : public InspectorStateUpdateListener {
+public:
+ InspectorCompositeState(InspectorStateClient* inspectorClient)
+ : m_client(inspectorClient)
+ , m_stateObject(InspectorObject::create())
+ , m_isMuted(false)
+ {
+ }
+ virtual ~InspectorCompositeState() { }
+
+ void mute();
+ void unmute();
+
+ InspectorState* createAgentState(const String&);
+ void loadFromCookie(const String&);
+
+private:
+ typedef HashMap<String, OwnPtr<InspectorState> > InspectorStateMap;
+
+ // From InspectorStateUpdateListener.
+ virtual void inspectorStateUpdated();
+
+ InspectorStateClient* m_client;
+ RefPtr<InspectorObject> m_stateObject;
+ bool m_isMuted;
+ InspectorStateMap m_inspectorStateMap;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorState_h)
diff --git a/Source/core/inspector/InspectorStateClient.h b/Source/core/inspector/InspectorStateClient.h
new file mode 100644
index 0000000..214c707
--- /dev/null
+++ b/Source/core/inspector/InspectorStateClient.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 Google 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 COMPUTER, INC. ``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 COMPUTER, INC. OR
+ * 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 InspectorStateClient_h
+#define InspectorStateClient_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class InspectorStateClient {
+public:
+ virtual ~InspectorStateClient() { }
+
+ // Navigation can cause some WebKit implementations to change the view / page / inspector controller instance.
+ // However, there are some inspector controller states that should survive navigation (such as tracking resources
+ // or recording timeline) and worker restart. Following callbacks allow embedders to track these states.
+ virtual void updateInspectorStateCookie(const String&) { };
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorStateClient_h)
diff --git a/Source/core/inspector/InspectorStyleSheet.cpp b/Source/core/inspector/InspectorStyleSheet.cpp
new file mode 100644
index 0000000..8b82254
--- /dev/null
+++ b/Source/core/inspector/InspectorStyleSheet.cpp
@@ -0,0 +1,1821 @@
+/*
+ * Copyright (C) 2010, Google 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 "core/inspector/InspectorStyleSheet.h"
+
+#include "CSSPropertyNames.h"
+#include "HTMLNames.h"
+#include "SVGNames.h"
+#include "core/css/CSSHostRule.h"
+#include "core/css/CSSImportRule.h"
+#include "core/css/CSSMediaRule.h"
+#include "core/css/CSSParser.h"
+#include "core/css/CSSPropertySourceData.h"
+#include "core/css/CSSRule.h"
+#include "core/css/CSSRuleList.h"
+#include "core/css/CSSStyleRule.h"
+#include "core/css/CSSStyleSheet.h"
+#include "core/css/CSSSupportsRule.h"
+#include "core/css/StylePropertySet.h"
+#include "core/css/StyleResolver.h"
+#include "core/css/StyleRule.h"
+#include "core/css/StyleRuleImport.h"
+#include "core/css/StyleSheetContents.h"
+#include "core/css/StyleSheetList.h"
+#include "core/css/WebKitCSSKeyframesRule.h"
+#include "core/dom/Document.h"
+#include "core/dom/Element.h"
+#include "core/dom/Node.h"
+#include "core/html/HTMLHeadElement.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/inspector/ContentSearchUtils.h"
+#include "core/inspector/InspectorCSSAgent.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/page/ContentSecurityPolicy.h"
+#include "core/platform/text/RegularExpression.h"
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/Vector.h>
+
+using WebCore::TypeBuilder::Array;
+using WebCore::RuleSourceDataList;
+using WebCore::CSSRuleSourceData;
+
+class ParsedStyleSheet {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ParsedStyleSheet();
+
+ WebCore::CSSStyleSheet* cssStyleSheet() const { return m_parserOutput; }
+ const String& text() const { ASSERT(m_hasText); return m_text; }
+ void setText(const String& text);
+ bool hasText() const { return m_hasText; }
+ void setSourceData(PassOwnPtr<RuleSourceDataList>);
+ bool hasSourceData() const { return m_sourceData; }
+ PassRefPtr<WebCore::CSSRuleSourceData> ruleSourceDataAt(unsigned) const;
+
+private:
+
+ // StyleSheet constructed while parsing m_text.
+ WebCore::CSSStyleSheet* m_parserOutput;
+ String m_text;
+ bool m_hasText;
+ OwnPtr<RuleSourceDataList> m_sourceData;
+};
+
+ParsedStyleSheet::ParsedStyleSheet()
+ : m_parserOutput(0)
+ , m_hasText(false)
+{
+}
+
+void ParsedStyleSheet::setText(const String& text)
+{
+ m_hasText = true;
+ m_text = text;
+ setSourceData(nullptr);
+}
+
+static void flattenSourceData(RuleSourceDataList* dataList, RuleSourceDataList* target)
+{
+ for (size_t i = 0; i < dataList->size(); ++i) {
+ RefPtr<CSSRuleSourceData>& data = dataList->at(i);
+ if (data->type == CSSRuleSourceData::STYLE_RULE)
+ target->append(data);
+ else if (data->type == CSSRuleSourceData::MEDIA_RULE)
+ flattenSourceData(&data->childRules, target);
+ else if (data->type == CSSRuleSourceData::HOST_RULE)
+ flattenSourceData(&data->childRules, target);
+ else if (data->type == CSSRuleSourceData::SUPPORTS_RULE)
+ flattenSourceData(&data->childRules, target);
+ }
+}
+
+void ParsedStyleSheet::setSourceData(PassOwnPtr<RuleSourceDataList> sourceData)
+{
+ if (!sourceData) {
+ m_sourceData.clear();
+ return;
+ }
+
+ m_sourceData = adoptPtr(new RuleSourceDataList());
+
+ // FIXME: This is a temporary solution to retain the original flat sourceData structure
+ // containing only style rules, even though CSSParser now provides the full rule source data tree.
+ // Normally, we should just assign m_sourceData = sourceData;
+ flattenSourceData(sourceData.get(), m_sourceData.get());
+}
+
+PassRefPtr<WebCore::CSSRuleSourceData> ParsedStyleSheet::ruleSourceDataAt(unsigned index) const
+{
+ if (!hasSourceData() || index >= m_sourceData->size())
+ return 0;
+
+ return m_sourceData->at(index);
+}
+
+namespace WebCore {
+
+static PassOwnPtr<CSSParser> createCSSParser(Document* document)
+{
+ return adoptPtr(new CSSParser(document ? CSSParserContext(document) : strictCSSParserContext()));
+}
+
+namespace {
+
+class StyleSheetHandler : public CSSParser::SourceDataHandler {
+public:
+ StyleSheetHandler(const String& parsedText, Document* document, StyleSheetContents* styleSheetContents, RuleSourceDataList* result)
+ : m_parsedText(parsedText)
+ , m_document(document)
+ , m_styleSheetContents(styleSheetContents)
+ , m_result(result)
+ , m_propertyRangeStart(UINT_MAX)
+ , m_selectorRangeStart(UINT_MAX)
+ , m_commentRangeStart(UINT_MAX)
+ {
+ ASSERT(m_result);
+ }
+
+private:
+ virtual void startRuleHeader(CSSRuleSourceData::Type, unsigned) OVERRIDE;
+ virtual void endRuleHeader(unsigned) OVERRIDE;
+ virtual void startSelector(unsigned) OVERRIDE;
+ virtual void endSelector(unsigned) OVERRIDE;
+ virtual void startRuleBody(unsigned) OVERRIDE;
+ virtual void endRuleBody(unsigned, bool) OVERRIDE;
+ virtual void startEndUnknownRule() OVERRIDE { addNewRuleToSourceTree(CSSRuleSourceData::createUnknown()); }
+ virtual void startProperty(unsigned) OVERRIDE;
+ virtual void endProperty(bool, bool, unsigned, CSSParser::SyntaxErrorType) OVERRIDE;
+ virtual void startComment(unsigned) OVERRIDE;
+ virtual void endComment(unsigned) OVERRIDE;
+
+ void addNewRuleToSourceTree(PassRefPtr<CSSRuleSourceData>);
+ PassRefPtr<CSSRuleSourceData> popRuleData();
+ template <typename CharacterType> inline void setRuleHeaderEnd(const CharacterType*, unsigned);
+ void fixUnparsedPropertyRanges(CSSRuleSourceData*);
+
+ const String& m_parsedText;
+ Document* m_document;
+ StyleSheetContents* m_styleSheetContents;
+ RuleSourceDataList* m_result;
+ RuleSourceDataList m_currentRuleDataStack;
+ RefPtr<CSSRuleSourceData> m_currentRuleData;
+ OwnPtr<CSSParser> m_commentParser;
+ unsigned m_propertyRangeStart;
+ unsigned m_selectorRangeStart;
+ unsigned m_commentRangeStart;
+};
+
+void StyleSheetHandler::startRuleHeader(CSSRuleSourceData::Type type, unsigned offset)
+{
+ // Pop off data for a previous invalid rule.
+ if (m_currentRuleData)
+ m_currentRuleDataStack.removeLast();
+
+ RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(type);
+ data->ruleHeaderRange.start = offset;
+ m_currentRuleData = data;
+ m_currentRuleDataStack.append(data.release());
+}
+
+template <typename CharacterType>
+inline void StyleSheetHandler::setRuleHeaderEnd(const CharacterType* dataStart, unsigned listEndOffset)
+{
+ while (listEndOffset > 1) {
+ if (isHTMLSpace(*(dataStart + listEndOffset - 1)))
+ --listEndOffset;
+ else
+ break;
+ }
+
+ m_currentRuleDataStack.last()->ruleHeaderRange.end = listEndOffset;
+}
+
+void StyleSheetHandler::endRuleHeader(unsigned offset)
+{
+ ASSERT(!m_currentRuleDataStack.isEmpty());
+
+ if (m_parsedText.is8Bit())
+ setRuleHeaderEnd<LChar>(m_parsedText.characters8(), offset);
+ else
+ setRuleHeaderEnd<UChar>(m_parsedText.characters16(), offset);
+}
+
+void StyleSheetHandler::startSelector(unsigned offset)
+{
+ m_selectorRangeStart = offset;
+}
+
+void StyleSheetHandler::endSelector(unsigned offset)
+{
+ ASSERT(m_currentRuleDataStack.size());
+ m_currentRuleDataStack.last()->selectorRanges.append(SourceRange(m_selectorRangeStart, offset));
+ m_selectorRangeStart = UINT_MAX;
+}
+
+void StyleSheetHandler::startRuleBody(unsigned offset)
+{
+ m_currentRuleData.clear();
+ ASSERT(!m_currentRuleDataStack.isEmpty());
+ if (m_parsedText[offset] == '{')
+ ++offset; // Skip the rule body opening brace.
+ m_currentRuleDataStack.last()->ruleBodyRange.start = offset;
+}
+
+void StyleSheetHandler::endRuleBody(unsigned offset, bool error)
+{
+ ASSERT(!m_currentRuleDataStack.isEmpty());
+ m_currentRuleDataStack.last()->ruleBodyRange.end = offset;
+ m_propertyRangeStart = UINT_MAX;
+ RefPtr<CSSRuleSourceData> rule = popRuleData();
+ if (error)
+ return;
+
+ fixUnparsedPropertyRanges(rule.get());
+ addNewRuleToSourceTree(rule.release());
+}
+
+void StyleSheetHandler::addNewRuleToSourceTree(PassRefPtr<CSSRuleSourceData> rule)
+{
+ if (m_currentRuleDataStack.isEmpty())
+ m_result->append(rule);
+ else
+ m_currentRuleDataStack.last()->childRules.append(rule);
+}
+
+PassRefPtr<CSSRuleSourceData> StyleSheetHandler::popRuleData()
+{
+ ASSERT(!m_currentRuleDataStack.isEmpty());
+ m_currentRuleData.clear();
+ RefPtr<CSSRuleSourceData> data = m_currentRuleDataStack.last();
+ m_currentRuleDataStack.removeLast();
+ return data.release();
+}
+
+template <typename CharacterType>
+static inline void fixUnparsedProperties(const CharacterType* characters, CSSRuleSourceData* ruleData)
+{
+ Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData;
+ unsigned size = propertyData.size();
+ if (!size)
+ return;
+
+ unsigned styleStart = ruleData->ruleBodyRange.start;
+ CSSPropertySourceData* nextData = &(propertyData.at(0));
+ for (unsigned i = 0; i < size; ++i) {
+ CSSPropertySourceData* currentData = nextData;
+ nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0;
+
+ if (currentData->parsedOk)
+ continue;
+ if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';')
+ continue;
+
+ unsigned propertyEndInStyleSheet;
+ if (!nextData)
+ propertyEndInStyleSheet = ruleData->ruleBodyRange.end - 1;
+ else
+ propertyEndInStyleSheet = styleStart + nextData->range.start - 1;
+
+ while (isHTMLSpace(characters[propertyEndInStyleSheet]))
+ --propertyEndInStyleSheet;
+
+ // propertyEndInStyleSheet points at the last property text character.
+ unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character.
+ if (currentData->range.end != newPropertyEnd) {
+ currentData->range.end = newPropertyEnd;
+ unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length();
+ while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':')
+ ++valueStartInStyleSheet;
+ if (valueStartInStyleSheet < propertyEndInStyleSheet)
+ ++valueStartInStyleSheet; // Shift past the ':'.
+ while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace(characters[valueStartInStyleSheet]))
+ ++valueStartInStyleSheet;
+ // Need to exclude the trailing ';' from the property value.
+ currentData->value = String(characters + valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1));
+ }
+ }
+}
+
+void StyleSheetHandler::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData)
+{
+ if (!ruleData->styleSourceData)
+ return;
+
+ if (m_parsedText.is8Bit()) {
+ fixUnparsedProperties<LChar>(m_parsedText.characters8(), ruleData);
+ return;
+ }
+
+ fixUnparsedProperties<UChar>(m_parsedText.characters16(), ruleData);
+}
+
+void StyleSheetHandler::startProperty(unsigned offset)
+{
+ if (m_currentRuleDataStack.isEmpty() || !m_currentRuleDataStack.last()->styleSourceData)
+ return;
+ m_propertyRangeStart = offset;
+}
+
+void StyleSheetHandler::endProperty(bool isImportant, bool isParsed, unsigned offset, CSSParser::SyntaxErrorType errorType)
+{
+ if (errorType != CSSParser::NoSyntaxError)
+ m_propertyRangeStart = UINT_MAX;
+
+ if (m_propertyRangeStart == UINT_MAX || m_currentRuleDataStack.isEmpty() || !m_currentRuleDataStack.last()->styleSourceData)
+ return;
+
+ ASSERT(offset <= m_parsedText.length());
+ if (offset < m_parsedText.length() && m_parsedText[offset] == ';') // Include semicolon into the property text.
+ ++offset;
+
+ const unsigned start = m_propertyRangeStart;
+ const unsigned end = offset;
+ ASSERT(start < end);
+ String propertyString = m_parsedText.substring(start, end - start).stripWhiteSpace();
+ if (propertyString.endsWith(';'))
+ propertyString = propertyString.left(propertyString.length() - 1);
+ size_t colonIndex = propertyString.find(':');
+ ASSERT(colonIndex != notFound);
+
+ String name = propertyString.left(colonIndex).stripWhiteSpace();
+ String value = propertyString.substring(colonIndex + 1, propertyString.length()).stripWhiteSpace();
+ // The property range is relative to the declaration start offset.
+ unsigned topRuleBodyRangeStart = m_currentRuleDataStack.last()->ruleBodyRange.start;
+ m_currentRuleDataStack.last()->styleSourceData->propertyData.append(
+ CSSPropertySourceData(name, value, isImportant, false, isParsed, SourceRange(start - topRuleBodyRangeStart, end - topRuleBodyRangeStart)));
+ m_propertyRangeStart = UINT_MAX;
+}
+
+void StyleSheetHandler::startComment(unsigned offset)
+{
+ ASSERT(m_commentRangeStart == UINT_MAX);
+ m_commentRangeStart = offset;
+}
+
+void StyleSheetHandler::endComment(unsigned offset)
+{
+ ASSERT(offset <= m_parsedText.length());
+
+ unsigned startOffset = m_commentRangeStart;
+ m_commentRangeStart = UINT_MAX;
+ if (m_propertyRangeStart != UINT_MAX) {
+ ASSERT(startOffset >= m_propertyRangeStart);
+ // startProperty() is called automatically at the start of a style declaration.
+ // Check if no text has been scanned yet, otherwise the comment is inside a property.
+ if (!m_parsedText.substring(m_propertyRangeStart, startOffset).stripWhiteSpace().isEmpty())
+ return;
+ m_propertyRangeStart = UINT_MAX;
+ }
+ if (m_currentRuleDataStack.isEmpty() || !m_currentRuleDataStack.last()->ruleHeaderRange.end || !m_currentRuleDataStack.last()->styleSourceData)
+ return;
+
+ // The lexer is not inside a property AND it is scanning a declaration-aware rule body.
+ String commentText = m_parsedText.substring(startOffset, offset - startOffset);
+
+ ASSERT(commentText.startsWith("/*"));
+ commentText = commentText.substring(2);
+
+ // Require well-formed comments.
+ if (!commentText.endsWith("*/"))
+ return;
+ commentText = commentText.substring(0, commentText.length() - 2).stripWhiteSpace();
+ if (commentText.isEmpty())
+ return;
+
+ // FIXME: Use the actual rule type rather than STYLE_RULE?
+ if (!m_commentParser)
+ m_commentParser = createCSSParser(m_document);
+ RuleSourceDataList sourceData;
+
+ // FIXME: Use another subclass of CSSParser::SourceDataHandler and assert that
+ // no comments are encountered (will not need m_document and m_styleSheetContents).
+ StyleSheetHandler handler(commentText, m_document, m_styleSheetContents, &sourceData);
+ RefPtr<StylePropertySet> tempMutableStyle = StylePropertySet::create();
+ m_commentParser->parseDeclaration(tempMutableStyle.get(), commentText, &handler, m_styleSheetContents);
+ Vector<CSSPropertySourceData>& commentPropertyData = sourceData.first()->styleSourceData->propertyData;
+ if (commentPropertyData.size() != 1)
+ return;
+ CSSPropertySourceData& propertyData = commentPropertyData.at(0);
+ if (propertyData.range.length() != commentText.length())
+ return;
+
+ unsigned topRuleBodyRangeStart = m_currentRuleDataStack.last()->ruleBodyRange.start;
+ m_currentRuleDataStack.last()->styleSourceData->propertyData.append(
+ CSSPropertySourceData(propertyData.name, propertyData.value, false, true, true, SourceRange(startOffset - topRuleBodyRangeStart, offset - topRuleBodyRangeStart)));
+}
+
+} // namespace
+
+enum MediaListSource {
+ MediaListSourceLinkedSheet,
+ MediaListSourceInlineSheet,
+ MediaListSourceMediaRule,
+ MediaListSourceImportRule
+};
+
+static PassRefPtr<TypeBuilder::CSS::SourceRange> buildSourceRangeObject(const SourceRange& range, Vector<size_t>* lineEndings)
+{
+ if (!lineEndings)
+ return 0;
+ TextPosition start = ContentSearchUtils::textPositionFromOffset(range.start, *lineEndings);
+ TextPosition end = ContentSearchUtils::textPositionFromOffset(range.end, *lineEndings);
+
+ RefPtr<TypeBuilder::CSS::SourceRange> result = TypeBuilder::CSS::SourceRange::create()
+ .setStartLine(start.m_line.zeroBasedInt())
+ .setStartColumn(start.m_column.zeroBasedInt())
+ .setEndLine(end.m_line.zeroBasedInt())
+ .setEndColumn(end.m_column.zeroBasedInt());
+ return result.release();
+}
+
+static PassRefPtr<TypeBuilder::CSS::CSSMedia> buildMediaObject(const MediaList* media, MediaListSource mediaListSource, const String& sourceURL)
+{
+ // Make certain compilers happy by initializing |source| up-front.
+ TypeBuilder::CSS::CSSMedia::Source::Enum source = TypeBuilder::CSS::CSSMedia::Source::InlineSheet;
+ switch (mediaListSource) {
+ case MediaListSourceMediaRule:
+ source = TypeBuilder::CSS::CSSMedia::Source::MediaRule;
+ break;
+ case MediaListSourceImportRule:
+ source = TypeBuilder::CSS::CSSMedia::Source::ImportRule;
+ break;
+ case MediaListSourceLinkedSheet:
+ source = TypeBuilder::CSS::CSSMedia::Source::LinkedSheet;
+ break;
+ case MediaListSourceInlineSheet:
+ source = TypeBuilder::CSS::CSSMedia::Source::InlineSheet;
+ break;
+ }
+
+ RefPtr<TypeBuilder::CSS::CSSMedia> mediaObject = TypeBuilder::CSS::CSSMedia::create()
+ .setText(media->mediaText())
+ .setSource(source);
+
+ if (!sourceURL.isEmpty()) {
+ mediaObject->setSourceURL(sourceURL);
+ mediaObject->setSourceLine(media->queries()->lastLine());
+ }
+ return mediaObject.release();
+}
+
+static PassRefPtr<CSSRuleList> asCSSRuleList(CSSStyleSheet* styleSheet)
+{
+ if (!styleSheet)
+ return 0;
+
+ RefPtr<StaticCSSRuleList> list = StaticCSSRuleList::create();
+ Vector<RefPtr<CSSRule> >& listRules = list->rules();
+ for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
+ CSSRule* item = styleSheet->item(i);
+ if (item->type() == CSSRule::CHARSET_RULE)
+ continue;
+ listRules.append(item);
+ }
+ return list.release();
+}
+
+static PassRefPtr<CSSRuleList> asCSSRuleList(CSSRule* rule)
+{
+ if (!rule)
+ return 0;
+
+ if (rule->type() == CSSRule::MEDIA_RULE)
+ return static_cast<CSSMediaRule*>(rule)->cssRules();
+
+ if (rule->type() == CSSRule::WEBKIT_KEYFRAMES_RULE)
+ return static_cast<WebKitCSSKeyframesRule*>(rule)->cssRules();
+
+ if (rule->type() == CSSRule::HOST_RULE)
+ return static_cast<CSSHostRule*>(rule)->cssRules();
+
+ if (rule->type() == CSSRule::SUPPORTS_RULE)
+ return static_cast<CSSSupportsRule*>(rule)->cssRules();
+
+ return 0;
+}
+
+static void fillMediaListChain(CSSRule* rule, Array<TypeBuilder::CSS::CSSMedia>* mediaArray)
+{
+ MediaList* mediaList;
+ CSSRule* parentRule = rule;
+ String sourceURL;
+ while (parentRule) {
+ CSSStyleSheet* parentStyleSheet = 0;
+ bool isMediaRule = true;
+ if (parentRule->type() == CSSRule::MEDIA_RULE) {
+ CSSMediaRule* mediaRule = static_cast<CSSMediaRule*>(parentRule);
+ mediaList = mediaRule->media();
+ parentStyleSheet = mediaRule->parentStyleSheet();
+ } else if (parentRule->type() == CSSRule::IMPORT_RULE) {
+ CSSImportRule* importRule = static_cast<CSSImportRule*>(parentRule);
+ mediaList = importRule->media();
+ parentStyleSheet = importRule->parentStyleSheet();
+ isMediaRule = false;
+ } else
+ mediaList = 0;
+
+ if (parentStyleSheet) {
+ sourceURL = parentStyleSheet->contents()->baseURL();
+ if (sourceURL.isEmpty())
+ sourceURL = InspectorDOMAgent::documentURLString(parentStyleSheet->ownerDocument());
+ } else
+ sourceURL = "";
+
+ if (mediaList && mediaList->length())
+ mediaArray->addItem(buildMediaObject(mediaList, isMediaRule ? MediaListSourceMediaRule : MediaListSourceImportRule, sourceURL));
+
+ if (parentRule->parentRule())
+ parentRule = parentRule->parentRule();
+ else {
+ CSSStyleSheet* styleSheet = parentRule->parentStyleSheet();
+ while (styleSheet) {
+ mediaList = styleSheet->media();
+ if (mediaList && mediaList->length()) {
+ Document* doc = styleSheet->ownerDocument();
+ if (doc)
+ sourceURL = doc->url();
+ else if (!styleSheet->contents()->baseURL().isEmpty())
+ sourceURL = styleSheet->contents()->baseURL();
+ else
+ sourceURL = "";
+ mediaArray->addItem(buildMediaObject(mediaList, styleSheet->ownerNode() ? MediaListSourceLinkedSheet : MediaListSourceInlineSheet, sourceURL));
+ }
+ parentRule = styleSheet->ownerRule();
+ if (parentRule)
+ break;
+ styleSheet = styleSheet->parentStyleSheet();
+ }
+ }
+ }
+}
+
+PassRefPtr<InspectorStyle> InspectorStyle::create(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet)
+{
+ return adoptRef(new InspectorStyle(styleId, style, parentStyleSheet));
+}
+
+InspectorStyle::InspectorStyle(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet)
+ : m_styleId(styleId)
+ , m_style(style)
+ , m_parentStyleSheet(parentStyleSheet)
+ , m_formatAcquired(false)
+{
+ ASSERT(m_style);
+}
+
+InspectorStyle::~InspectorStyle()
+{
+}
+
+PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorStyle::buildObjectForStyle() const
+{
+ RefPtr<TypeBuilder::CSS::CSSStyle> result = styleWithProperties();
+ if (!m_styleId.isEmpty())
+ result->setStyleId(m_styleId.asProtocolValue<TypeBuilder::CSS::CSSStyleId>());
+
+ result->setWidth(m_style->getPropertyValue("width"));
+ result->setHeight(m_style->getPropertyValue("height"));
+
+ RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
+ if (sourceData)
+ result->setRange(buildSourceRangeObject(sourceData->ruleBodyRange, m_parentStyleSheet->lineEndings().get()));
+
+ return result.release();
+}
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> > InspectorStyle::buildArrayForComputedStyle() const
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty>::create();
+ Vector<InspectorStyleProperty> properties;
+ populateAllProperties(properties);
+
+ for (Vector<InspectorStyleProperty>::iterator it = properties.begin(), itEnd = properties.end(); it != itEnd; ++it) {
+ const CSSPropertySourceData& propertyEntry = it->sourceData;
+ RefPtr<TypeBuilder::CSS::CSSComputedStyleProperty> entry = TypeBuilder::CSS::CSSComputedStyleProperty::create()
+ .setName(propertyEntry.name)
+ .setValue(propertyEntry.value);
+ result->addItem(entry);
+ }
+
+ return result.release();
+}
+
+// This method does the following preprocessing of |propertyText| with |overwrite| == false and |index| past the last active property:
+// - If the last property (if present) has no closing ";", the ";" is prepended to the current |propertyText| value.
+// - A heuristic formatting is attempted to retain the style structure.
+//
+// The propertyText (if not empty) is checked to be a valid style declaration (containing at least one property). If not,
+// the method returns false (denoting an error).
+bool InspectorStyle::setPropertyText(unsigned index, const String& propertyText, bool overwrite, String* oldText, ExceptionCode& ec)
+{
+ ASSERT(m_parentStyleSheet);
+ DEFINE_STATIC_LOCAL(String, bogusPropertyName, (ASCIILiteral("-webkit-boguz-propertee")));
+
+ if (!m_parentStyleSheet->ensureParsedDataReady()) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ Vector<InspectorStyleProperty> allProperties;
+ populateAllProperties(allProperties);
+
+ if (!propertyText.stripWhiteSpace().isEmpty()) {
+ RefPtr<StylePropertySet> tempMutableStyle = StylePropertySet::create();
+ String declarationText = propertyText + " " + bogusPropertyName + ": none";
+ RuleSourceDataList sourceData;
+ StyleSheetHandler handler(declarationText, ownerDocument(), m_style->parentStyleSheet()->contents(), &sourceData);
+ createCSSParser(ownerDocument())->parseDeclaration(tempMutableStyle.get(), declarationText, &handler, m_style->parentStyleSheet()->contents());
+ Vector<CSSPropertySourceData>& propertyData = sourceData.first()->styleSourceData->propertyData;
+ unsigned propertyCount = propertyData.size();
+
+ // At least one property + the bogus property added just above should be present.
+ if (propertyCount < 2) {
+ ec = SYNTAX_ERR;
+ return false;
+ }
+
+ // Check for the proper propertyText termination (the parser could at least restore to the PROPERTY_NAME state).
+ if (propertyData.at(propertyCount - 1).name != bogusPropertyName) {
+ ec = SYNTAX_ERR;
+ return false;
+ }
+ }
+
+ RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
+ if (!sourceData) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ String text;
+ bool success = styleText(&text);
+ if (!success) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ InspectorStyleTextEditor editor(&allProperties, text, newLineAndWhitespaceDelimiters());
+ if (overwrite) {
+ if (index >= allProperties.size()) {
+ ec = INDEX_SIZE_ERR;
+ return false;
+ }
+ *oldText = allProperties.at(index).rawText;
+ editor.replaceProperty(index, propertyText);
+ } else
+ editor.insertProperty(index, propertyText, sourceData->ruleBodyRange.length());
+
+ return applyStyleText(editor.styleText());
+}
+
+bool InspectorStyle::toggleProperty(unsigned index, bool disable, ExceptionCode& ec)
+{
+ ASSERT(m_parentStyleSheet);
+ if (!m_parentStyleSheet->ensureParsedDataReady()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return false;
+ }
+
+ RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
+ if (!sourceData) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ String text;
+ bool success = styleText(&text);
+ if (!success) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ Vector<InspectorStyleProperty> allProperties;
+ populateAllProperties(allProperties);
+ if (index >= allProperties.size()) {
+ ec = INDEX_SIZE_ERR;
+ return false;
+ }
+
+ InspectorStyleProperty& property = allProperties.at(index);
+ if (property.sourceData.disabled == disable)
+ return true; // Idempotent operation.
+
+ InspectorStyleTextEditor editor(&allProperties, text, newLineAndWhitespaceDelimiters());
+ if (disable)
+ editor.disableProperty(index);
+ else
+ editor.enableProperty(index);
+
+ return applyStyleText(editor.styleText());
+}
+
+bool InspectorStyle::styleText(String* result) const
+{
+ RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
+ if (!sourceData)
+ return false;
+
+ String styleSheetText;
+ bool success = m_parentStyleSheet->getText(&styleSheetText);
+ if (!success)
+ return false;
+
+ SourceRange& bodyRange = sourceData->ruleBodyRange;
+ *result = styleSheetText.substring(bodyRange.start, bodyRange.end - bodyRange.start);
+ return true;
+}
+
+void InspectorStyle::populateAllProperties(Vector<InspectorStyleProperty>& result) const
+{
+ HashSet<String> foundShorthands;
+ HashSet<String> sourcePropertyNames;
+
+ RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
+ OwnPtr<CSSParser> cssParser;
+ if (sourceData) {
+ String styleDeclaration;
+ bool isStyleTextKnown = styleText(&styleDeclaration);
+ ASSERT_UNUSED(isStyleTextKnown, isStyleTextKnown);
+ Vector<CSSPropertySourceData>& sourcePropertyData = sourceData->styleSourceData->propertyData;
+ for (Vector<CSSPropertySourceData>::const_iterator it = sourcePropertyData.begin(); it != sourcePropertyData.end(); ++it) {
+ InspectorStyleProperty p(*it, true);
+ p.setRawTextFromStyleDeclaration(styleDeclaration);
+ result.append(p);
+ sourcePropertyNames.add(it->name.lower());
+ }
+ }
+
+ for (int i = 0, size = m_style->length(); i < size; ++i) {
+ String name = m_style->item(i);
+ if (sourcePropertyNames.contains(name.lower()))
+ continue;
+
+ sourcePropertyNames.add(name.lower());
+ result.append(InspectorStyleProperty(CSSPropertySourceData(name, m_style->getPropertyValue(name), !m_style->getPropertyPriority(name).isEmpty(), false, true, SourceRange()), false));
+ }
+}
+
+PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorStyle::styleWithProperties() const
+{
+ Vector<InspectorStyleProperty> properties;
+ populateAllProperties(properties);
+
+ RefPtr<Array<TypeBuilder::CSS::CSSProperty> > propertiesObject = Array<TypeBuilder::CSS::CSSProperty>::create();
+ RefPtr<Array<TypeBuilder::CSS::ShorthandEntry> > shorthandEntries = Array<TypeBuilder::CSS::ShorthandEntry>::create();
+ HashMap<String, RefPtr<TypeBuilder::CSS::CSSProperty> > propertyNameToPreviousActiveProperty;
+ HashSet<String> foundShorthands;
+ String previousPriority;
+ String previousStatus;
+ OwnPtr<Vector<size_t> > lineEndings(m_parentStyleSheet ? m_parentStyleSheet->lineEndings() : PassOwnPtr<Vector<size_t> >());
+ RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
+ unsigned ruleBodyRangeStart = sourceData ? sourceData->ruleBodyRange.start : 0;
+
+ for (Vector<InspectorStyleProperty>::iterator it = properties.begin(), itEnd = properties.end(); it != itEnd; ++it) {
+ const CSSPropertySourceData& propertyEntry = it->sourceData;
+ const String& name = propertyEntry.name;
+ const bool disabled = it->sourceData.disabled;
+
+ TypeBuilder::CSS::CSSProperty::Status::Enum status = disabled ? TypeBuilder::CSS::CSSProperty::Status::Disabled : TypeBuilder::CSS::CSSProperty::Status::Active;
+
+ RefPtr<TypeBuilder::CSS::CSSProperty> property = TypeBuilder::CSS::CSSProperty::create()
+ .setName(name)
+ .setValue(propertyEntry.value);
+ propertiesObject->addItem(property);
+
+ // Default "parsedOk" == true.
+ if (!propertyEntry.parsedOk)
+ property->setParsedOk(false);
+ if (it->hasRawText())
+ property->setText(it->rawText);
+
+ // Default "priority" == "".
+ if (propertyEntry.important)
+ property->setPriority("important");
+ if (it->hasSource) {
+ // The property range is relative to the style body start.
+ // Should be converted into an absolute range (relative to the stylesheet start)
+ // for the proper conversion into line:column.
+ SourceRange absolutePropertyRange = propertyEntry.range;
+ absolutePropertyRange.start += ruleBodyRangeStart;
+ absolutePropertyRange.end += ruleBodyRangeStart;
+ property->setRange(buildSourceRangeObject(absolutePropertyRange, lineEndings.get()));
+ }
+ if (!disabled) {
+ if (it->hasSource) {
+ ASSERT(sourceData);
+ property->setImplicit(false);
+
+ // Parsed property overrides any property with the same name. Non-parsed property overrides
+ // previous non-parsed property with the same name (if any).
+ bool shouldInactivate = false;
+ CSSPropertyID propertyId = cssPropertyID(name);
+ // Canonicalize property names to treat non-prefixed and vendor-prefixed property names the same (opacity vs. -webkit-opacity).
+ String canonicalPropertyName = propertyId ? getPropertyNameString(propertyId) : name;
+ HashMap<String, RefPtr<TypeBuilder::CSS::CSSProperty> >::iterator activeIt = propertyNameToPreviousActiveProperty.find(canonicalPropertyName);
+ if (activeIt != propertyNameToPreviousActiveProperty.end()) {
+ if (propertyEntry.parsedOk) {
+ bool successPriority = activeIt->value->getString(TypeBuilder::CSS::CSSProperty::Priority, &previousPriority);
+ bool successStatus = activeIt->value->getString(TypeBuilder::CSS::CSSProperty::Status, &previousStatus);
+ if (successStatus && previousStatus != "inactive") {
+ if (propertyEntry.important || !successPriority) // Priority not set == "not important".
+ shouldInactivate = true;
+ else if (status == TypeBuilder::CSS::CSSProperty::Status::Active) {
+ // Inactivate a non-important property following the same-named important property.
+ status = TypeBuilder::CSS::CSSProperty::Status::Inactive;
+ }
+ }
+ } else {
+ bool previousParsedOk;
+ bool success = activeIt->value->getBoolean(TypeBuilder::CSS::CSSProperty::ParsedOk, &previousParsedOk);
+ if (success && !previousParsedOk)
+ shouldInactivate = true;
+ }
+ } else
+ propertyNameToPreviousActiveProperty.set(canonicalPropertyName, property);
+
+ if (shouldInactivate) {
+ activeIt->value->setStatus(TypeBuilder::CSS::CSSProperty::Status::Inactive);
+ propertyNameToPreviousActiveProperty.set(canonicalPropertyName, property);
+ }
+ } else {
+ bool implicit = m_style->isPropertyImplicit(name);
+ // Default "implicit" == false.
+ if (implicit)
+ property->setImplicit(true);
+ status = TypeBuilder::CSS::CSSProperty::Status::Style;
+
+ String shorthand = m_style->getPropertyShorthand(name);
+ if (!shorthand.isEmpty()) {
+ if (!foundShorthands.contains(shorthand)) {
+ foundShorthands.add(shorthand);
+ RefPtr<TypeBuilder::CSS::ShorthandEntry> entry = TypeBuilder::CSS::ShorthandEntry::create()
+ .setName(shorthand)
+ .setValue(shorthandValue(shorthand));
+ shorthandEntries->addItem(entry);
+ }
+ }
+ }
+ }
+
+ // Default "status" == "style".
+ if (status != TypeBuilder::CSS::CSSProperty::Status::Style)
+ property->setStatus(status);
+ }
+
+ RefPtr<TypeBuilder::CSS::CSSStyle> result = TypeBuilder::CSS::CSSStyle::create()
+ .setCssProperties(propertiesObject)
+ .setShorthandEntries(shorthandEntries);
+ return result.release();
+}
+
+PassRefPtr<CSSRuleSourceData> InspectorStyle::extractSourceData() const
+{
+ if (!m_parentStyleSheet || !m_parentStyleSheet->ensureParsedDataReady())
+ return 0;
+ return m_parentStyleSheet->ruleSourceDataFor(m_style.get());
+}
+
+bool InspectorStyle::applyStyleText(const String& text)
+{
+ return m_parentStyleSheet->setStyleText(m_style.get(), text);
+}
+
+String InspectorStyle::shorthandValue(const String& shorthandProperty) const
+{
+ String value = m_style->getPropertyValue(shorthandProperty);
+ if (value.isEmpty()) {
+ for (unsigned i = 0; i < m_style->length(); ++i) {
+ String individualProperty = m_style->item(i);
+ if (m_style->getPropertyShorthand(individualProperty) != shorthandProperty)
+ continue;
+ if (m_style->isPropertyImplicit(individualProperty))
+ continue;
+ String individualValue = m_style->getPropertyValue(individualProperty);
+ if (individualValue == "initial")
+ continue;
+ if (value.length())
+ value.append(" ");
+ value.append(individualValue);
+ }
+ }
+ return value;
+}
+
+String InspectorStyle::shorthandPriority(const String& shorthandProperty) const
+{
+ String priority = m_style->getPropertyPriority(shorthandProperty);
+ if (priority.isEmpty()) {
+ for (unsigned i = 0; i < m_style->length(); ++i) {
+ String individualProperty = m_style->item(i);
+ if (m_style->getPropertyShorthand(individualProperty) != shorthandProperty)
+ continue;
+ priority = m_style->getPropertyPriority(individualProperty);
+ break;
+ }
+ }
+ return priority;
+}
+
+Vector<String> InspectorStyle::longhandProperties(const String& shorthandProperty) const
+{
+ Vector<String> properties;
+ HashSet<String> foundProperties;
+ for (unsigned i = 0; i < m_style->length(); ++i) {
+ String individualProperty = m_style->item(i);
+ if (foundProperties.contains(individualProperty) || m_style->getPropertyShorthand(individualProperty) != shorthandProperty)
+ continue;
+
+ foundProperties.add(individualProperty);
+ properties.append(individualProperty);
+ }
+ return properties;
+}
+
+NewLineAndWhitespace& InspectorStyle::newLineAndWhitespaceDelimiters() const
+{
+ DEFINE_STATIC_LOCAL(String, defaultPrefix, (ASCIILiteral(" ")));
+
+ if (m_formatAcquired)
+ return m_format;
+
+ RefPtr<CSSRuleSourceData> sourceData = extractSourceData();
+ Vector<CSSPropertySourceData>* sourcePropertyData = sourceData ? &(sourceData->styleSourceData->propertyData) : 0;
+ int propertyCount;
+ if (!sourcePropertyData || !(propertyCount = sourcePropertyData->size())) {
+ m_format.first = "\n";
+ m_format.second = defaultPrefix;
+ return m_format; // Do not remember the default formatting and attempt to acquire it later.
+ }
+
+ String text;
+ bool success = styleText(&text);
+ ASSERT_UNUSED(success, success);
+
+ m_formatAcquired = true;
+
+ String candidatePrefix = defaultPrefix;
+ StringBuilder formatLineFeed;
+ StringBuilder prefix;
+ int scanStart = 0;
+ int propertyIndex = 0;
+ bool isFullPrefixScanned = false;
+ bool lineFeedTerminated = false;
+ const UChar* characters = text.characters();
+ while (propertyIndex < propertyCount) {
+ const WebCore::CSSPropertySourceData& currentProperty = sourcePropertyData->at(propertyIndex++);
+
+ bool processNextProperty = false;
+ int scanEnd = currentProperty.range.start;
+ for (int i = scanStart; i < scanEnd; ++i) {
+ UChar ch = characters[i];
+ bool isLineFeed = isHTMLLineBreak(ch);
+ if (isLineFeed) {
+ if (!lineFeedTerminated)
+ formatLineFeed.append(ch);
+ prefix.clear();
+ } else if (isHTMLSpace(ch))
+ prefix.append(ch);
+ else {
+ candidatePrefix = prefix.toString();
+ prefix.clear();
+ scanStart = currentProperty.range.end;
+ ++propertyIndex;
+ processNextProperty = true;
+ break;
+ }
+ if (!isLineFeed && formatLineFeed.length())
+ lineFeedTerminated = true;
+ }
+ if (!processNextProperty) {
+ isFullPrefixScanned = true;
+ break;
+ }
+ }
+
+ m_format.first = formatLineFeed.toString();
+ m_format.second = isFullPrefixScanned ? prefix.toString() : candidatePrefix;
+ return m_format;
+}
+
+Document* InspectorStyle::ownerDocument() const
+{
+ return m_parentStyleSheet->pageStyleSheet() ? m_parentStyleSheet->pageStyleSheet()->ownerDocument() : 0;
+}
+
+PassRefPtr<InspectorStyleSheet> InspectorStyleSheet::create(InspectorPageAgent* pageAgent, const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, TypeBuilder::CSS::StyleSheetOrigin::Enum origin, const String& documentURL, Listener* listener)
+{
+ return adoptRef(new InspectorStyleSheet(pageAgent, id, pageStyleSheet, origin, documentURL, listener));
+}
+
+// static
+String InspectorStyleSheet::styleSheetURL(CSSStyleSheet* pageStyleSheet)
+{
+ if (pageStyleSheet && !pageStyleSheet->contents()->baseURL().isEmpty())
+ return pageStyleSheet->contents()->baseURL().string();
+ return emptyString();
+}
+
+InspectorStyleSheet::InspectorStyleSheet(InspectorPageAgent* pageAgent, const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, TypeBuilder::CSS::StyleSheetOrigin::Enum origin, const String& documentURL, Listener* listener)
+ : m_pageAgent(pageAgent)
+ , m_id(id)
+ , m_pageStyleSheet(pageStyleSheet)
+ , m_origin(origin)
+ , m_documentURL(documentURL)
+ , m_isRevalidating(false)
+ , m_isReparsing(false)
+ , m_listener(listener)
+{
+ m_parsedStyleSheet = new ParsedStyleSheet();
+}
+
+InspectorStyleSheet::~InspectorStyleSheet()
+{
+ delete m_parsedStyleSheet;
+}
+
+String InspectorStyleSheet::finalURL() const
+{
+ String url = styleSheetURL(m_pageStyleSheet.get());
+ return url.isEmpty() ? m_documentURL : url;
+}
+
+void InspectorStyleSheet::reparseStyleSheet(const String& text)
+{
+ {
+ // Have a separate scope for clearRules() (bug 95324).
+ CSSStyleSheet::RuleMutationScope mutationScope(m_pageStyleSheet.get());
+ m_pageStyleSheet->contents()->clearRules();
+ m_pageStyleSheet->clearChildRuleCSSOMWrappers();
+ }
+ {
+ m_isReparsing = true;
+ CSSStyleSheet::RuleMutationScope mutationScope(m_pageStyleSheet.get());
+ m_pageStyleSheet->contents()->parseString(text);
+ fireStyleSheetChanged();
+ m_isReparsing = false;
+ }
+}
+
+bool InspectorStyleSheet::setText(const String& text, ExceptionCode& ec)
+{
+ if (!checkPageStyleSheet(ec))
+ return false;
+ if (!m_parsedStyleSheet)
+ return false;
+
+ m_parsedStyleSheet->setText(text);
+ m_flatRules.clear();
+
+ return true;
+}
+
+String InspectorStyleSheet::ruleSelector(const InspectorCSSId& id, ExceptionCode& ec)
+{
+ CSSStyleRule* rule = ruleForId(id);
+ if (!rule) {
+ ec = NOT_FOUND_ERR;
+ return "";
+ }
+ return rule->selectorText();
+}
+
+bool InspectorStyleSheet::setRuleSelector(const InspectorCSSId& id, const String& selector, ExceptionCode& ec)
+{
+ if (!checkPageStyleSheet(ec))
+ return false;
+ CSSStyleRule* rule = ruleForId(id);
+ if (!rule) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+ CSSStyleSheet* styleSheet = rule->parentStyleSheet();
+ if (!styleSheet || !ensureParsedDataReady()) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ rule->setSelectorText(selector);
+ RefPtr<CSSRuleSourceData> sourceData = ruleSourceDataFor(rule->style());
+ if (!sourceData) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ String sheetText = m_parsedStyleSheet->text();
+ sheetText.replace(sourceData->ruleHeaderRange.start, sourceData->ruleHeaderRange.length(), selector);
+ m_parsedStyleSheet->setText(sheetText);
+ fireStyleSheetChanged();
+ return true;
+}
+
+static bool checkStyleRuleSelector(Document* document, const String& selector)
+{
+ CSSSelectorList selectorList;
+ createCSSParser(document)->parseSelector(selector, selectorList);
+ return selectorList.isValid();
+}
+
+CSSStyleRule* InspectorStyleSheet::addRule(const String& selector, ExceptionCode& ec)
+{
+ if (!checkPageStyleSheet(ec))
+ return 0;
+ if (!checkStyleRuleSelector(m_pageStyleSheet->ownerDocument(), selector)) {
+ ec = SYNTAX_ERR;
+ return 0;
+ }
+
+ String text;
+ bool success = getText(&text);
+ if (!success) {
+ ec = NOT_FOUND_ERR;
+ return 0;
+ }
+ StringBuilder styleSheetText;
+ styleSheetText.append(text);
+
+ m_pageStyleSheet->addRule(selector, "", ec);
+ if (ec)
+ return 0;
+ ASSERT(m_pageStyleSheet->length());
+ unsigned lastRuleIndex = m_pageStyleSheet->length() - 1;
+ CSSRule* rule = m_pageStyleSheet->item(lastRuleIndex);
+ ASSERT(rule);
+
+ CSSStyleRule* styleRule = InspectorCSSAgent::asCSSStyleRule(rule);
+ if (!styleRule) {
+ // What we just added has to be a CSSStyleRule - we cannot handle other types of rules yet.
+ // If it is not a style rule, pretend we never touched the stylesheet.
+ m_pageStyleSheet->deleteRule(lastRuleIndex, ASSERT_NO_EXCEPTION);
+ ec = SYNTAX_ERR;
+ return 0;
+ }
+
+ if (!styleSheetText.isEmpty())
+ styleSheetText.append('\n');
+
+ styleSheetText.append(selector);
+ styleSheetText.appendLiteral(" {}");
+ // Using setText() as this operation changes the style sheet rule set.
+ setText(styleSheetText.toString(), ASSERT_NO_EXCEPTION);
+
+ fireStyleSheetChanged();
+
+ return styleRule;
+}
+
+bool InspectorStyleSheet::deleteRule(const InspectorCSSId& id, ExceptionCode& ec)
+{
+ if (!checkPageStyleSheet(ec))
+ return false;
+ RefPtr<CSSStyleRule> rule = ruleForId(id);
+ if (!rule) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+ CSSStyleSheet* styleSheet = rule->parentStyleSheet();
+ if (!styleSheet || !ensureParsedDataReady()) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ RefPtr<CSSRuleSourceData> sourceData = ruleSourceDataFor(rule->style());
+ if (!sourceData) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ styleSheet->deleteRule(id.ordinal(), ec);
+ // |rule| MAY NOT be addressed after this line!
+
+ if (ec)
+ return false;
+
+ String sheetText = m_parsedStyleSheet->text();
+ sheetText.remove(sourceData->ruleHeaderRange.start, sourceData->ruleBodyRange.end - sourceData->ruleHeaderRange.start + 1);
+ setText(sheetText, ASSERT_NO_EXCEPTION);
+ fireStyleSheetChanged();
+ return true;
+}
+
+CSSStyleRule* InspectorStyleSheet::ruleForId(const InspectorCSSId& id) const
+{
+ if (!m_pageStyleSheet)
+ return 0;
+
+ ASSERT(!id.isEmpty());
+ ensureFlatRules();
+ return id.ordinal() >= m_flatRules.size() ? 0 : m_flatRules.at(id.ordinal()).get();
+
+}
+
+PassRefPtr<TypeBuilder::CSS::CSSStyleSheetBody> InspectorStyleSheet::buildObjectForStyleSheet()
+{
+ CSSStyleSheet* styleSheet = pageStyleSheet();
+ if (!styleSheet)
+ return 0;
+
+ RefPtr<CSSRuleList> cssRuleList = asCSSRuleList(styleSheet);
+
+ RefPtr<TypeBuilder::CSS::CSSStyleSheetBody> result = TypeBuilder::CSS::CSSStyleSheetBody::create()
+ .setStyleSheetId(id())
+ .setRules(buildArrayForRuleList(cssRuleList.get()));
+
+ String styleSheetText;
+ bool success = getText(&styleSheetText);
+ if (success)
+ result->setText(styleSheetText);
+
+ return result.release();
+}
+
+PassRefPtr<TypeBuilder::CSS::CSSStyleSheetHeader> InspectorStyleSheet::buildObjectForStyleSheetInfo()
+{
+ CSSStyleSheet* styleSheet = pageStyleSheet();
+ if (!styleSheet)
+ return 0;
+
+ Document* document = styleSheet->ownerDocument();
+ Frame* frame = document ? document->frame() : 0;
+ RefPtr<TypeBuilder::CSS::CSSStyleSheetHeader> result = TypeBuilder::CSS::CSSStyleSheetHeader::create()
+ .setStyleSheetId(id())
+ .setOrigin(m_origin)
+ .setDisabled(styleSheet->disabled())
+ .setSourceURL(finalURL())
+ .setTitle(styleSheet->title())
+ .setFrameId(m_pageAgent->frameId(frame));
+
+ return result.release();
+}
+
+static PassRefPtr<TypeBuilder::Array<String> > selectorsFromSource(const CSSRuleSourceData* sourceData, const String& sheetText)
+{
+ RegularExpression comment("/\\*[^]*?\\*/", TextCaseSensitive, MultilineEnabled);
+ RefPtr<TypeBuilder::Array<String> > result = TypeBuilder::Array<String>::create();
+ const SelectorRangeList& ranges = sourceData->selectorRanges;
+ for (size_t i = 0, size = ranges.size(); i < size; ++i) {
+ const SourceRange& range = ranges.at(i);
+ String selector = sheetText.substring(range.start, range.length());
+
+ // We don't want to see any comments in the selector components, only the meaningful parts.
+ int matchLength;
+ int offset = 0;
+ while ((offset = comment.match(selector, offset, &matchLength)) >= 0)
+ selector.replace(offset, matchLength, "");
+
+ result->addItem(selector.stripWhiteSpace());
+ }
+ return result.release();
+}
+
+PassRefPtr<TypeBuilder::CSS::SelectorList> InspectorStyleSheet::buildObjectForSelectorList(CSSStyleRule* rule)
+{
+ RefPtr<CSSRuleSourceData> sourceData;
+ if (ensureParsedDataReady())
+ sourceData = ruleSourceDataFor(rule->style());
+ RefPtr<TypeBuilder::Array<String> > selectors;
+
+ // This intentionally does not rely on the source data to avoid catching the trailing comments (before the declaration starting '{').
+ String selectorText = rule->selectorText();
+
+ if (sourceData)
+ selectors = selectorsFromSource(sourceData.get(), m_parsedStyleSheet->text());
+ else {
+ selectors = TypeBuilder::Array<String>::create();
+ const CSSSelectorList& selectorList = rule->styleRule()->selectorList();
+ for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
+ selectors->addItem(selector->selectorText());
+ }
+ RefPtr<TypeBuilder::CSS::SelectorList> result = TypeBuilder::CSS::SelectorList::create()
+ .setSelectors(selectors)
+ .setText(selectorText)
+ .release();
+ if (sourceData)
+ result->setRange(buildSourceRangeObject(sourceData->ruleHeaderRange, lineEndings().get()));
+ return result.release();
+}
+
+PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorStyleSheet::buildObjectForRule(CSSStyleRule* rule)
+{
+ CSSStyleSheet* styleSheet = pageStyleSheet();
+ if (!styleSheet)
+ return 0;
+
+ RefPtr<TypeBuilder::CSS::CSSRule> result = TypeBuilder::CSS::CSSRule::create()
+ .setSelectorList(buildObjectForSelectorList(rule))
+ .setSourceLine(rule->styleRule()->sourceLine())
+ .setOrigin(m_origin)
+ .setStyle(buildObjectForStyle(rule->style()));
+
+ // "sourceURL" is present only for regular rules, otherwise "origin" should be used in the frontend.
+ if (m_origin == TypeBuilder::CSS::StyleSheetOrigin::Regular)
+ result->setSourceURL(finalURL());
+
+ if (canBind()) {
+ InspectorCSSId id(ruleId(rule));
+ if (!id.isEmpty())
+ result->setRuleId(id.asProtocolValue<TypeBuilder::CSS::CSSRuleId>());
+ }
+
+ RefPtr<Array<TypeBuilder::CSS::CSSMedia> > mediaArray = Array<TypeBuilder::CSS::CSSMedia>::create();
+
+ fillMediaListChain(rule, mediaArray.get());
+ if (mediaArray->length())
+ result->setMedia(mediaArray.release());
+
+ return result.release();
+}
+
+PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorStyleSheet::buildObjectForStyle(CSSStyleDeclaration* style)
+{
+ RefPtr<CSSRuleSourceData> sourceData;
+ if (ensureParsedDataReady())
+ sourceData = ruleSourceDataFor(style);
+
+ InspectorCSSId id = ruleOrStyleId(style);
+ if (id.isEmpty()) {
+ RefPtr<TypeBuilder::CSS::CSSStyle> bogusStyle = TypeBuilder::CSS::CSSStyle::create()
+ .setCssProperties(Array<TypeBuilder::CSS::CSSProperty>::create())
+ .setShorthandEntries(Array<TypeBuilder::CSS::ShorthandEntry>::create());
+ return bogusStyle.release();
+ }
+ RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
+ RefPtr<TypeBuilder::CSS::CSSStyle> result = inspectorStyle->buildObjectForStyle();
+
+ // Style text cannot be retrieved without stylesheet, so set cssText here.
+ if (sourceData) {
+ String sheetText;
+ bool success = getText(&sheetText);
+ if (success) {
+ const SourceRange& bodyRange = sourceData->ruleBodyRange;
+ result->setCssText(sheetText.substring(bodyRange.start, bodyRange.end - bodyRange.start));
+ }
+ }
+
+ return result.release();
+}
+
+bool InspectorStyleSheet::setStyleText(const InspectorCSSId& id, const String& text, String* oldText, ExceptionCode& ec)
+{
+ RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
+ if (!inspectorStyle || !inspectorStyle->cssStyle()) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ bool success = inspectorStyle->styleText(oldText);
+ if (!success) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ success = setStyleText(inspectorStyle->cssStyle(), text);
+ if (success)
+ fireStyleSheetChanged();
+ else
+ ec = SYNTAX_ERR;
+ return success;
+}
+
+bool InspectorStyleSheet::setPropertyText(const InspectorCSSId& id, unsigned propertyIndex, const String& text, bool overwrite, String* oldText, ExceptionCode& ec)
+{
+ RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
+ if (!inspectorStyle) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ bool success = inspectorStyle->setPropertyText(propertyIndex, text, overwrite, oldText, ec);
+ if (success)
+ fireStyleSheetChanged();
+ return success;
+}
+
+bool InspectorStyleSheet::toggleProperty(const InspectorCSSId& id, unsigned propertyIndex, bool disable, ExceptionCode& ec)
+{
+ RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
+ if (!inspectorStyle) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ bool success = inspectorStyle->toggleProperty(propertyIndex, disable, ec);
+ if (success)
+ fireStyleSheetChanged();
+ return success;
+}
+
+bool InspectorStyleSheet::getText(String* result) const
+{
+ if (!ensureText())
+ return false;
+ *result = m_parsedStyleSheet->text();
+ return true;
+}
+
+CSSStyleDeclaration* InspectorStyleSheet::styleForId(const InspectorCSSId& id) const
+{
+ CSSStyleRule* rule = ruleForId(id);
+ if (!rule)
+ return 0;
+
+ return rule->style();
+}
+
+void InspectorStyleSheet::fireStyleSheetChanged()
+{
+ if (m_listener)
+ m_listener->styleSheetChanged(this);
+}
+
+PassRefPtr<InspectorStyle> InspectorStyleSheet::inspectorStyleForId(const InspectorCSSId& id)
+{
+ CSSStyleDeclaration* style = styleForId(id);
+ if (!style)
+ return 0;
+
+ return InspectorStyle::create(id, style, this);
+}
+
+InspectorCSSId InspectorStyleSheet::ruleOrStyleId(CSSStyleDeclaration* style) const
+{
+ unsigned index = ruleIndexByStyle(style);
+ if (index != UINT_MAX)
+ return InspectorCSSId(id(), index);
+ return InspectorCSSId();
+}
+
+Document* InspectorStyleSheet::ownerDocument() const
+{
+ return m_pageStyleSheet->ownerDocument();
+}
+
+PassRefPtr<CSSRuleSourceData> InspectorStyleSheet::ruleSourceDataFor(CSSStyleDeclaration* style) const
+{
+ return m_parsedStyleSheet->ruleSourceDataAt(ruleIndexByStyle(style));
+}
+
+PassOwnPtr<Vector<size_t> > InspectorStyleSheet::lineEndings() const
+{
+ if (!m_parsedStyleSheet->hasText())
+ return PassOwnPtr<Vector<size_t> >();
+ return ContentSearchUtils::lineEndings(m_parsedStyleSheet->text());
+}
+
+unsigned InspectorStyleSheet::ruleIndexByStyle(CSSStyleDeclaration* pageStyle) const
+{
+ ensureFlatRules();
+ unsigned index = 0;
+ for (unsigned i = 0, size = m_flatRules.size(); i < size; ++i) {
+ if (m_flatRules.at(i)->style() == pageStyle)
+ return index;
+
+ ++index;
+ }
+ return UINT_MAX;
+}
+
+bool InspectorStyleSheet::checkPageStyleSheet(ExceptionCode& ec) const
+{
+ if (!m_pageStyleSheet) {
+ ec = NOT_SUPPORTED_ERR;
+ return false;
+ }
+ return true;
+}
+
+bool InspectorStyleSheet::ensureParsedDataReady()
+{
+ return ensureText() && ensureSourceData();
+}
+
+bool InspectorStyleSheet::ensureText() const
+{
+ if (!m_parsedStyleSheet)
+ return false;
+ if (m_parsedStyleSheet->hasText())
+ return true;
+
+ String text;
+ bool success = originalStyleSheetText(&text);
+ if (success)
+ m_parsedStyleSheet->setText(text);
+ // No need to clear m_flatRules here - it's empty.
+
+ return success;
+}
+
+bool InspectorStyleSheet::ensureSourceData()
+{
+ if (m_parsedStyleSheet->hasSourceData())
+ return true;
+
+ if (!m_parsedStyleSheet->hasText())
+ return false;
+
+ RefPtr<StyleSheetContents> newStyleSheet = StyleSheetContents::create();
+ OwnPtr<RuleSourceDataList> result = adoptPtr(new RuleSourceDataList());
+ StyleSheetHandler handler(m_parsedStyleSheet->text(), m_pageStyleSheet->ownerDocument(), newStyleSheet.get(), result.get());
+ createCSSParser(m_pageStyleSheet->ownerDocument())->parseSheet(newStyleSheet.get(), m_parsedStyleSheet->text(), 0, &handler);
+ m_parsedStyleSheet->setSourceData(result.release());
+ return m_parsedStyleSheet->hasSourceData();
+}
+
+void InspectorStyleSheet::ensureFlatRules() const
+{
+ // We are fine with redoing this for empty stylesheets as this will run fast.
+ if (m_flatRules.isEmpty())
+ collectFlatRules(asCSSRuleList(pageStyleSheet()), &m_flatRules);
+}
+
+bool InspectorStyleSheet::setStyleText(CSSStyleDeclaration* style, const String& text)
+{
+ if (!m_pageStyleSheet)
+ return false;
+ if (!ensureParsedDataReady())
+ return false;
+
+ String patchedStyleSheetText;
+ bool success = styleSheetTextWithChangedStyle(style, text, &patchedStyleSheetText);
+ if (!success)
+ return false;
+
+ InspectorCSSId id = ruleOrStyleId(style);
+ if (id.isEmpty())
+ return false;
+
+ ExceptionCode ec = 0;
+ style->setCssText(text, ec);
+ if (!ec)
+ m_parsedStyleSheet->setText(patchedStyleSheetText);
+
+ return !ec;
+}
+
+bool InspectorStyleSheet::styleSheetTextWithChangedStyle(CSSStyleDeclaration* style, const String& newStyleText, String* result)
+{
+ if (!style)
+ return false;
+
+ if (!ensureParsedDataReady())
+ return false;
+
+ RefPtr<CSSRuleSourceData> sourceData = ruleSourceDataFor(style);
+ unsigned bodyStart = sourceData->ruleBodyRange.start;
+ unsigned bodyEnd = sourceData->ruleBodyRange.end;
+ ASSERT(bodyStart <= bodyEnd);
+
+ String text = m_parsedStyleSheet->text();
+ ASSERT_WITH_SECURITY_IMPLICATION(bodyEnd <= text.length()); // bodyEnd is exclusive
+
+ text.replace(bodyStart, bodyEnd - bodyStart, newStyleText);
+ *result = text;
+ return true;
+}
+
+InspectorCSSId InspectorStyleSheet::ruleId(CSSStyleRule* rule) const
+{
+ return ruleOrStyleId(rule->style());
+}
+
+void InspectorStyleSheet::revalidateStyle(CSSStyleDeclaration* pageStyle)
+{
+ if (m_isRevalidating)
+ return;
+
+ m_isRevalidating = true;
+ ensureFlatRules();
+ for (unsigned i = 0, size = m_flatRules.size(); i < size; ++i) {
+ CSSStyleRule* parsedRule = m_flatRules.at(i).get();
+ if (parsedRule->style() == pageStyle) {
+ if (parsedRule->styleRule()->properties()->asText() != pageStyle->cssText())
+ setStyleText(pageStyle, pageStyle->cssText());
+ break;
+ }
+ }
+ m_isRevalidating = false;
+}
+
+bool InspectorStyleSheet::originalStyleSheetText(String* result) const
+{
+ bool success = inlineStyleSheetText(result);
+ if (!success)
+ success = resourceStyleSheetText(result);
+ return success;
+}
+
+bool InspectorStyleSheet::resourceStyleSheetText(String* result) const
+{
+ if (m_origin == TypeBuilder::CSS::StyleSheetOrigin::User || m_origin == TypeBuilder::CSS::StyleSheetOrigin::User_agent)
+ return false;
+
+ if (!m_pageStyleSheet || !ownerDocument() || !ownerDocument()->frame())
+ return false;
+
+ String error;
+ bool base64Encoded;
+ InspectorPageAgent::resourceContent(&error, ownerDocument()->frame(), KURL(ParsedURLString, m_pageStyleSheet->href()), result, &base64Encoded);
+ return error.isEmpty() && !base64Encoded;
+}
+
+bool InspectorStyleSheet::inlineStyleSheetText(String* result) const
+{
+ if (!m_pageStyleSheet)
+ return false;
+
+ Node* ownerNode = m_pageStyleSheet->ownerNode();
+ if (!ownerNode || ownerNode->nodeType() != Node::ELEMENT_NODE)
+ return false;
+ Element* ownerElement = toElement(ownerNode);
+
+ if (!ownerElement->hasTagName(HTMLNames::styleTag)
+#if ENABLE(SVG)
+ && !ownerElement->hasTagName(SVGNames::styleTag)
+#endif
+ )
+ return false;
+ *result = ownerElement->textContent();
+ return true;
+}
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > InspectorStyleSheet::buildArrayForRuleList(CSSRuleList* ruleList)
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSRule>::create();
+ if (!ruleList)
+ return result.release();
+
+ RefPtr<CSSRuleList> refRuleList = ruleList;
+ CSSStyleRuleVector rules;
+ collectFlatRules(refRuleList, &rules);
+
+ for (unsigned i = 0, size = rules.size(); i < size; ++i)
+ result->addItem(buildObjectForRule(rules.at(i).get()));
+
+ return result.release();
+}
+
+void InspectorStyleSheet::collectFlatRules(PassRefPtr<CSSRuleList> ruleList, CSSStyleRuleVector* result)
+{
+ if (!ruleList)
+ return;
+
+ for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
+ CSSRule* rule = ruleList->item(i);
+ CSSStyleRule* styleRule = InspectorCSSAgent::asCSSStyleRule(rule);
+ if (styleRule)
+ result->append(styleRule);
+ else {
+ RefPtr<CSSRuleList> childRuleList = asCSSRuleList(rule);
+ if (childRuleList)
+ collectFlatRules(childRuleList, result);
+ }
+ }
+}
+
+PassRefPtr<InspectorStyleSheetForInlineStyle> InspectorStyleSheetForInlineStyle::create(InspectorPageAgent* pageAgent, const String& id, PassRefPtr<Element> element, TypeBuilder::CSS::StyleSheetOrigin::Enum origin, Listener* listener)
+{
+ return adoptRef(new InspectorStyleSheetForInlineStyle(pageAgent, id, element, origin, listener));
+}
+
+InspectorStyleSheetForInlineStyle::InspectorStyleSheetForInlineStyle(InspectorPageAgent* pageAgent, const String& id, PassRefPtr<Element> element, TypeBuilder::CSS::StyleSheetOrigin::Enum origin, Listener* listener)
+ : InspectorStyleSheet(pageAgent, id, 0, origin, "", listener)
+ , m_element(element)
+ , m_ruleSourceData(0)
+ , m_isStyleTextValid(false)
+{
+ ASSERT(m_element);
+ m_inspectorStyle = InspectorStyle::create(InspectorCSSId(id, 0), inlineStyle(), this);
+ m_styleText = m_element->isStyledElement() ? m_element->getAttribute("style").string() : String();
+}
+
+void InspectorStyleSheetForInlineStyle::didModifyElementAttribute()
+{
+ m_isStyleTextValid = false;
+ if (m_element->isStyledElement() && m_element->style() != m_inspectorStyle->cssStyle())
+ m_inspectorStyle = InspectorStyle::create(InspectorCSSId(id(), 0), inlineStyle(), this);
+ m_ruleSourceData.clear();
+}
+
+bool InspectorStyleSheetForInlineStyle::getText(String* result) const
+{
+ if (!m_isStyleTextValid) {
+ m_styleText = elementStyleText();
+ m_isStyleTextValid = true;
+ }
+ *result = m_styleText;
+ return true;
+}
+
+bool InspectorStyleSheetForInlineStyle::setStyleText(CSSStyleDeclaration* style, const String& text)
+{
+ ASSERT_UNUSED(style, style == inlineStyle());
+ ExceptionCode ec = 0;
+
+ {
+ InspectorCSSAgent::InlineStyleOverrideScope overrideScope(m_element->ownerDocument());
+ m_element->setAttribute("style", text, ec);
+ }
+
+ m_styleText = text;
+ m_isStyleTextValid = true;
+ m_ruleSourceData.clear();
+ return !ec;
+}
+
+PassOwnPtr<Vector<size_t> > InspectorStyleSheetForInlineStyle::lineEndings() const
+{
+ return ContentSearchUtils::lineEndings(elementStyleText());
+}
+
+Document* InspectorStyleSheetForInlineStyle::ownerDocument() const
+{
+ return m_element->document();
+}
+
+bool InspectorStyleSheetForInlineStyle::ensureParsedDataReady()
+{
+ // The "style" property value can get changed indirectly, e.g. via element.style.borderWidth = "2px".
+ const String& currentStyleText = elementStyleText();
+ if (m_styleText != currentStyleText) {
+ m_ruleSourceData.clear();
+ m_styleText = currentStyleText;
+ m_isStyleTextValid = true;
+ }
+
+ if (m_ruleSourceData)
+ return true;
+
+ m_ruleSourceData = getStyleAttributeData();
+
+ bool success = !!m_ruleSourceData;
+ if (!success) {
+ m_ruleSourceData = CSSRuleSourceData::create(CSSRuleSourceData::STYLE_RULE);
+ return false;
+ }
+
+ return true;
+}
+
+PassRefPtr<InspectorStyle> InspectorStyleSheetForInlineStyle::inspectorStyleForId(const InspectorCSSId& id)
+{
+ ASSERT_UNUSED(id, !id.ordinal());
+ return m_inspectorStyle;
+}
+
+CSSStyleDeclaration* InspectorStyleSheetForInlineStyle::inlineStyle() const
+{
+ return m_element->style();
+}
+
+const String& InspectorStyleSheetForInlineStyle::elementStyleText() const
+{
+ return m_element->getAttribute("style").string();
+}
+
+PassRefPtr<CSSRuleSourceData> InspectorStyleSheetForInlineStyle::getStyleAttributeData() const
+{
+ if (!m_element->isStyledElement())
+ return 0;
+
+ if (m_styleText.isEmpty()) {
+ RefPtr<CSSRuleSourceData> result = CSSRuleSourceData::create(CSSRuleSourceData::STYLE_RULE);
+ result->ruleBodyRange.start = 0;
+ result->ruleBodyRange.end = 0;
+ return result.release();
+ }
+
+ RefPtr<StylePropertySet> tempDeclaration = StylePropertySet::create();
+ RuleSourceDataList ruleSourceDataResult;
+ StyleSheetHandler handler(m_styleText, m_element->document(), m_element->document()->elementSheet()->contents(), &ruleSourceDataResult);
+ createCSSParser(m_element->document())->parseDeclaration(tempDeclaration.get(), m_styleText, &handler, m_element->document()->elementSheet()->contents());
+ return ruleSourceDataResult.first().release();
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorStyleSheet.h b/Source/core/inspector/InspectorStyleSheet.h
new file mode 100644
index 0000000..1994981
--- /dev/null
+++ b/Source/core/inspector/InspectorStyleSheet.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2010, Google 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 InspectorStyleSheet_h
+#define InspectorStyleSheet_h
+
+#include "InspectorTypeBuilder.h"
+#include "core/css/CSSPropertySourceData.h"
+#include "core/css/CSSStyleDeclaration.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/inspector/InspectorStyleTextEditor.h"
+#include "core/inspector/InspectorValues.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+class ParsedStyleSheet;
+
+namespace WebCore {
+
+class CSSRuleList;
+class CSSStyleDeclaration;
+class CSSStyleRule;
+class CSSStyleSheet;
+class Document;
+class Element;
+class InspectorPageAgent;
+class InspectorStyleSheet;
+class Node;
+
+
+typedef String ErrorString;
+
+class InspectorCSSId {
+public:
+ InspectorCSSId()
+ : m_ordinal(0)
+ {
+ }
+
+ explicit InspectorCSSId(RefPtr<InspectorObject> value)
+ {
+ if (!value->getString("styleSheetId", &m_styleSheetId))
+ return;
+
+ RefPtr<InspectorValue> ordinalValue = value->get("ordinal");
+ if (!ordinalValue || !ordinalValue->asNumber(&m_ordinal))
+ m_styleSheetId = "";
+ }
+
+ InspectorCSSId(const String& styleSheetId, unsigned ordinal)
+ : m_styleSheetId(styleSheetId)
+ , m_ordinal(ordinal)
+ {
+ }
+
+ bool isEmpty() const { return m_styleSheetId.isEmpty(); }
+
+ const String& styleSheetId() const { return m_styleSheetId; }
+ unsigned ordinal() const { return m_ordinal; }
+
+ // ID type is either TypeBuilder::CSS::CSSStyleId or TypeBuilder::CSS::CSSRuleId.
+ template<typename ID>
+ PassRefPtr<ID> asProtocolValue() const
+ {
+ if (isEmpty())
+ return 0;
+
+ RefPtr<ID> result = ID::create()
+ .setStyleSheetId(m_styleSheetId)
+ .setOrdinal(m_ordinal);
+ return result.release();
+ }
+
+private:
+ String m_styleSheetId;
+ unsigned m_ordinal;
+};
+
+struct InspectorStyleProperty {
+ explicit InspectorStyleProperty(CSSPropertySourceData sourceData)
+ : sourceData(sourceData)
+ , hasSource(true)
+ {
+ }
+
+ InspectorStyleProperty(CSSPropertySourceData sourceData, bool hasSource)
+ : sourceData(sourceData)
+ , hasSource(hasSource)
+ {
+ }
+
+ void setRawTextFromStyleDeclaration(const String& styleDeclaration)
+ {
+ unsigned start = sourceData.range.start;
+ unsigned end = sourceData.range.end;
+ ASSERT(start < end);
+ ASSERT(end <= styleDeclaration.length());
+ rawText = styleDeclaration.substring(start, end - start);
+ }
+
+ bool hasRawText() const { return !rawText.isEmpty(); }
+
+ CSSPropertySourceData sourceData;
+ bool hasSource;
+ String rawText;
+};
+
+class InspectorStyle : public RefCounted<InspectorStyle> {
+public:
+ static PassRefPtr<InspectorStyle> create(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet);
+ virtual ~InspectorStyle();
+
+ CSSStyleDeclaration* cssStyle() const { return m_style.get(); }
+ PassRefPtr<TypeBuilder::CSS::CSSStyle> buildObjectForStyle() const;
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> > buildArrayForComputedStyle() const;
+ bool setPropertyText(unsigned index, const String& text, bool overwrite, String* oldText, ExceptionCode&);
+ bool toggleProperty(unsigned index, bool disable, ExceptionCode&);
+ bool styleText(String* result) const;
+
+private:
+ InspectorStyle(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet);
+
+ void populateAllProperties(Vector<InspectorStyleProperty>& result) const;
+ PassRefPtr<TypeBuilder::CSS::CSSStyle> styleWithProperties() const;
+ PassRefPtr<CSSRuleSourceData> extractSourceData() const;
+ bool applyStyleText(const String&);
+ String shorthandValue(const String& shorthandProperty) const;
+ String shorthandPriority(const String& shorthandProperty) const;
+ Vector<String> longhandProperties(const String& shorthandProperty) const;
+ NewLineAndWhitespace& newLineAndWhitespaceDelimiters() const;
+ inline Document* ownerDocument() const;
+
+ InspectorCSSId m_styleId;
+ RefPtr<CSSStyleDeclaration> m_style;
+ InspectorStyleSheet* m_parentStyleSheet;
+ mutable std::pair<String, String> m_format;
+ mutable bool m_formatAcquired;
+};
+
+class InspectorStyleSheet : public RefCounted<InspectorStyleSheet> {
+public:
+ class Listener {
+ public:
+ Listener() { }
+ virtual ~Listener() { }
+ virtual void styleSheetChanged(InspectorStyleSheet*) = 0;
+ };
+
+ typedef HashMap<CSSStyleDeclaration*, RefPtr<InspectorStyle> > InspectorStyleMap;
+ static PassRefPtr<InspectorStyleSheet> create(InspectorPageAgent*, const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, TypeBuilder::CSS::StyleSheetOrigin::Enum, const String& documentURL, Listener*);
+ static String styleSheetURL(CSSStyleSheet* pageStyleSheet);
+
+ virtual ~InspectorStyleSheet();
+
+ String id() const { return m_id; }
+ String finalURL() const;
+ bool canBind() const { return m_origin != TypeBuilder::CSS::StyleSheetOrigin::User_agent && m_origin != TypeBuilder::CSS::StyleSheetOrigin::User; }
+ CSSStyleSheet* pageStyleSheet() const { return m_pageStyleSheet.get(); }
+ bool isReparsing() const { return m_isReparsing; }
+ void reparseStyleSheet(const String&);
+ bool setText(const String&, ExceptionCode&);
+ String ruleSelector(const InspectorCSSId&, ExceptionCode&);
+ bool setRuleSelector(const InspectorCSSId&, const String& selector, ExceptionCode&);
+ CSSStyleRule* addRule(const String& selector, ExceptionCode&);
+ bool deleteRule(const InspectorCSSId&, ExceptionCode&);
+ CSSStyleRule* ruleForId(const InspectorCSSId&) const;
+ PassRefPtr<TypeBuilder::CSS::CSSStyleSheetBody> buildObjectForStyleSheet();
+ PassRefPtr<TypeBuilder::CSS::CSSStyleSheetHeader> buildObjectForStyleSheetInfo();
+ PassRefPtr<TypeBuilder::CSS::CSSRule> buildObjectForRule(CSSStyleRule*);
+ PassRefPtr<TypeBuilder::CSS::CSSStyle> buildObjectForStyle(CSSStyleDeclaration*);
+ bool setStyleText(const InspectorCSSId&, const String& text, String* oldText, ExceptionCode&);
+ bool setPropertyText(const InspectorCSSId&, unsigned propertyIndex, const String& text, bool overwrite, String* oldPropertyText, ExceptionCode&);
+ bool toggleProperty(const InspectorCSSId&, unsigned propertyIndex, bool disable, ExceptionCode&);
+
+ virtual bool getText(String* result) const;
+ virtual CSSStyleDeclaration* styleForId(const InspectorCSSId&) const;
+ void fireStyleSheetChanged();
+
+ InspectorCSSId ruleId(CSSStyleRule*) const;
+ InspectorCSSId styleId(CSSStyleDeclaration* style) const { return ruleOrStyleId(style); }
+
+protected:
+ InspectorStyleSheet(InspectorPageAgent*, const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, TypeBuilder::CSS::StyleSheetOrigin::Enum, const String& documentURL, Listener*);
+
+ InspectorCSSId ruleOrStyleId(CSSStyleDeclaration* style) const;
+ virtual Document* ownerDocument() const;
+ virtual PassRefPtr<CSSRuleSourceData> ruleSourceDataFor(CSSStyleDeclaration* style) const;
+ virtual unsigned ruleIndexByStyle(CSSStyleDeclaration*) const;
+ virtual bool ensureParsedDataReady();
+ virtual PassRefPtr<InspectorStyle> inspectorStyleForId(const InspectorCSSId&);
+
+ // Also accessed by friend class InspectorStyle.
+ virtual bool setStyleText(CSSStyleDeclaration*, const String&);
+ virtual PassOwnPtr<Vector<size_t> > lineEndings() const;
+
+private:
+ typedef Vector<RefPtr<CSSStyleRule> > CSSStyleRuleVector;
+ friend class InspectorStyle;
+
+ static void collectFlatRules(PassRefPtr<CSSRuleList>, CSSStyleRuleVector* result);
+ bool checkPageStyleSheet(ExceptionCode&) const;
+ bool ensureText() const;
+ bool ensureSourceData();
+ void ensureFlatRules() const;
+ bool styleSheetTextWithChangedStyle(CSSStyleDeclaration*, const String& newStyleText, String* result);
+ void revalidateStyle(CSSStyleDeclaration*);
+ bool originalStyleSheetText(String* result) const;
+ bool resourceStyleSheetText(String* result) const;
+ bool inlineStyleSheetText(String* result) const;
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > buildArrayForRuleList(CSSRuleList*);
+ PassRefPtr<TypeBuilder::CSS::SelectorList> buildObjectForSelectorList(CSSStyleRule*);
+
+ InspectorPageAgent* m_pageAgent;
+ String m_id;
+ RefPtr<CSSStyleSheet> m_pageStyleSheet;
+ TypeBuilder::CSS::StyleSheetOrigin::Enum m_origin;
+ String m_documentURL;
+ bool m_isRevalidating;
+ bool m_isReparsing;
+ ParsedStyleSheet* m_parsedStyleSheet;
+ mutable CSSStyleRuleVector m_flatRules;
+ Listener* m_listener;
+};
+
+class InspectorStyleSheetForInlineStyle : public InspectorStyleSheet {
+public:
+ static PassRefPtr<InspectorStyleSheetForInlineStyle> create(InspectorPageAgent*, const String& id, PassRefPtr<Element>, TypeBuilder::CSS::StyleSheetOrigin::Enum, Listener*);
+
+ void didModifyElementAttribute();
+ virtual bool getText(String* result) const;
+ virtual CSSStyleDeclaration* styleForId(const InspectorCSSId& id) const { ASSERT_UNUSED(id, !id.ordinal()); return inlineStyle(); }
+
+protected:
+ InspectorStyleSheetForInlineStyle(InspectorPageAgent*, const String& id, PassRefPtr<Element>, TypeBuilder::CSS::StyleSheetOrigin::Enum, Listener*);
+
+ virtual Document* ownerDocument() const;
+ virtual PassRefPtr<CSSRuleSourceData> ruleSourceDataFor(CSSStyleDeclaration* style) const { ASSERT_UNUSED(style, style == inlineStyle()); return m_ruleSourceData; }
+ virtual unsigned ruleIndexByStyle(CSSStyleDeclaration*) const { return 0; }
+ virtual bool ensureParsedDataReady();
+ virtual PassRefPtr<InspectorStyle> inspectorStyleForId(const InspectorCSSId&);
+
+ // Also accessed by friend class InspectorStyle.
+ virtual bool setStyleText(CSSStyleDeclaration*, const String&);
+ virtual PassOwnPtr<Vector<size_t> > lineEndings() const;
+
+private:
+ CSSStyleDeclaration* inlineStyle() const;
+ const String& elementStyleText() const;
+ PassRefPtr<CSSRuleSourceData> getStyleAttributeData() const;
+
+ RefPtr<Element> m_element;
+ RefPtr<CSSRuleSourceData> m_ruleSourceData;
+ RefPtr<InspectorStyle> m_inspectorStyle;
+
+ // Contains "style" attribute value.
+ mutable String m_styleText;
+ mutable bool m_isStyleTextValid;
+};
+
+
+} // namespace WebCore
+
+#endif // !defined(InspectorStyleSheet_h)
diff --git a/Source/core/inspector/InspectorStyleTextEditor.cpp b/Source/core/inspector/InspectorStyleTextEditor.cpp
new file mode 100644
index 0000000..f2701b2
--- /dev/null
+++ b/Source/core/inspector/InspectorStyleTextEditor.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2011, Google 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 "core/inspector/InspectorStyleTextEditor.h"
+
+#include "core/css/CSSPropertySourceData.h"
+#include "core/html/parser/HTMLParserIdioms.h"
+#include "core/inspector/InspectorStyleSheet.h"
+
+namespace WebCore {
+
+InspectorStyleTextEditor::InspectorStyleTextEditor(Vector<InspectorStyleProperty>* allProperties, const String& styleText, const NewLineAndWhitespace& format)
+ : m_allProperties(allProperties)
+ , m_styleText(styleText)
+ , m_format(format)
+{
+}
+
+void InspectorStyleTextEditor::insertProperty(unsigned index, const String& propertyText, unsigned styleBodyLength)
+{
+ long propertyStart = 0;
+
+ bool insertLast = true;
+ if (index < m_allProperties->size()) {
+ const InspectorStyleProperty& property = m_allProperties->at(index);
+ if (property.hasSource) {
+ propertyStart = property.sourceData.range.start;
+ // If inserting before a disabled property, it should be shifted, too.
+ insertLast = false;
+ }
+ }
+
+ bool insertFirstInSource = !m_allProperties->size() || !m_allProperties->at(0).hasSource;
+ bool insertLastInSource = true;
+ for (unsigned i = index, size = m_allProperties->size(); i < size; ++i) {
+ const InspectorStyleProperty& property = m_allProperties->at(i);
+ if (property.hasSource) {
+ insertLastInSource = false;
+ break;
+ }
+ }
+
+ String textToSet = propertyText;
+
+ int formattingPrependOffset = 0;
+ if (insertLast && !insertFirstInSource) {
+ propertyStart = styleBodyLength;
+ if (propertyStart && textToSet.length()) {
+ const UChar* characters = m_styleText.characters();
+
+ long curPos = propertyStart - 1; // The last position of style declaration, since propertyStart points past one.
+ while (curPos && isHTMLSpace(characters[curPos]))
+ --curPos;
+ if (curPos) {
+ bool terminated = characters[curPos] == ';' || (characters[curPos] == '/' && characters[curPos - 1] == '*');
+ if (!terminated) {
+ // Prepend a ";" to the property text if appending to a style declaration where
+ // the last property has no trailing ";".
+ textToSet.insert(";", 0);
+ formattingPrependOffset = 1;
+ }
+ }
+ }
+ }
+
+ const String& formatLineFeed = m_format.first;
+ const String& formatPropertyPrefix = m_format.second;
+ if (insertLastInSource) {
+ long formatPropertyPrefixLength = formatPropertyPrefix.length();
+ if (!formattingPrependOffset && (propertyStart < formatPropertyPrefixLength || m_styleText.substring(propertyStart - formatPropertyPrefixLength, formatPropertyPrefixLength) != formatPropertyPrefix)) {
+ textToSet.insert(formatPropertyPrefix, formattingPrependOffset);
+ if (!propertyStart || !isHTMLLineBreak(m_styleText[propertyStart - 1]))
+ textToSet.insert(formatLineFeed, formattingPrependOffset);
+ }
+ if (!isHTMLLineBreak(m_styleText[propertyStart]))
+ textToSet.append(formatLineFeed);
+ } else {
+ String fullPrefix = formatLineFeed + formatPropertyPrefix;
+ long fullPrefixLength = fullPrefix.length();
+ textToSet.append(fullPrefix);
+ if (insertFirstInSource && (propertyStart < fullPrefixLength || m_styleText.substring(propertyStart - fullPrefixLength, fullPrefixLength) != fullPrefix))
+ textToSet.insert(fullPrefix, formattingPrependOffset);
+ }
+ m_styleText.insert(textToSet, propertyStart);
+}
+
+void InspectorStyleTextEditor::replaceProperty(unsigned index, const String& newText)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(index < m_allProperties->size());
+ internalReplaceProperty(m_allProperties->at(index), newText);
+}
+
+void InspectorStyleTextEditor::removeProperty(unsigned index)
+{
+ replaceProperty(index, "");
+}
+
+void InspectorStyleTextEditor::enableProperty(unsigned index)
+{
+ InspectorStyleProperty& disabledProperty = m_allProperties->at(index);
+ ASSERT(disabledProperty.sourceData.disabled);
+ internalReplaceProperty(disabledProperty, disabledProperty.rawText.substring(2, disabledProperty.rawText.length() - 4).stripWhiteSpace());
+}
+
+void InspectorStyleTextEditor::disableProperty(unsigned index)
+{
+ ASSERT(!m_allProperties->at(index).sourceData.disabled);
+
+ InspectorStyleProperty& property = m_allProperties->at(index);
+ property.setRawTextFromStyleDeclaration(m_styleText);
+ property.sourceData.disabled = true;
+
+ internalReplaceProperty(property, "/* " + property.rawText + " */");
+}
+
+void InspectorStyleTextEditor::internalReplaceProperty(const InspectorStyleProperty& property, const String& newText)
+{
+ const SourceRange& range = property.sourceData.range;
+ long replaceRangeStart = range.start;
+ long replaceRangeEnd = range.end;
+ const UChar* characters = m_styleText.characters();
+ long newTextLength = newText.length();
+ String finalNewText = newText;
+
+ // Removing a property - remove preceding prefix.
+ String fullPrefix = m_format.first + m_format.second;
+ long fullPrefixLength = fullPrefix.length();
+ if (!newTextLength && fullPrefixLength) {
+ if (replaceRangeStart >= fullPrefixLength && m_styleText.substring(replaceRangeStart - fullPrefixLength, fullPrefixLength) == fullPrefix)
+ replaceRangeStart -= fullPrefixLength;
+ } else if (newTextLength) {
+ if (isHTMLLineBreak(newText.characters()[newTextLength - 1])) {
+ // Coalesce newlines of the original and new property values (to avoid a lot of blank lines while incrementally applying property values).
+ bool foundNewline = false;
+ bool isLastNewline = false;
+ int i;
+ int textLength = m_styleText.length();
+ for (i = replaceRangeEnd; i < textLength && isSpaceOrNewline(characters[i]); ++i) {
+ isLastNewline = isHTMLLineBreak(characters[i]);
+ if (isLastNewline)
+ foundNewline = true;
+ else if (foundNewline && !isLastNewline) {
+ replaceRangeEnd = i;
+ break;
+ }
+ }
+ if (foundNewline && isLastNewline)
+ replaceRangeEnd = i;
+ }
+
+ if (fullPrefixLength > replaceRangeStart || m_styleText.substring(replaceRangeStart - fullPrefixLength, fullPrefixLength) != fullPrefix)
+ finalNewText.insert(fullPrefix, 0);
+ }
+
+ int replacedLength = replaceRangeEnd - replaceRangeStart;
+ m_styleText.replace(replaceRangeStart, replacedLength, finalNewText);
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorStyleTextEditor.h b/Source/core/inspector/InspectorStyleTextEditor.h
new file mode 100644
index 0000000..5fdab78
--- /dev/null
+++ b/Source/core/inspector/InspectorStyleTextEditor.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011, Google 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 InspectorStyleTextEditor_h
+#define InspectorStyleTextEditor_h
+
+#include "core/css/CSSPropertySourceData.h"
+
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+
+struct InspectorStyleProperty;
+struct SourceRange;
+
+typedef std::pair<String, String> NewLineAndWhitespace;
+
+class InspectorStyleTextEditor {
+public:
+ InspectorStyleTextEditor(Vector<InspectorStyleProperty>* allProperties,const String& styleText, const NewLineAndWhitespace& format);
+ void insertProperty(unsigned index, const String& propertyText, unsigned styleBodyLength);
+ void replaceProperty(unsigned index, const String& newText);
+ void removeProperty(unsigned index);
+ void enableProperty(unsigned index);
+ void disableProperty(unsigned index);
+ const String& styleText() const { return m_styleText; }
+
+private:
+ void internalReplaceProperty(const InspectorStyleProperty&, const String& newText);
+
+ Vector<InspectorStyleProperty>* m_allProperties;
+ String m_styleText;
+ const std::pair<String, String> m_format;
+};
+
+
+} // namespace WebCore
+
+#endif // !defined(InspectorStyleTextEditor_h)
diff --git a/Source/core/inspector/InspectorTimelineAgent.cpp b/Source/core/inspector/InspectorTimelineAgent.cpp
new file mode 100644
index 0000000..bf18d07
--- /dev/null
+++ b/Source/core/inspector/InspectorTimelineAgent.cpp
@@ -0,0 +1,800 @@
+/*
+* Copyright (C) 2013 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 "core/inspector/InspectorTimelineAgent.h"
+
+#include "InspectorFrontend.h"
+#include "core/dom/Event.h"
+#include "core/inspector/IdentifiersFactory.h"
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorCounters.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/InspectorMemoryAgent.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/inspector/TimelineRecordFactory.h"
+#include "core/inspector/TimelineTraceEventProcessor.h"
+#include "core/loader/DocumentLoader.h"
+#include "core/page/DOMWindow.h"
+#include "core/page/Frame.h"
+#include "core/page/FrameView.h"
+#include "core/platform/MemoryUsageSupport.h"
+#include "core/platform/graphics/IntRect.h"
+#include "core/platform/network/ResourceRequest.h"
+#include "core/platform/network/ResourceResponse.h"
+#include "core/rendering/RenderObject.h"
+#include "core/rendering/RenderView.h"
+#include "core/xml/XMLHttpRequest.h"
+
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+namespace TimelineAgentState {
+static const char timelineAgentEnabled[] = "timelineAgentEnabled";
+static const char timelineMaxCallStackDepth[] = "timelineMaxCallStackDepth";
+static const char includeDomCounters[] = "includeDomCounters";
+static const char includeNativeMemoryStatistics[] = "includeNativeMemoryStatistics";
+}
+
+// Must be kept in sync with WebInspector.TimelineModel.RecordType in TimelineModel.js
+namespace TimelineRecordType {
+static const char Program[] = "Program";
+
+static const char EventDispatch[] = "EventDispatch";
+static const char BeginFrame[] = "BeginFrame";
+static const char ScheduleStyleRecalculation[] = "ScheduleStyleRecalculation";
+static const char RecalculateStyles[] = "RecalculateStyles";
+static const char InvalidateLayout[] = "InvalidateLayout";
+static const char Layout[] = "Layout";
+static const char Paint[] = "Paint";
+static const char ScrollLayer[] = "ScrollLayer";
+static const char ResizeImage[] = "ResizeImage";
+static const char CompositeLayers[] = "CompositeLayers";
+
+static const char ParseHTML[] = "ParseHTML";
+
+static const char TimerInstall[] = "TimerInstall";
+static const char TimerRemove[] = "TimerRemove";
+static const char TimerFire[] = "TimerFire";
+
+static const char EvaluateScript[] = "EvaluateScript";
+
+static const char MarkLoad[] = "MarkLoad";
+static const char MarkDOMContent[] = "MarkDOMContent";
+
+static const char TimeStamp[] = "TimeStamp";
+static const char Time[] = "Time";
+static const char TimeEnd[] = "TimeEnd";
+
+static const char ScheduleResourceRequest[] = "ScheduleResourceRequest";
+static const char ResourceSendRequest[] = "ResourceSendRequest";
+static const char ResourceReceiveResponse[] = "ResourceReceiveResponse";
+static const char ResourceReceivedData[] = "ResourceReceivedData";
+static const char ResourceFinish[] = "ResourceFinish";
+
+static const char XHRReadyStateChange[] = "XHRReadyStateChange";
+static const char XHRLoad[] = "XHRLoad";
+
+static const char FunctionCall[] = "FunctionCall";
+static const char GCEvent[] = "GCEvent";
+
+static const char RequestAnimationFrame[] = "RequestAnimationFrame";
+static const char CancelAnimationFrame[] = "CancelAnimationFrame";
+static const char FireAnimationFrame[] = "FireAnimationFrame";
+
+static const char WebSocketCreate[] = "WebSocketCreate";
+static const char WebSocketSendHandshakeRequest[] = "WebSocketSendHandshakeRequest";
+static const char WebSocketReceiveHandshakeResponse[] = "WebSocketReceiveHandshakeResponse";
+static const char WebSocketDestroy[] = "WebSocketDestroy";
+
+// Event names visible to other modules.
+const char DecodeImage[] = "DecodeImage";
+const char Rasterize[] = "Rasterize";
+}
+
+static Frame* frameForScriptExecutionContext(ScriptExecutionContext* context)
+{
+ Frame* frame = 0;
+ if (context->isDocument())
+ frame = toDocument(context)->frame();
+ return frame;
+}
+
+static bool eventHasListeners(const AtomicString& eventType, DOMWindow* window, Node* node, const EventPath& eventPath)
+{
+ if (window && window->hasEventListeners(eventType))
+ return true;
+
+ if (node->hasEventListeners(eventType))
+ return true;
+
+ for (size_t i = 0; i < eventPath.size(); i++) {
+ if (eventPath[i]->node()->hasEventListeners(eventType))
+ return true;
+ }
+
+ return false;
+}
+
+void TimelineTimeConverter::reset()
+{
+ m_startOffset = monotonicallyIncreasingTime() - currentTime();
+}
+
+void InspectorTimelineAgent::pushGCEventRecords()
+{
+ if (!m_gcEvents.size())
+ return;
+
+ GCEvents events = m_gcEvents;
+ m_gcEvents.clear();
+ for (GCEvents::iterator i = events.begin(); i != events.end(); ++i) {
+ RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(m_timeConverter.fromMonotonicallyIncreasingTime(i->startTime), m_maxCallStackDepth);
+ record->setObject("data", TimelineRecordFactory::createGCEventData(i->collectedBytes));
+ record->setNumber("endTime", m_timeConverter.fromMonotonicallyIncreasingTime(i->endTime));
+ addRecordToTimeline(record.release(), TimelineRecordType::GCEvent);
+ }
+}
+
+void InspectorTimelineAgent::didGC(double startTime, double endTime, size_t collectedBytesCount)
+{
+ m_gcEvents.append(GCEvent(startTime, endTime, collectedBytesCount));
+}
+
+InspectorTimelineAgent::~InspectorTimelineAgent()
+{
+ clearFrontend();
+}
+
+void InspectorTimelineAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->timeline();
+}
+
+void InspectorTimelineAgent::clearFrontend()
+{
+ ErrorString error;
+ stop(&error);
+ m_frontend = 0;
+}
+
+void InspectorTimelineAgent::restore()
+{
+ if (m_state->getBoolean(TimelineAgentState::timelineAgentEnabled)) {
+ m_maxCallStackDepth = m_state->getLong(TimelineAgentState::timelineMaxCallStackDepth);
+ ErrorString error;
+ bool includeDomCounters = m_state->getBoolean(TimelineAgentState::includeDomCounters);
+ bool includeNativeMemoryStatistics = m_state->getBoolean(TimelineAgentState::includeNativeMemoryStatistics);
+ start(&error, &m_maxCallStackDepth, &includeDomCounters, &includeNativeMemoryStatistics);
+ }
+}
+
+void InspectorTimelineAgent::start(ErrorString*, const int* maxCallStackDepth, const bool* includeDomCounters, const bool* includeNativeMemoryStatistics)
+{
+ if (!m_frontend)
+ return;
+
+ if (maxCallStackDepth && *maxCallStackDepth >= 0)
+ m_maxCallStackDepth = *maxCallStackDepth;
+ else
+ m_maxCallStackDepth = 5;
+ m_state->setLong(TimelineAgentState::timelineMaxCallStackDepth, m_maxCallStackDepth);
+ m_state->setBoolean(TimelineAgentState::includeDomCounters, includeDomCounters && *includeDomCounters);
+ m_state->setBoolean(TimelineAgentState::includeNativeMemoryStatistics, includeNativeMemoryStatistics && *includeNativeMemoryStatistics);
+ m_timeConverter.reset();
+
+ m_instrumentingAgents->setInspectorTimelineAgent(this);
+ ScriptGCEvent::addEventListener(this);
+ m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, true);
+ if (m_client && m_pageAgent)
+ m_traceEventProcessor = adoptRef(new TimelineTraceEventProcessor(m_weakFactory.createWeakPtr(), m_client));
+}
+
+void InspectorTimelineAgent::stop(ErrorString*)
+{
+ if (!m_state->getBoolean(TimelineAgentState::timelineAgentEnabled))
+ return;
+
+ m_traceEventProcessor->shutdown();
+ m_traceEventProcessor.clear();
+ m_weakFactory.revokeAll();
+ m_instrumentingAgents->setInspectorTimelineAgent(0);
+ ScriptGCEvent::removeEventListener(this);
+
+ clearRecordStack();
+ m_gcEvents.clear();
+
+ m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, false);
+}
+
+void InspectorTimelineAgent::didBeginFrame()
+{
+ TRACE_EVENT_INSTANT0("webkit", InstrumentationEvents::BeginFrame);
+ m_pendingFrameRecord = TimelineRecordFactory::createGenericRecord(timestamp(), 0);
+}
+
+void InspectorTimelineAgent::didCancelFrame()
+{
+ m_pendingFrameRecord.clear();
+}
+
+bool InspectorTimelineAgent::willCallFunction(ScriptExecutionContext* context, const String& scriptName, int scriptLine)
+{
+ pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frameForScriptExecutionContext(context));
+ return true;
+}
+
+void InspectorTimelineAgent::didCallFunction()
+{
+ didCompleteCurrentRecord(TimelineRecordType::FunctionCall);
+}
+
+bool InspectorTimelineAgent::willDispatchEvent(Document* document, const Event& event, DOMWindow* window, Node* node, const EventPath& eventPath)
+{
+ if (!eventHasListeners(event.type(), window, node, eventPath))
+ return false;
+
+ pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, document->frame());
+ return true;
+}
+
+bool InspectorTimelineAgent::willDispatchEventOnWindow(const Event& event, DOMWindow* window)
+{
+ if (!window->hasEventListeners(event.type()))
+ return false;
+ pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, window->frame());
+ return true;
+}
+
+void InspectorTimelineAgent::didDispatchEvent()
+{
+ didCompleteCurrentRecord(TimelineRecordType::EventDispatch);
+}
+
+void InspectorTimelineAgent::didDispatchEventOnWindow()
+{
+ didDispatchEvent();
+}
+
+void InspectorTimelineAgent::didInvalidateLayout(Frame* frame)
+{
+ appendRecord(InspectorObject::create(), TimelineRecordType::InvalidateLayout, true, frame);
+}
+
+bool InspectorTimelineAgent::willLayout(Frame* frame)
+{
+ RenderObject* root = frame->view()->layoutRoot();
+ bool partialLayout = !!root;
+
+ if (!partialLayout)
+ root = frame->contentRenderer();
+
+ unsigned dirtyObjects = 0;
+ unsigned totalObjects = 0;
+ for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
+ ++totalObjects;
+ if (o->needsLayout())
+ ++dirtyObjects;
+ }
+ pushCurrentRecord(TimelineRecordFactory::createLayoutData(dirtyObjects, totalObjects, partialLayout), TimelineRecordType::Layout, true, frame);
+ return true;
+}
+
+void InspectorTimelineAgent::didLayout(RenderObject* root)
+{
+ if (m_recordStack.isEmpty())
+ return;
+ TimelineRecordEntry& entry = m_recordStack.last();
+ ASSERT(entry.type == TimelineRecordType::Layout);
+ Vector<FloatQuad> quads;
+ root->absoluteQuads(quads);
+ if (quads.size() >= 1)
+ TimelineRecordFactory::appendLayoutRoot(entry.data.get(), quads[0]);
+ else
+ ASSERT_NOT_REACHED();
+ didCompleteCurrentRecord(TimelineRecordType::Layout);
+}
+
+void InspectorTimelineAgent::didScheduleStyleRecalculation(Document* document)
+{
+ appendRecord(InspectorObject::create(), TimelineRecordType::ScheduleStyleRecalculation, true, document->frame());
+}
+
+bool InspectorTimelineAgent::willRecalculateStyle(Document* document)
+{
+ pushCurrentRecord(InspectorObject::create(), TimelineRecordType::RecalculateStyles, true, document->frame());
+ ASSERT(!m_styleRecalcElementCounter);
+ return true;
+}
+
+void InspectorTimelineAgent::didRecalculateStyle()
+{
+ if (m_recordStack.isEmpty())
+ return;
+ TimelineRecordEntry& entry = m_recordStack.last();
+ ASSERT(entry.type == TimelineRecordType::RecalculateStyles);
+ TimelineRecordFactory::appendStyleRecalcDetails(entry.data.get(), m_styleRecalcElementCounter);
+ m_styleRecalcElementCounter = 0;
+ didCompleteCurrentRecord(TimelineRecordType::RecalculateStyles);
+}
+
+void InspectorTimelineAgent::didRecalculateStyleForElement()
+{
+ ++m_styleRecalcElementCounter;
+}
+
+void InspectorTimelineAgent::willPaint(Frame* frame)
+{
+ pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Paint, true, frame, true);
+}
+
+void InspectorTimelineAgent::didPaint(RenderObject* renderer, GraphicsContext*, const LayoutRect& clipRect)
+{
+ TimelineRecordEntry& entry = m_recordStack.last();
+ ASSERT(entry.type == TimelineRecordType::Paint);
+ FloatQuad quad;
+ localToPageQuad(*renderer, clipRect, &quad);
+ entry.data = TimelineRecordFactory::createPaintData(quad);
+ didCompleteCurrentRecord(TimelineRecordType::Paint);
+}
+
+void InspectorTimelineAgent::willScrollLayer(Frame* frame)
+{
+ pushCurrentRecord(InspectorObject::create(), TimelineRecordType::ScrollLayer, false, frame);
+}
+
+void InspectorTimelineAgent::didScrollLayer()
+{
+ didCompleteCurrentRecord(TimelineRecordType::ScrollLayer);
+}
+
+void InspectorTimelineAgent::willDecodeImage(const String& imageType)
+{
+ pushCurrentRecord(TimelineRecordFactory::createDecodeImageData(imageType), TimelineRecordType::DecodeImage, true, 0);
+}
+
+void InspectorTimelineAgent::didDecodeImage()
+{
+ didCompleteCurrentRecord(TimelineRecordType::DecodeImage);
+}
+
+void InspectorTimelineAgent::willResizeImage(bool shouldCache)
+{
+ pushCurrentRecord(TimelineRecordFactory::createResizeImageData(shouldCache), TimelineRecordType::ResizeImage, true, 0);
+}
+
+void InspectorTimelineAgent::didResizeImage()
+{
+ didCompleteCurrentRecord(TimelineRecordType::ResizeImage);
+}
+
+void InspectorTimelineAgent::willComposite()
+{
+ pushCurrentRecord(InspectorObject::create(), TimelineRecordType::CompositeLayers, false, 0);
+}
+
+void InspectorTimelineAgent::didComposite()
+{
+ didCompleteCurrentRecord(TimelineRecordType::CompositeLayers);
+}
+
+bool InspectorTimelineAgent::willWriteHTML(Document* document, unsigned startLine)
+{
+ pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(startLine), TimelineRecordType::ParseHTML, true, document->frame());
+ return true;
+}
+
+void InspectorTimelineAgent::didWriteHTML(unsigned endLine)
+{
+ if (!m_recordStack.isEmpty()) {
+ TimelineRecordEntry entry = m_recordStack.last();
+ entry.data->setNumber("endLine", endLine);
+ didCompleteCurrentRecord(TimelineRecordType::ParseHTML);
+ }
+}
+
+void InspectorTimelineAgent::didInstallTimer(ScriptExecutionContext* context, int timerId, int timeout, bool singleShot)
+{
+ appendRecord(TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot), TimelineRecordType::TimerInstall, true, frameForScriptExecutionContext(context));
+}
+
+void InspectorTimelineAgent::didRemoveTimer(ScriptExecutionContext* context, int timerId)
+{
+ appendRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerRemove, true, frameForScriptExecutionContext(context));
+}
+
+bool InspectorTimelineAgent::willFireTimer(ScriptExecutionContext* context, int timerId)
+{
+ pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerFire, false, frameForScriptExecutionContext(context));
+ return true;
+}
+
+void InspectorTimelineAgent::didFireTimer()
+{
+ didCompleteCurrentRecord(TimelineRecordType::TimerFire);
+}
+
+bool InspectorTimelineAgent::willDispatchXHRReadyStateChangeEvent(ScriptExecutionContext* context, XMLHttpRequest* request)
+{
+ if (!request->hasEventListeners(eventNames().readystatechangeEvent))
+ return false;
+ pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(request->url().string(), request->readyState()), TimelineRecordType::XHRReadyStateChange, false, frameForScriptExecutionContext(context));
+ return true;
+}
+
+void InspectorTimelineAgent::didDispatchXHRReadyStateChangeEvent()
+{
+ didCompleteCurrentRecord(TimelineRecordType::XHRReadyStateChange);
+}
+
+bool InspectorTimelineAgent::willDispatchXHRLoadEvent(ScriptExecutionContext* context, XMLHttpRequest* request)
+{
+ if (!request->hasEventListeners(eventNames().loadEvent))
+ return false;
+ pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(request->url()), TimelineRecordType::XHRLoad, true, frameForScriptExecutionContext(context));
+ return true;
+}
+
+void InspectorTimelineAgent::didDispatchXHRLoadEvent()
+{
+ didCompleteCurrentRecord(TimelineRecordType::XHRLoad);
+}
+
+bool InspectorTimelineAgent::willEvaluateScript(Frame* frame, const String& url, int lineNumber)
+{
+ pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript, true, frame);
+ return true;
+}
+
+void InspectorTimelineAgent::didEvaluateScript()
+{
+ didCompleteCurrentRecord(TimelineRecordType::EvaluateScript);
+}
+
+void InspectorTimelineAgent::didScheduleResourceRequest(Document* document, const String& url)
+{
+ appendRecord(TimelineRecordFactory::createScheduleResourceRequestData(url), TimelineRecordType::ScheduleResourceRequest, true, document->frame());
+}
+
+void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse&)
+{
+ String requestId = IdentifiersFactory::requestId(identifier);
+ appendRecord(TimelineRecordFactory::createResourceSendRequestData(requestId, request), TimelineRecordType::ResourceSendRequest, true, loader->frame());
+}
+
+bool InspectorTimelineAgent::willReceiveResourceData(Frame* frame, unsigned long identifier, int length)
+{
+ String requestId = IdentifiersFactory::requestId(identifier);
+ pushCurrentRecord(TimelineRecordFactory::createReceiveResourceData(requestId, length), TimelineRecordType::ResourceReceivedData, false, frame);
+ return true;
+}
+
+void InspectorTimelineAgent::didReceiveResourceData()
+{
+ didCompleteCurrentRecord(TimelineRecordType::ResourceReceivedData);
+}
+
+bool InspectorTimelineAgent::willReceiveResourceResponse(Frame* frame, unsigned long identifier, const ResourceResponse& response)
+{
+ String requestId = IdentifiersFactory::requestId(identifier);
+ pushCurrentRecord(TimelineRecordFactory::createResourceReceiveResponseData(requestId, response), TimelineRecordType::ResourceReceiveResponse, false, frame);
+ return true;
+}
+
+void InspectorTimelineAgent::didReceiveResourceResponse(unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
+{
+ didCompleteCurrentRecord(TimelineRecordType::ResourceReceiveResponse);
+}
+
+void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail, double finishTime, Frame* frame)
+{
+ appendRecord(TimelineRecordFactory::createResourceFinishData(IdentifiersFactory::requestId(identifier), didFail, finishTime * 1000), TimelineRecordType::ResourceFinish, false, frame);
+}
+
+void InspectorTimelineAgent::didFailLoading(unsigned long identifier, DocumentLoader* loader, const ResourceError& error)
+{
+ didFinishLoadingResource(identifier, true, 0, loader->frame());
+}
+
+void InspectorTimelineAgent::didTimeStamp(Frame* frame, const String& message)
+{
+ appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frame);
+}
+
+void InspectorTimelineAgent::time(Frame* frame, const String& message)
+{
+ appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::Time, true, frame);
+}
+
+void InspectorTimelineAgent::timeEnd(Frame* frame, const String& message)
+{
+ appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeEnd, true, frame);
+}
+
+void InspectorTimelineAgent::didMarkDOMContentEvent(Frame* frame)
+{
+ bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
+ appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkDOMContent, false, frame);
+}
+
+void InspectorTimelineAgent::didMarkLoadEvent(Frame* frame)
+{
+ bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
+ appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkLoad, false, frame);
+}
+
+void InspectorTimelineAgent::didCommitLoad()
+{
+ clearRecordStack();
+}
+
+void InspectorTimelineAgent::didRequestAnimationFrame(Document* document, int callbackId)
+{
+ appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::RequestAnimationFrame, true, document->frame());
+}
+
+void InspectorTimelineAgent::didCancelAnimationFrame(Document* document, int callbackId)
+{
+ appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::CancelAnimationFrame, true, document->frame());
+}
+
+bool InspectorTimelineAgent::willFireAnimationFrame(Document* document, int callbackId)
+{
+ pushCurrentRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::FireAnimationFrame, false, document->frame());
+ return true;
+}
+
+void InspectorTimelineAgent::didFireAnimationFrame()
+{
+ didCompleteCurrentRecord(TimelineRecordType::FireAnimationFrame);
+}
+
+void InspectorTimelineAgent::willProcessTask()
+{
+ pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Program, false, 0);
+}
+
+void InspectorTimelineAgent::didProcessTask()
+{
+ didCompleteCurrentRecord(TimelineRecordType::Program);
+}
+
+void InspectorTimelineAgent::didCreateWebSocket(Document* document, unsigned long identifier, const KURL& url, const String& protocol)
+{
+ appendRecord(TimelineRecordFactory::createWebSocketCreateData(identifier, url, protocol), TimelineRecordType::WebSocketCreate, true, document->frame());
+}
+
+void InspectorTimelineAgent::willSendWebSocketHandshakeRequest(Document* document, unsigned long identifier, const WebSocketHandshakeRequest&)
+{
+ appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketSendHandshakeRequest, true, document->frame());
+}
+
+void InspectorTimelineAgent::didReceiveWebSocketHandshakeResponse(Document* document, unsigned long identifier, const WebSocketHandshakeResponse&)
+{
+ appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketReceiveHandshakeResponse, false, document->frame());
+}
+
+void InspectorTimelineAgent::didCloseWebSocket(Document* document, unsigned long identifier)
+{
+ appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketDestroy, true, document->frame());
+}
+
+void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<InspectorObject> record, const String& type)
+{
+ commitFrameRecord();
+ innerAddRecordToTimeline(record, type);
+}
+
+void InspectorTimelineAgent::innerAddRecordToTimeline(PassRefPtr<InspectorObject> prpRecord, const String& type)
+{
+ prpRecord->setString("type", type);
+ RefPtr<TypeBuilder::Timeline::TimelineEvent> record = TypeBuilder::Timeline::TimelineEvent::runtimeCast(prpRecord);
+ if (type == TimelineRecordType::Program)
+ setNativeHeapStatistics(record.get());
+ else
+ setDOMCounters(record.get());
+
+ if (m_recordStack.isEmpty())
+ sendEvent(record.release());
+ else {
+ TimelineRecordEntry parent = m_recordStack.last();
+ parent.children->pushObject(record.release());
+ }
+}
+
+static size_t getUsedHeapSize()
+{
+ HeapInfo info;
+ ScriptGCEvent::getHeapSize(info);
+ return info.usedJSHeapSize;
+}
+
+void InspectorTimelineAgent::setDOMCounters(TypeBuilder::Timeline::TimelineEvent* record)
+{
+ record->setUsedHeapSize(getUsedHeapSize());
+
+ if (m_state->getBoolean(TimelineAgentState::includeDomCounters)) {
+ int documentCount = 0;
+ int nodeCount = 0;
+ if (m_inspectorType == PageInspector) {
+ documentCount = InspectorCounters::counterValue(InspectorCounters::DocumentCounter);
+ nodeCount = InspectorCounters::counterValue(InspectorCounters::NodeCounter);
+ }
+ int listenerCount = ThreadLocalInspectorCounters::current().counterValue(ThreadLocalInspectorCounters::JSEventListenerCounter);
+ RefPtr<TypeBuilder::Timeline::DOMCounters> counters = TypeBuilder::Timeline::DOMCounters::create()
+ .setDocuments(documentCount)
+ .setNodes(nodeCount)
+ .setJsEventListeners(listenerCount);
+ record->setCounters(counters.release());
+ }
+}
+
+void InspectorTimelineAgent::setNativeHeapStatistics(TypeBuilder::Timeline::TimelineEvent* record)
+{
+ if (!m_memoryAgent)
+ return;
+ if (!m_state->getBoolean(TimelineAgentState::includeNativeMemoryStatistics))
+ return;
+ HashMap<String, size_t> map;
+ m_memoryAgent->getProcessMemoryDistributionMap(&map);
+ RefPtr<InspectorObject> stats = InspectorObject::create();
+ for (HashMap<String, size_t>::iterator it = map.begin(); it != map.end(); ++it)
+ stats->setNumber(it->key, it->value);
+ size_t privateBytes = 0;
+ size_t sharedBytes = 0;
+ MemoryUsageSupport::processMemorySizesInBytes(&privateBytes, &sharedBytes);
+ stats->setNumber("PrivateBytes", privateBytes);
+ record->setNativeHeapStatistics(stats.release());
+}
+
+void InspectorTimelineAgent::setFrameIdentifier(InspectorObject* record, Frame* frame)
+{
+ if (!frame || !m_pageAgent)
+ return;
+ String frameId;
+ if (frame && m_pageAgent)
+ frameId = m_pageAgent->frameId(frame);
+ record->setString("frameId", frameId);
+}
+
+void InspectorTimelineAgent::didCompleteCurrentRecord(const String& type)
+{
+ // An empty stack could merely mean that the timeline agent was turned on in the middle of
+ // an event. Don't treat as an error.
+ if (!m_recordStack.isEmpty()) {
+ if (m_platformInstrumentationClientInstalledAtStackDepth == m_recordStack.size()) {
+ m_platformInstrumentationClientInstalledAtStackDepth = 0;
+ PlatformInstrumentation::setClient(0);
+ }
+
+ pushGCEventRecords();
+ TimelineRecordEntry entry = m_recordStack.last();
+ m_recordStack.removeLast();
+ ASSERT(entry.type == type);
+ entry.record->setObject("data", entry.data);
+ entry.record->setArray("children", entry.children);
+ entry.record->setNumber("endTime", timestamp());
+ size_t usedHeapSizeDelta = getUsedHeapSize() - entry.usedHeapSizeAtStart;
+ if (usedHeapSizeDelta)
+ entry.record->setNumber("usedHeapSizeDelta", usedHeapSizeDelta);
+ addRecordToTimeline(entry.record, type);
+ }
+}
+
+InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorMemoryAgent* memoryAgent, InspectorCompositeState* state, InspectorType type, InspectorClient* client)
+ : InspectorBaseAgent<InspectorTimelineAgent>("Timeline", instrumentingAgents, state)
+ , m_pageAgent(pageAgent)
+ , m_memoryAgent(memoryAgent)
+ , m_frontend(0)
+ , m_id(1)
+ , m_maxCallStackDepth(5)
+ , m_platformInstrumentationClientInstalledAtStackDepth(0)
+ , m_inspectorType(type)
+ , m_client(client)
+ , m_weakFactory(this)
+ , m_styleRecalcElementCounter(0)
+{
+}
+
+void InspectorTimelineAgent::appendRecord(PassRefPtr<InspectorObject> data, const String& type, bool captureCallStack, Frame* frame)
+{
+ pushGCEventRecords();
+ RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0);
+ record->setObject("data", data);
+ setFrameIdentifier(record.get(), frame);
+ addRecordToTimeline(record.release(), type);
+}
+
+void InspectorTimelineAgent::sendEvent(PassRefPtr<InspectorObject> event)
+{
+ // FIXME: runtimeCast is a hack. We do it because we can't build TimelineEvent directly now.
+ RefPtr<TypeBuilder::Timeline::TimelineEvent> recordChecked = TypeBuilder::Timeline::TimelineEvent::runtimeCast(event);
+ m_frontend->eventRecorded(recordChecked.release());
+}
+
+void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, const String& type, bool captureCallStack, Frame* frame, bool hasLowLevelDetails)
+{
+ pushGCEventRecords();
+ commitFrameRecord();
+ RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0);
+ setFrameIdentifier(record.get(), frame);
+ m_recordStack.append(TimelineRecordEntry(record.release(), data, InspectorArray::create(), type, getUsedHeapSize()));
+ if (hasLowLevelDetails && !m_platformInstrumentationClientInstalledAtStackDepth && !PlatformInstrumentation::hasClient()) {
+ m_platformInstrumentationClientInstalledAtStackDepth = m_recordStack.size();
+ PlatformInstrumentation::setClient(this);
+ }
+}
+
+void InspectorTimelineAgent::commitFrameRecord()
+{
+ if (!m_pendingFrameRecord)
+ return;
+
+ m_pendingFrameRecord->setObject("data", InspectorObject::create());
+ innerAddRecordToTimeline(m_pendingFrameRecord.release(), TimelineRecordType::BeginFrame);
+}
+
+void InspectorTimelineAgent::clearRecordStack()
+{
+ if (m_platformInstrumentationClientInstalledAtStackDepth) {
+ m_platformInstrumentationClientInstalledAtStackDepth = 0;
+ PlatformInstrumentation::setClient(0);
+ }
+ m_pendingFrameRecord.clear();
+ m_recordStack.clear();
+ m_id++;
+}
+
+void InspectorTimelineAgent::localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad)
+{
+ Frame* frame = renderer.frame();
+ FrameView* view = frame->view();
+ FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect));
+ quad->setP1(view->contentsToRootView(roundedIntPoint(absolute.p1())));
+ quad->setP2(view->contentsToRootView(roundedIntPoint(absolute.p2())));
+ quad->setP3(view->contentsToRootView(roundedIntPoint(absolute.p3())));
+ quad->setP4(view->contentsToRootView(roundedIntPoint(absolute.p4())));
+}
+
+double InspectorTimelineAgent::timestamp()
+{
+ return m_timeConverter.fromMonotonicallyIncreasingTime(WTF::monotonicallyIncreasingTime());
+}
+
+Page* InspectorTimelineAgent::page()
+{
+ return m_pageAgent ? m_pageAgent->page() : 0;
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/InspectorTimelineAgent.h b/Source/core/inspector/InspectorTimelineAgent.h
new file mode 100644
index 0000000..62d0de9
--- /dev/null
+++ b/Source/core/inspector/InspectorTimelineAgent.h
@@ -0,0 +1,281 @@
+/*
+* Copyright (C) 2012 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 InspectorTimelineAgent_h
+#define InspectorTimelineAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptGCEvent.h"
+#include "core/dom/EventContext.h"
+#include "core/inspector/InspectorBaseAgent.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/ScriptGCEventListener.h"
+#include "core/platform/PlatformInstrumentation.h"
+#include "core/platform/graphics/LayoutRect.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+class DOMWindow;
+class Document;
+class DocumentLoader;
+class Event;
+class FloatQuad;
+class Frame;
+class GraphicsContext;
+class InspectorClient;
+class InspectorFrontend;
+class InspectorMemoryAgent;
+class InspectorPageAgent;
+class InspectorState;
+class InstrumentingAgents;
+class IntRect;
+class KURL;
+class Node;
+class Page;
+class RenderObject;
+class ResourceError;
+class ResourceLoader;
+class ResourceRequest;
+class ResourceResponse;
+class ScriptExecutionContext;
+class TimelineTraceEventProcessor;
+class WebSocketHandshakeRequest;
+class WebSocketHandshakeResponse;
+class XMLHttpRequest;
+
+typedef String ErrorString;
+
+namespace TimelineRecordType {
+extern const char DecodeImage[];
+extern const char Rasterize[];
+};
+
+class TimelineTimeConverter {
+public:
+ TimelineTimeConverter()
+ : m_startOffset(0)
+ {
+ }
+ double fromMonotonicallyIncreasingTime(double time) const { return (time - m_startOffset) * 1000.0; }
+ void reset();
+
+private:
+ double m_startOffset;
+};
+
+class InspectorTimelineAgent
+ : public InspectorBaseAgent<InspectorTimelineAgent>,
+ public ScriptGCEventListener,
+ public InspectorBackendDispatcher::TimelineCommandHandler,
+ public PlatformInstrumentationClient {
+ WTF_MAKE_NONCOPYABLE(InspectorTimelineAgent);
+public:
+ enum InspectorType { PageInspector, WorkerInspector };
+
+ static PassOwnPtr<InspectorTimelineAgent> create(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorMemoryAgent* memoryAgent, InspectorCompositeState* state, InspectorType type, InspectorClient* client)
+ {
+ return adoptPtr(new InspectorTimelineAgent(instrumentingAgents, pageAgent, memoryAgent, state, type, client));
+ }
+
+ ~InspectorTimelineAgent();
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+
+ virtual void start(ErrorString*, const int* maxCallStackDepth, const bool* includeDomCounters, const bool* includeNativeMemoryStatistics);
+ virtual void stop(ErrorString*);
+
+ int id() const { return m_id; }
+
+ void didCommitLoad();
+
+ // Methods called from WebCore.
+ bool willCallFunction(ScriptExecutionContext* context, const String& scriptName, int scriptLine);
+ void didCallFunction();
+
+ bool willDispatchEvent(Document* document, const Event& event, DOMWindow* window, Node* node, const EventPath& eventPath);
+ bool willDispatchEventOnWindow(const Event& event, DOMWindow* window);
+ void didDispatchEvent();
+ void didDispatchEventOnWindow();
+
+ void didBeginFrame();
+ void didCancelFrame();
+
+ void didInvalidateLayout(Frame*);
+ bool willLayout(Frame*);
+ void didLayout(RenderObject*);
+
+ void didScheduleStyleRecalculation(Document*);
+ bool willRecalculateStyle(Document*);
+ void didRecalculateStyle();
+ void didRecalculateStyleForElement();
+
+ void willPaint(Frame*);
+ void didPaint(RenderObject*, GraphicsContext*, const LayoutRect&);
+
+ void willScrollLayer(Frame*);
+ void didScrollLayer();
+
+ void willComposite();
+ void didComposite();
+
+ bool willWriteHTML(Document*, unsigned startLine);
+ void didWriteHTML(unsigned endLine);
+
+ void didInstallTimer(ScriptExecutionContext* context, int timerId, int timeout, bool singleShot);
+ void didRemoveTimer(ScriptExecutionContext* context, int timerId);
+ bool willFireTimer(ScriptExecutionContext* context, int timerId);
+ void didFireTimer();
+
+ bool willDispatchXHRReadyStateChangeEvent(ScriptExecutionContext* context, XMLHttpRequest* request);
+ void didDispatchXHRReadyStateChangeEvent();
+ bool willDispatchXHRLoadEvent(ScriptExecutionContext* context, XMLHttpRequest* request);
+ void didDispatchXHRLoadEvent();
+
+ bool willEvaluateScript(Frame*, const String&, int);
+ void didEvaluateScript();
+
+ void didTimeStamp(Frame*, const String&);
+ void didMarkDOMContentEvent(Frame*);
+ void didMarkLoadEvent(Frame*);
+
+ void time(Frame*, const String&);
+ void timeEnd(Frame*, const String&);
+
+ void didScheduleResourceRequest(Document*, const String& url);
+ void willSendResourceRequest(unsigned long, DocumentLoader*, const ResourceRequest&, const ResourceResponse&);
+ bool willReceiveResourceResponse(Frame*, unsigned long, const ResourceResponse&);
+ void didReceiveResourceResponse(unsigned long, DocumentLoader*, const ResourceResponse&, ResourceLoader*);
+ void didFinishLoadingResource(unsigned long, bool didFail, double finishTime, Frame*);
+ void didFailLoading(unsigned long identifier, DocumentLoader* loader, const ResourceError& error);
+ bool willReceiveResourceData(Frame*, unsigned long identifier, int length);
+ void didReceiveResourceData();
+
+ void didRequestAnimationFrame(Document*, int callbackId);
+ void didCancelAnimationFrame(Document*, int callbackId);
+ bool willFireAnimationFrame(Document*, int callbackId);
+ void didFireAnimationFrame();
+
+ void willProcessTask();
+ void didProcessTask();
+
+ void didCreateWebSocket(Document*, unsigned long identifier, const KURL&, const String& protocol);
+ void willSendWebSocketHandshakeRequest(Document*, unsigned long identifier, const WebSocketHandshakeRequest&);
+ void didReceiveWebSocketHandshakeResponse(Document*, unsigned long identifier, const WebSocketHandshakeResponse&);
+ void didCloseWebSocket(Document*, unsigned long identifier);
+
+ // ScriptGCEventListener methods.
+ virtual void didGC(double, double, size_t);
+
+ // PlatformInstrumentationClient methods.
+ virtual void willDecodeImage(const String& imageType) OVERRIDE;
+ virtual void didDecodeImage() OVERRIDE;
+ virtual void willResizeImage(bool shouldCache) OVERRIDE;
+ virtual void didResizeImage() OVERRIDE;
+
+private:
+ friend class TimelineRecordStack;
+ friend class TimelineTraceEventProcessor;
+
+ struct TimelineRecordEntry {
+ TimelineRecordEntry(PassRefPtr<InspectorObject> record, PassRefPtr<InspectorObject> data, PassRefPtr<InspectorArray> children, const String& type, size_t usedHeapSizeAtStart)
+ : record(record), data(data), children(children), type(type), usedHeapSizeAtStart(usedHeapSizeAtStart)
+ {
+ }
+ RefPtr<InspectorObject> record;
+ RefPtr<InspectorObject> data;
+ RefPtr<InspectorArray> children;
+ String type;
+ size_t usedHeapSizeAtStart;
+ };
+
+ InspectorTimelineAgent(InstrumentingAgents*, InspectorPageAgent*, InspectorMemoryAgent*, InspectorCompositeState*, InspectorType, InspectorClient*);
+
+ void sendEvent(PassRefPtr<InspectorObject>);
+ void appendRecord(PassRefPtr<InspectorObject> data, const String& type, bool captureCallStack, Frame*);
+ void pushCurrentRecord(PassRefPtr<InspectorObject>, const String& type, bool captureCallStack, Frame*, bool hasLowLevelDetails = false);
+
+ void setDOMCounters(TypeBuilder::Timeline::TimelineEvent* record);
+ void setNativeHeapStatistics(TypeBuilder::Timeline::TimelineEvent* record);
+ void setFrameIdentifier(InspectorObject* record, Frame*);
+ void pushGCEventRecords();
+
+ void didCompleteCurrentRecord(const String& type);
+
+ void setHeapSizeStatistics(InspectorObject* record);
+ void commitFrameRecord();
+
+ void addRecordToTimeline(PassRefPtr<InspectorObject>, const String& type);
+ void innerAddRecordToTimeline(PassRefPtr<InspectorObject>, const String& type);
+ void clearRecordStack();
+
+ void localToPageQuad(const RenderObject& renderer, const LayoutRect&, FloatQuad*);
+ const TimelineTimeConverter& timeConverter() const { return m_timeConverter; }
+ double timestamp();
+ Page* page();
+
+ InspectorPageAgent* m_pageAgent;
+ InspectorMemoryAgent* m_memoryAgent;
+ TimelineTimeConverter m_timeConverter;
+
+ InspectorFrontend::Timeline* m_frontend;
+ double m_timestampOffset;
+
+ Vector<TimelineRecordEntry> m_recordStack;
+
+ int m_id;
+ struct GCEvent {
+ GCEvent(double startTime, double endTime, size_t collectedBytes)
+ : startTime(startTime), endTime(endTime), collectedBytes(collectedBytes)
+ {
+ }
+ double startTime;
+ double endTime;
+ size_t collectedBytes;
+ };
+ typedef Vector<GCEvent> GCEvents;
+ GCEvents m_gcEvents;
+ int m_maxCallStackDepth;
+ unsigned m_platformInstrumentationClientInstalledAtStackDepth;
+ RefPtr<InspectorObject> m_pendingFrameRecord;
+ InspectorType m_inspectorType;
+ InspectorClient* m_client;
+ WeakPtrFactory<InspectorTimelineAgent> m_weakFactory;
+ RefPtr<TimelineTraceEventProcessor> m_traceEventProcessor;
+ unsigned m_styleRecalcElementCounter;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorTimelineAgent_h)
diff --git a/Source/core/inspector/InspectorValues.cpp b/Source/core/inspector/InspectorValues.cpp
new file mode 100644
index 0000000..c132a98
--- /dev/null
+++ b/Source/core/inspector/InspectorValues.cpp
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorValues.h"
+
+#include <wtf/DecimalNumber.h>
+#include <wtf/dtoa.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+namespace {
+
+static const int stackLimit = 1000;
+
+enum Token {
+ OBJECT_BEGIN,
+ OBJECT_END,
+ ARRAY_BEGIN,
+ ARRAY_END,
+ STRING,
+ NUMBER,
+ BOOL_TRUE,
+ BOOL_FALSE,
+ NULL_TOKEN,
+ LIST_SEPARATOR,
+ OBJECT_PAIR_SEPARATOR,
+ INVALID_TOKEN,
+};
+
+const char* const nullString = "null";
+const char* const trueString = "true";
+const char* const falseString = "false";
+
+bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEnd, const char* token)
+{
+ while (start < end && *token != '\0' && *start++ == *token++) { }
+ if (*token != '\0')
+ return false;
+ *tokenEnd = start;
+ return true;
+}
+
+bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool canHaveLeadingZeros)
+{
+ if (start == end)
+ return false;
+ bool haveLeadingZero = '0' == *start;
+ int length = 0;
+ while (start < end && '0' <= *start && *start <= '9') {
+ ++start;
+ ++length;
+ }
+ if (!length)
+ return false;
+ if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
+ return false;
+ *tokenEnd = start;
+ return true;
+}
+
+bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
+{
+ // We just grab the number here. We validate the size in DecodeNumber.
+ // According to RFC4627, a valid number is: [minus] int [frac] [exp]
+ if (start == end)
+ return false;
+ UChar c = *start;
+ if ('-' == c)
+ ++start;
+
+ if (!readInt(start, end, &start, false))
+ return false;
+ if (start == end) {
+ *tokenEnd = start;
+ return true;
+ }
+
+ // Optional fraction part
+ c = *start;
+ if ('.' == c) {
+ ++start;
+ if (!readInt(start, end, &start, true))
+ return false;
+ if (start == end) {
+ *tokenEnd = start;
+ return true;
+ }
+ c = *start;
+ }
+
+ // Optional exponent part
+ if ('e' == c || 'E' == c) {
+ ++start;
+ if (start == end)
+ return false;
+ c = *start;
+ if ('-' == c || '+' == c) {
+ ++start;
+ if (start == end)
+ return false;
+ }
+ if (!readInt(start, end, &start, true))
+ return false;
+ }
+
+ *tokenEnd = start;
+ return true;
+}
+
+bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd, int digits)
+{
+ if (end - start < digits)
+ return false;
+ for (int i = 0; i < digits; ++i) {
+ UChar c = *start++;
+ if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')))
+ return false;
+ }
+ *tokenEnd = start;
+ return true;
+}
+
+bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
+{
+ while (start < end) {
+ UChar c = *start++;
+ if ('\\' == c) {
+ c = *start++;
+ // Make sure the escaped char is valid.
+ switch (c) {
+ case 'x':
+ if (!readHexDigits(start, end, &start, 2))
+ return false;
+ break;
+ case 'u':
+ if (!readHexDigits(start, end, &start, 4))
+ return false;
+ break;
+ case '\\':
+ case '/':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'v':
+ case '"':
+ break;
+ default:
+ return false;
+ }
+ } else if ('"' == c) {
+ *tokenEnd = start;
+ return true;
+ }
+ }
+ return false;
+}
+
+Token parseToken(const UChar* start, const UChar* end, const UChar** tokenStart, const UChar** tokenEnd)
+{
+ while (start < end && isSpaceOrNewline(*start))
+ ++start;
+
+ if (start == end)
+ return INVALID_TOKEN;
+
+ *tokenStart = start;
+
+ switch (*start) {
+ case 'n':
+ if (parseConstToken(start, end, tokenEnd, nullString))
+ return NULL_TOKEN;
+ break;
+ case 't':
+ if (parseConstToken(start, end, tokenEnd, trueString))
+ return BOOL_TRUE;
+ break;
+ case 'f':
+ if (parseConstToken(start, end, tokenEnd, falseString))
+ return BOOL_FALSE;
+ break;
+ case '[':
+ *tokenEnd = start + 1;
+ return ARRAY_BEGIN;
+ case ']':
+ *tokenEnd = start + 1;
+ return ARRAY_END;
+ case ',':
+ *tokenEnd = start + 1;
+ return LIST_SEPARATOR;
+ case '{':
+ *tokenEnd = start + 1;
+ return OBJECT_BEGIN;
+ case '}':
+ *tokenEnd = start + 1;
+ return OBJECT_END;
+ case ':':
+ *tokenEnd = start + 1;
+ return OBJECT_PAIR_SEPARATOR;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ if (parseNumberToken(start, end, tokenEnd))
+ return NUMBER;
+ break;
+ case '"':
+ if (parseStringToken(start + 1, end, tokenEnd))
+ return STRING;
+ break;
+ }
+ return INVALID_TOKEN;
+}
+
+inline int hexToInt(UChar c)
+{
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+bool decodeString(const UChar* start, const UChar* end, StringBuilder* output)
+{
+ while (start < end) {
+ UChar c = *start++;
+ if ('\\' != c) {
+ output->append(c);
+ continue;
+ }
+ c = *start++;
+ switch (c) {
+ case '"':
+ case '/':
+ case '\\':
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+ case 'x':
+ c = (hexToInt(*start) << 4) +
+ hexToInt(*(start + 1));
+ start += 2;
+ break;
+ case 'u':
+ c = (hexToInt(*start) << 12) +
+ (hexToInt(*(start + 1)) << 8) +
+ (hexToInt(*(start + 2)) << 4) +
+ hexToInt(*(start + 3));
+ start += 4;
+ break;
+ default:
+ return false;
+ }
+ output->append(c);
+ }
+ return true;
+}
+
+bool decodeString(const UChar* start, const UChar* end, String* output)
+{
+ if (start == end) {
+ *output = "";
+ return true;
+ }
+ if (start > end)
+ return false;
+ StringBuilder buffer;
+ buffer.reserveCapacity(end - start);
+ if (!decodeString(start, end, &buffer))
+ return false;
+ *output = buffer.toString();
+ return true;
+}
+
+PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth)
+{
+ if (depth > stackLimit)
+ return 0;
+
+ RefPtr<InspectorValue> result;
+ const UChar* tokenStart;
+ const UChar* tokenEnd;
+ Token token = parseToken(start, end, &tokenStart, &tokenEnd);
+ switch (token) {
+ case INVALID_TOKEN:
+ return 0;
+ case NULL_TOKEN:
+ result = InspectorValue::null();
+ break;
+ case BOOL_TRUE:
+ result = InspectorBasicValue::create(true);
+ break;
+ case BOOL_FALSE:
+ result = InspectorBasicValue::create(false);
+ break;
+ case NUMBER: {
+ bool ok;
+ double value = charactersToDouble(tokenStart, tokenEnd - tokenStart, &ok);
+ if (!ok)
+ return 0;
+ result = InspectorBasicValue::create(value);
+ break;
+ }
+ case STRING: {
+ String value;
+ bool ok = decodeString(tokenStart + 1, tokenEnd - 1, &value);
+ if (!ok)
+ return 0;
+ result = InspectorString::create(value);
+ break;
+ }
+ case ARRAY_BEGIN: {
+ RefPtr<InspectorArray> array = InspectorArray::create();
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ while (token != ARRAY_END) {
+ RefPtr<InspectorValue> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
+ if (!arrayNode)
+ return 0;
+ array->pushValue(arrayNode);
+
+ // After a list value, we expect a comma or the end of the list.
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token == LIST_SEPARATOR) {
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token == ARRAY_END)
+ return 0;
+ } else if (token != ARRAY_END) {
+ // Unexpected value after list value. Bail out.
+ return 0;
+ }
+ }
+ if (token != ARRAY_END)
+ return 0;
+ result = array.release();
+ break;
+ }
+ case OBJECT_BEGIN: {
+ RefPtr<InspectorObject> object = InspectorObject::create();
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ while (token != OBJECT_END) {
+ if (token != STRING)
+ return 0;
+ String key;
+ if (!decodeString(tokenStart + 1, tokenEnd - 1, &key))
+ return 0;
+ start = tokenEnd;
+
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token != OBJECT_PAIR_SEPARATOR)
+ return 0;
+ start = tokenEnd;
+
+ RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, depth + 1);
+ if (!value)
+ return 0;
+ object->setValue(key, value);
+ start = tokenEnd;
+
+ // After a key/value pair, we expect a comma or the end of the
+ // object.
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token == LIST_SEPARATOR) {
+ start = tokenEnd;
+ token = parseToken(start, end, &tokenStart, &tokenEnd);
+ if (token == OBJECT_END)
+ return 0;
+ } else if (token != OBJECT_END) {
+ // Unexpected value after last object value. Bail out.
+ return 0;
+ }
+ }
+ if (token != OBJECT_END)
+ return 0;
+ result = object.release();
+ break;
+ }
+
+ default:
+ // We got a token that's not a value.
+ return 0;
+ }
+ *valueTokenEnd = tokenEnd;
+ return result.release();
+}
+
+inline bool escapeChar(UChar c, StringBuilder* dst)
+{
+ switch (c) {
+ case '\b': dst->append("\\b", 2); break;
+ case '\f': dst->append("\\f", 2); break;
+ case '\n': dst->append("\\n", 2); break;
+ case '\r': dst->append("\\r", 2); break;
+ case '\t': dst->append("\\t", 2); break;
+ case '\\': dst->append("\\\\", 2); break;
+ case '"': dst->append("\\\"", 2); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+inline void doubleQuoteString(const String& str, StringBuilder* dst)
+{
+ dst->append('"');
+ for (unsigned i = 0; i < str.length(); ++i) {
+ UChar c = str[i];
+ if (!escapeChar(c, dst)) {
+ if (c < 32 || c > 126 || c == '<' || c == '>') {
+ // 1. Escaping <, > to prevent script execution.
+ // 2. Technically, we could also pass through c > 126 as UTF8, but this
+ // is also optional. It would also be a pain to implement here.
+ unsigned int symbol = static_cast<unsigned int>(c);
+ String symbolCode = String::format("\\u%04X", symbol);
+ dst->append(symbolCode.characters(), symbolCode.length());
+ } else
+ dst->append(c);
+ }
+ }
+ dst->append('"');
+}
+
+} // anonymous namespace
+
+bool InspectorValue::asBoolean(bool*) const
+{
+ return false;
+}
+
+bool InspectorValue::asNumber(double*) const
+{
+ return false;
+}
+
+bool InspectorValue::asNumber(long*) const
+{
+ return false;
+}
+
+bool InspectorValue::asNumber(int*) const
+{
+ return false;
+}
+
+bool InspectorValue::asNumber(unsigned long*) const
+{
+ return false;
+}
+
+bool InspectorValue::asNumber(unsigned int*) const
+{
+ return false;
+}
+
+bool InspectorValue::asString(String*) const
+{
+ return false;
+}
+
+bool InspectorValue::asValue(RefPtr<InspectorValue>* output)
+{
+ *output = this;
+ return true;
+}
+
+bool InspectorValue::asObject(RefPtr<InspectorObject>*)
+{
+ return false;
+}
+
+bool InspectorValue::asArray(RefPtr<InspectorArray>*)
+{
+ return false;
+}
+
+PassRefPtr<InspectorObject> InspectorValue::asObject()
+{
+ return 0;
+}
+
+PassRefPtr<InspectorArray> InspectorValue::asArray()
+{
+ return 0;
+}
+
+PassRefPtr<InspectorValue> InspectorValue::parseJSON(const String& json)
+{
+ const UChar* start = json.characters();
+ const UChar* end = json.characters() + json.length();
+ const UChar *tokenEnd;
+ RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, 0);
+ if (!value || tokenEnd != end)
+ return 0;
+ return value.release();
+}
+
+String InspectorValue::toJSONString() const
+{
+ StringBuilder result;
+ result.reserveCapacity(512);
+ writeJSON(&result);
+ return result.toString();
+}
+
+void InspectorValue::writeJSON(StringBuilder* output) const
+{
+ ASSERT(m_type == TypeNull);
+ output->append(nullString, 4);
+}
+
+bool InspectorBasicValue::asBoolean(bool* output) const
+{
+ if (type() != TypeBoolean)
+ return false;
+ *output = m_boolValue;
+ return true;
+}
+
+bool InspectorBasicValue::asNumber(double* output) const
+{
+ if (type() != TypeNumber)
+ return false;
+ *output = m_doubleValue;
+ return true;
+}
+
+bool InspectorBasicValue::asNumber(long* output) const
+{
+ if (type() != TypeNumber)
+ return false;
+ *output = static_cast<long>(m_doubleValue);
+ return true;
+}
+
+bool InspectorBasicValue::asNumber(int* output) const
+{
+ if (type() != TypeNumber)
+ return false;
+ *output = static_cast<int>(m_doubleValue);
+ return true;
+}
+
+bool InspectorBasicValue::asNumber(unsigned long* output) const
+{
+ if (type() != TypeNumber)
+ return false;
+ *output = static_cast<unsigned long>(m_doubleValue);
+ return true;
+}
+
+bool InspectorBasicValue::asNumber(unsigned int* output) const
+{
+ if (type() != TypeNumber)
+ return false;
+ *output = static_cast<unsigned int>(m_doubleValue);
+ return true;
+}
+
+void InspectorBasicValue::writeJSON(StringBuilder* output) const
+{
+ ASSERT(type() == TypeBoolean || type() == TypeNumber);
+ if (type() == TypeBoolean) {
+ if (m_boolValue)
+ output->append(trueString, 4);
+ else
+ output->append(falseString, 5);
+ } else if (type() == TypeNumber) {
+ NumberToLStringBuffer buffer;
+ if (!std::isfinite(m_doubleValue)) {
+ output->append(nullString, 4);
+ return;
+ }
+ DecimalNumber decimal = m_doubleValue;
+ unsigned length = 0;
+ if (decimal.bufferLengthForStringDecimal() > WTF::NumberToStringBufferLength) {
+ // Not enough room for decimal. Use exponential format.
+ if (decimal.bufferLengthForStringExponential() > WTF::NumberToStringBufferLength) {
+ // Fallback for an abnormal case if it's too little even for exponential.
+ output->append("NaN", 3);
+ return;
+ }
+ length = decimal.toStringExponential(buffer, WTF::NumberToStringBufferLength);
+ } else
+ length = decimal.toStringDecimal(buffer, WTF::NumberToStringBufferLength);
+ output->append(buffer, length);
+ }
+}
+
+bool InspectorString::asString(String* output) const
+{
+ *output = m_stringValue;
+ return true;
+}
+
+void InspectorString::writeJSON(StringBuilder* output) const
+{
+ ASSERT(type() == TypeString);
+ doubleQuoteString(m_stringValue, output);
+}
+
+InspectorObjectBase::~InspectorObjectBase()
+{
+}
+
+bool InspectorObjectBase::asObject(RefPtr<InspectorObject>* output)
+{
+ COMPILE_ASSERT(sizeof(InspectorObject) == sizeof(InspectorObjectBase), cannot_cast);
+ *output = static_cast<InspectorObject*>(this);
+ return true;
+}
+
+PassRefPtr<InspectorObject> InspectorObjectBase::asObject()
+{
+ return openAccessors();
+}
+
+InspectorObject* InspectorObjectBase::openAccessors()
+{
+ COMPILE_ASSERT(sizeof(InspectorObject) == sizeof(InspectorObjectBase), cannot_cast);
+ return static_cast<InspectorObject*>(this);
+}
+
+bool InspectorObjectBase::getBoolean(const String& name, bool* output) const
+{
+ RefPtr<InspectorValue> value = get(name);
+ if (!value)
+ return false;
+ return value->asBoolean(output);
+}
+
+bool InspectorObjectBase::getString(const String& name, String* output) const
+{
+ RefPtr<InspectorValue> value = get(name);
+ if (!value)
+ return false;
+ return value->asString(output);
+}
+
+PassRefPtr<InspectorObject> InspectorObjectBase::getObject(const String& name) const
+{
+ PassRefPtr<InspectorValue> value = get(name);
+ if (!value)
+ return 0;
+ return value->asObject();
+}
+
+PassRefPtr<InspectorArray> InspectorObjectBase::getArray(const String& name) const
+{
+ PassRefPtr<InspectorValue> value = get(name);
+ if (!value)
+ return 0;
+ return value->asArray();
+}
+
+PassRefPtr<InspectorValue> InspectorObjectBase::get(const String& name) const
+{
+ Dictionary::const_iterator it = m_data.find(name);
+ if (it == m_data.end())
+ return 0;
+ return it->value;
+}
+
+void InspectorObjectBase::remove(const String& name)
+{
+ m_data.remove(name);
+ for (size_t i = 0; i < m_order.size(); ++i) {
+ if (m_order[i] == name) {
+ m_order.remove(i);
+ break;
+ }
+ }
+}
+
+void InspectorObjectBase::writeJSON(StringBuilder* output) const
+{
+ output->append('{');
+ for (size_t i = 0; i < m_order.size(); ++i) {
+ Dictionary::const_iterator it = m_data.find(m_order[i]);
+ ASSERT(it != m_data.end());
+ if (i)
+ output->append(',');
+ doubleQuoteString(it->key, output);
+ output->append(':');
+ it->value->writeJSON(output);
+ }
+ output->append('}');
+}
+
+InspectorObjectBase::InspectorObjectBase()
+ : InspectorValue(TypeObject)
+ , m_data()
+ , m_order()
+{
+}
+
+InspectorArrayBase::~InspectorArrayBase()
+{
+}
+
+bool InspectorArrayBase::asArray(RefPtr<InspectorArray>* output)
+{
+ COMPILE_ASSERT(sizeof(InspectorArrayBase) == sizeof(InspectorArray), cannot_cast);
+ *output = static_cast<InspectorArray*>(this);
+ return true;
+}
+
+PassRefPtr<InspectorArray> InspectorArrayBase::asArray()
+{
+ COMPILE_ASSERT(sizeof(InspectorArrayBase) == sizeof(InspectorArray), cannot_cast);
+ return static_cast<InspectorArray*>(this);
+}
+
+void InspectorArrayBase::writeJSON(StringBuilder* output) const
+{
+ output->append('[');
+ for (Vector<RefPtr<InspectorValue> >::const_iterator it = m_data.begin(); it != m_data.end(); ++it) {
+ if (it != m_data.begin())
+ output->append(',');
+ (*it)->writeJSON(output);
+ }
+ output->append(']');
+}
+
+InspectorArrayBase::InspectorArrayBase()
+ : InspectorValue(TypeArray)
+ , m_data()
+{
+}
+
+PassRefPtr<InspectorValue> InspectorArrayBase::get(size_t index)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(index < m_data.size());
+ return m_data[index];
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InspectorValues.h b/Source/core/inspector/InspectorValues.h
new file mode 100644
index 0000000..1f0aecb
--- /dev/null
+++ b/Source/core/inspector/InspectorValues.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorValues_h
+#define InspectorValues_h
+
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InspectorArray;
+class InspectorObject;
+
+class InspectorValue : public RefCounted<InspectorValue> {
+public:
+ static const int maxDepth = 1000;
+
+ InspectorValue() : m_type(TypeNull) { }
+ virtual ~InspectorValue() { }
+
+ static PassRefPtr<InspectorValue> null()
+ {
+ return adoptRef(new InspectorValue());
+ }
+
+ typedef enum {
+ TypeNull = 0,
+ TypeBoolean,
+ TypeNumber,
+ TypeString,
+ TypeObject,
+ TypeArray
+ } Type;
+
+ Type type() const { return m_type; }
+
+ bool isNull() const { return m_type == TypeNull; }
+
+ virtual bool asBoolean(bool* output) const;
+ virtual bool asNumber(double* output) const;
+ virtual bool asNumber(long* output) const;
+ virtual bool asNumber(int* output) const;
+ virtual bool asNumber(unsigned long* output) const;
+ virtual bool asNumber(unsigned int* output) const;
+ virtual bool asString(String* output) const;
+ virtual bool asValue(RefPtr<InspectorValue>* output);
+ virtual bool asObject(RefPtr<InspectorObject>* output);
+ virtual bool asArray(RefPtr<InspectorArray>* output);
+ virtual PassRefPtr<InspectorObject> asObject();
+ virtual PassRefPtr<InspectorArray> asArray();
+
+ static PassRefPtr<InspectorValue> parseJSON(const String& json);
+
+ String toJSONString() const;
+ virtual void writeJSON(StringBuilder* output) const;
+
+protected:
+ explicit InspectorValue(Type type) : m_type(type) { }
+
+private:
+ Type m_type;
+};
+
+class InspectorBasicValue : public InspectorValue {
+public:
+
+ static PassRefPtr<InspectorBasicValue> create(bool value)
+ {
+ return adoptRef(new InspectorBasicValue(value));
+ }
+
+ static PassRefPtr<InspectorBasicValue> create(int value)
+ {
+ return adoptRef(new InspectorBasicValue(value));
+ }
+
+ static PassRefPtr<InspectorBasicValue> create(double value)
+ {
+ return adoptRef(new InspectorBasicValue(value));
+ }
+
+ virtual bool asBoolean(bool* output) const;
+ virtual bool asNumber(double* output) const;
+ virtual bool asNumber(long* output) const;
+ virtual bool asNumber(int* output) const;
+ virtual bool asNumber(unsigned long* output) const;
+ virtual bool asNumber(unsigned int* output) const;
+
+ virtual void writeJSON(StringBuilder* output) const;
+
+private:
+ explicit InspectorBasicValue(bool value) : InspectorValue(TypeBoolean), m_boolValue(value) { }
+ explicit InspectorBasicValue(int value) : InspectorValue(TypeNumber), m_doubleValue((double)value) { }
+ explicit InspectorBasicValue(double value) : InspectorValue(TypeNumber), m_doubleValue(value) { }
+
+ union {
+ bool m_boolValue;
+ double m_doubleValue;
+ };
+};
+
+class InspectorString : public InspectorValue {
+public:
+ static PassRefPtr<InspectorString> create(const String& value)
+ {
+ return adoptRef(new InspectorString(value));
+ }
+
+ static PassRefPtr<InspectorString> create(const char* value)
+ {
+ return adoptRef(new InspectorString(value));
+ }
+
+ virtual bool asString(String* output) const;
+
+ virtual void writeJSON(StringBuilder* output) const;
+
+private:
+ explicit InspectorString(const String& value) : InspectorValue(TypeString), m_stringValue(value) { }
+ explicit InspectorString(const char* value) : InspectorValue(TypeString), m_stringValue(value) { }
+
+ String m_stringValue;
+};
+
+class InspectorObjectBase : public InspectorValue {
+private:
+ typedef HashMap<String, RefPtr<InspectorValue> > Dictionary;
+
+public:
+ typedef Dictionary::iterator iterator;
+ typedef Dictionary::const_iterator const_iterator;
+
+ virtual PassRefPtr<InspectorObject> asObject();
+ InspectorObject* openAccessors();
+
+protected:
+ ~InspectorObjectBase();
+
+ virtual bool asObject(RefPtr<InspectorObject>* output);
+
+ void setBoolean(const String& name, bool);
+ void setNumber(const String& name, double);
+ void setString(const String& name, const String&);
+ void setValue(const String& name, PassRefPtr<InspectorValue>);
+ void setObject(const String& name, PassRefPtr<InspectorObject>);
+ void setArray(const String& name, PassRefPtr<InspectorArray>);
+
+ iterator find(const String& name);
+ const_iterator find(const String& name) const;
+ bool getBoolean(const String& name, bool* output) const;
+ template<class T> bool getNumber(const String& name, T* output) const
+ {
+ RefPtr<InspectorValue> value = get(name);
+ if (!value)
+ return false;
+ return value->asNumber(output);
+ }
+ bool getString(const String& name, String* output) const;
+ PassRefPtr<InspectorObject> getObject(const String& name) const;
+ PassRefPtr<InspectorArray> getArray(const String& name) const;
+ PassRefPtr<InspectorValue> get(const String& name) const;
+
+ void remove(const String& name);
+
+ virtual void writeJSON(StringBuilder* output) const;
+
+ iterator begin() { return m_data.begin(); }
+ iterator end() { return m_data.end(); }
+ const_iterator begin() const { return m_data.begin(); }
+ const_iterator end() const { return m_data.end(); }
+
+ int size() const { return m_data.size(); }
+
+protected:
+ InspectorObjectBase();
+
+private:
+ Dictionary m_data;
+ Vector<String> m_order;
+};
+
+class InspectorObject : public InspectorObjectBase {
+public:
+ static PassRefPtr<InspectorObject> create()
+ {
+ return adoptRef(new InspectorObject());
+ }
+
+ using InspectorObjectBase::asObject;
+
+ using InspectorObjectBase::setBoolean;
+ using InspectorObjectBase::setNumber;
+ using InspectorObjectBase::setString;
+ using InspectorObjectBase::setValue;
+ using InspectorObjectBase::setObject;
+ using InspectorObjectBase::setArray;
+
+ using InspectorObjectBase::find;
+ using InspectorObjectBase::getBoolean;
+ using InspectorObjectBase::getNumber;
+ using InspectorObjectBase::getString;
+ using InspectorObjectBase::getObject;
+ using InspectorObjectBase::getArray;
+ using InspectorObjectBase::get;
+
+ using InspectorObjectBase::remove;
+
+ using InspectorObjectBase::begin;
+ using InspectorObjectBase::end;
+
+ using InspectorObjectBase::size;
+};
+
+
+class InspectorArrayBase : public InspectorValue {
+public:
+ typedef Vector<RefPtr<InspectorValue> >::iterator iterator;
+ typedef Vector<RefPtr<InspectorValue> >::const_iterator const_iterator;
+
+ virtual PassRefPtr<InspectorArray> asArray();
+
+ unsigned length() const { return m_data.size(); }
+
+protected:
+ ~InspectorArrayBase();
+
+ virtual bool asArray(RefPtr<InspectorArray>* output);
+
+ void pushBoolean(bool);
+ void pushInt(int);
+ void pushNumber(double);
+ void pushString(const String&);
+ void pushValue(PassRefPtr<InspectorValue>);
+ void pushObject(PassRefPtr<InspectorObject>);
+ void pushArray(PassRefPtr<InspectorArray>);
+
+ PassRefPtr<InspectorValue> get(size_t index);
+
+ virtual void writeJSON(StringBuilder* output) const;
+
+ iterator begin() { return m_data.begin(); }
+ iterator end() { return m_data.end(); }
+ const_iterator begin() const { return m_data.begin(); }
+ const_iterator end() const { return m_data.end(); }
+
+protected:
+ InspectorArrayBase();
+
+private:
+ Vector<RefPtr<InspectorValue> > m_data;
+};
+
+class InspectorArray : public InspectorArrayBase {
+public:
+ static PassRefPtr<InspectorArray> create()
+ {
+ return adoptRef(new InspectorArray());
+ }
+
+ using InspectorArrayBase::asArray;
+
+ using InspectorArrayBase::pushBoolean;
+ using InspectorArrayBase::pushInt;
+ using InspectorArrayBase::pushNumber;
+ using InspectorArrayBase::pushString;
+ using InspectorArrayBase::pushValue;
+ using InspectorArrayBase::pushObject;
+ using InspectorArrayBase::pushArray;
+
+ using InspectorArrayBase::get;
+
+ using InspectorArrayBase::begin;
+ using InspectorArrayBase::end;
+};
+
+
+inline InspectorObjectBase::iterator InspectorObjectBase::find(const String& name)
+{
+ return m_data.find(name);
+}
+
+inline InspectorObjectBase::const_iterator InspectorObjectBase::find(const String& name) const
+{
+ return m_data.find(name);
+}
+
+inline void InspectorObjectBase::setBoolean(const String& name, bool value)
+{
+ setValue(name, InspectorBasicValue::create(value));
+}
+
+inline void InspectorObjectBase::setNumber(const String& name, double value)
+{
+ setValue(name, InspectorBasicValue::create(value));
+}
+
+inline void InspectorObjectBase::setString(const String& name, const String& value)
+{
+ setValue(name, InspectorString::create(value));
+}
+
+inline void InspectorObjectBase::setValue(const String& name, PassRefPtr<InspectorValue> value)
+{
+ ASSERT(value);
+ if (m_data.set(name, value).isNewEntry)
+ m_order.append(name);
+}
+
+inline void InspectorObjectBase::setObject(const String& name, PassRefPtr<InspectorObject> value)
+{
+ ASSERT(value);
+ if (m_data.set(name, value).isNewEntry)
+ m_order.append(name);
+}
+
+inline void InspectorObjectBase::setArray(const String& name, PassRefPtr<InspectorArray> value)
+{
+ ASSERT(value);
+ if (m_data.set(name, value).isNewEntry)
+ m_order.append(name);
+}
+
+inline void InspectorArrayBase::pushBoolean(bool value)
+{
+ m_data.append(InspectorBasicValue::create(value));
+}
+
+inline void InspectorArrayBase::pushInt(int value)
+{
+ m_data.append(InspectorBasicValue::create(value));
+}
+
+inline void InspectorArrayBase::pushNumber(double value)
+{
+ m_data.append(InspectorBasicValue::create(value));
+}
+
+inline void InspectorArrayBase::pushString(const String& value)
+{
+ m_data.append(InspectorString::create(value));
+}
+
+inline void InspectorArrayBase::pushValue(PassRefPtr<InspectorValue> value)
+{
+ ASSERT(value);
+ m_data.append(value);
+}
+
+inline void InspectorArrayBase::pushObject(PassRefPtr<InspectorObject> value)
+{
+ ASSERT(value);
+ m_data.append(value);
+}
+
+inline void InspectorArrayBase::pushArray(PassRefPtr<InspectorArray> value)
+{
+ ASSERT(value);
+ m_data.append(value);
+}
+
+} // namespace WebCore
+
+#endif // !defined(InspectorValues_h)
diff --git a/Source/core/inspector/InspectorWorkerAgent.cpp b/Source/core/inspector/InspectorWorkerAgent.cpp
new file mode 100644
index 0000000..e995c22
--- /dev/null
+++ b/Source/core/inspector/InspectorWorkerAgent.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InspectorWorkerAgent.h"
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorFrontendChannel.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/platform/KURL.h"
+#include "core/workers/WorkerContextProxy.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+namespace WorkerAgentState {
+static const char workerInspectionEnabled[] = "workerInspectionEnabled";
+static const char autoconnectToWorkers[] = "autoconnectToWorkers";
+};
+
+class InspectorWorkerAgent::WorkerFrontendChannel : public WorkerContextProxy::PageInspector {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ explicit WorkerFrontendChannel(InspectorFrontend* frontend, WorkerContextProxy* proxy)
+ : m_frontend(frontend)
+ , m_proxy(proxy)
+ , m_id(s_nextId++)
+ , m_connected(false)
+ {
+ }
+ virtual ~WorkerFrontendChannel()
+ {
+ disconnectFromWorkerContext();
+ }
+
+ int id() const { return m_id; }
+ WorkerContextProxy* proxy() const { return m_proxy; }
+
+ void connectToWorkerContext()
+ {
+ if (m_connected)
+ return;
+ m_connected = true;
+ m_proxy->connectToInspector(this);
+ }
+
+ void disconnectFromWorkerContext()
+ {
+ if (!m_connected)
+ return;
+ m_connected = false;
+ m_proxy->disconnectFromInspector();
+ }
+
+private:
+ // WorkerContextProxy::PageInspector implementation
+ virtual void dispatchMessageFromWorker(const String& message)
+ {
+ RefPtr<InspectorValue> value = InspectorValue::parseJSON(message);
+ if (!value)
+ return;
+ RefPtr<InspectorObject> messageObject = value->asObject();
+ if (!messageObject)
+ return;
+ m_frontend->worker()->dispatchMessageFromWorker(m_id, messageObject);
+ }
+
+ InspectorFrontend* m_frontend;
+ WorkerContextProxy* m_proxy;
+ int m_id;
+ bool m_connected;
+ static int s_nextId;
+};
+
+int InspectorWorkerAgent::WorkerFrontendChannel::s_nextId = 1;
+
+PassOwnPtr<InspectorWorkerAgent> InspectorWorkerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState)
+{
+ return adoptPtr(new InspectorWorkerAgent(instrumentingAgents, inspectorState));
+}
+
+InspectorWorkerAgent::InspectorWorkerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState)
+ : InspectorBaseAgent<InspectorWorkerAgent>("Worker", instrumentingAgents, inspectorState)
+ , m_inspectorFrontend(0)
+{
+ m_instrumentingAgents->setInspectorWorkerAgent(this);
+}
+
+InspectorWorkerAgent::~InspectorWorkerAgent()
+{
+ m_instrumentingAgents->setInspectorWorkerAgent(0);
+}
+
+void InspectorWorkerAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_inspectorFrontend = frontend;
+}
+
+void InspectorWorkerAgent::restore()
+{
+ if (m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
+ createWorkerFrontendChannelsForExistingWorkers();
+}
+
+void InspectorWorkerAgent::clearFrontend()
+{
+ m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, false);
+ disable(0);
+ m_inspectorFrontend = 0;
+}
+
+void InspectorWorkerAgent::enable(ErrorString*)
+{
+ m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, true);
+ if (!m_inspectorFrontend)
+ return;
+ createWorkerFrontendChannelsForExistingWorkers();
+}
+
+void InspectorWorkerAgent::disable(ErrorString*)
+{
+ m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, false);
+ if (!m_inspectorFrontend)
+ return;
+ destroyWorkerFrontendChannels();
+}
+
+void InspectorWorkerAgent::canInspectWorkers(ErrorString*, bool* result)
+{
+ *result = true;
+}
+
+void InspectorWorkerAgent::connectToWorker(ErrorString* error, int workerId)
+{
+ WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
+ if (channel)
+ channel->connectToWorkerContext();
+ else
+ *error = "Worker is gone";
+}
+
+void InspectorWorkerAgent::disconnectFromWorker(ErrorString* error, int workerId)
+{
+ WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
+ if (channel)
+ channel->disconnectFromWorkerContext();
+ else
+ *error = "Worker is gone";
+}
+
+void InspectorWorkerAgent::sendMessageToWorker(ErrorString* error, int workerId, const RefPtr<InspectorObject>& message)
+{
+ WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
+ if (channel)
+ channel->proxy()->sendMessageToInspector(message->toJSONString());
+ else
+ *error = "Worker is gone";
+}
+
+void InspectorWorkerAgent::setAutoconnectToWorkers(ErrorString*, bool value)
+{
+ m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, value);
+}
+
+bool InspectorWorkerAgent::shouldPauseDedicatedWorkerOnStart()
+{
+ return m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
+}
+
+void InspectorWorkerAgent::didStartWorkerContext(WorkerContextProxy* workerContextProxy, const KURL& url)
+{
+ m_dedicatedWorkers.set(workerContextProxy, url.string());
+ if (m_inspectorFrontend && m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
+ createWorkerFrontendChannel(workerContextProxy, url.string());
+}
+
+void InspectorWorkerAgent::workerContextTerminated(WorkerContextProxy* proxy)
+{
+ m_dedicatedWorkers.remove(proxy);
+ for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
+ if (proxy == it->value->proxy()) {
+ m_inspectorFrontend->worker()->workerTerminated(it->key);
+ delete it->value;
+ m_idToChannel.remove(it);
+ return;
+ }
+ }
+}
+
+void InspectorWorkerAgent::createWorkerFrontendChannelsForExistingWorkers()
+{
+ for (DedicatedWorkers::iterator it = m_dedicatedWorkers.begin(); it != m_dedicatedWorkers.end(); ++it)
+ createWorkerFrontendChannel(it->key, it->value);
+}
+
+void InspectorWorkerAgent::destroyWorkerFrontendChannels()
+{
+ for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
+ it->value->disconnectFromWorkerContext();
+ delete it->value;
+ }
+ m_idToChannel.clear();
+}
+
+void InspectorWorkerAgent::createWorkerFrontendChannel(WorkerContextProxy* workerContextProxy, const String& url)
+{
+ WorkerFrontendChannel* channel = new WorkerFrontendChannel(m_inspectorFrontend, workerContextProxy);
+ m_idToChannel.set(channel->id(), channel);
+
+ ASSERT(m_inspectorFrontend);
+ bool autoconnectToWorkers = m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
+ if (autoconnectToWorkers)
+ channel->connectToWorkerContext();
+ m_inspectorFrontend->worker()->workerCreated(channel->id(), url, autoconnectToWorkers);
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InspectorWorkerAgent.h b/Source/core/inspector/InspectorWorkerAgent.h
new file mode 100644
index 0000000..4f53b1f
--- /dev/null
+++ b/Source/core/inspector/InspectorWorkerAgent.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorWorkerAgent_h
+#define InspectorWorkerAgent_h
+
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+class InspectorFrontend;
+class InspectorObject;
+class InspectorState;
+class InstrumentingAgents;
+class KURL;
+class WorkerContextProxy;
+
+typedef String ErrorString;
+
+class InspectorWorkerAgent : public InspectorBaseAgent<InspectorWorkerAgent>, public InspectorBackendDispatcher::WorkerCommandHandler {
+public:
+ static PassOwnPtr<InspectorWorkerAgent> create(InstrumentingAgents*, InspectorCompositeState*);
+ ~InspectorWorkerAgent();
+
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void restore();
+ virtual void clearFrontend();
+
+ // Called from InspectorInstrumentation
+ bool shouldPauseDedicatedWorkerOnStart();
+ void didStartWorkerContext(WorkerContextProxy*, const KURL&);
+ void workerContextTerminated(WorkerContextProxy*);
+
+ // Called from InspectorBackendDispatcher
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+ virtual void canInspectWorkers(ErrorString*, bool*);
+ virtual void connectToWorker(ErrorString*, int workerId);
+ virtual void disconnectFromWorker(ErrorString*, int workerId);
+ virtual void sendMessageToWorker(ErrorString*, int workerId, const RefPtr<InspectorObject>& message);
+ virtual void setAutoconnectToWorkers(ErrorString*, bool value);
+
+private:
+ InspectorWorkerAgent(InstrumentingAgents*, InspectorCompositeState*);
+ void createWorkerFrontendChannelsForExistingWorkers();
+ void createWorkerFrontendChannel(WorkerContextProxy*, const String& url);
+ void destroyWorkerFrontendChannels();
+
+ InspectorFrontend* m_inspectorFrontend;
+
+ class WorkerFrontendChannel;
+ typedef HashMap<int, WorkerFrontendChannel*> WorkerChannels;
+ WorkerChannels m_idToChannel;
+ typedef HashMap<WorkerContextProxy*, String> DedicatedWorkers;
+ DedicatedWorkers m_dedicatedWorkers;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorWorkerAgent_h)
diff --git a/Source/core/inspector/InspectorWorkerResource.h b/Source/core/inspector/InspectorWorkerResource.h
new file mode 100644
index 0000000..f8bed52
--- /dev/null
+++ b/Source/core/inspector/InspectorWorkerResource.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InspectorWorkerResource_h
+#define InspectorWorkerResource_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InspectorWorkerResource : public RefCounted<InspectorWorkerResource> {
+public:
+ static PassRefPtr<InspectorWorkerResource> create(intptr_t id, const String& url, bool isSharedWorker)
+ {
+ return adoptRef(new InspectorWorkerResource(id, url, isSharedWorker));
+ }
+
+ intptr_t id() const { return m_id; }
+ const String& url() const { return m_url; }
+ bool isSharedWorker() const { return m_isSharedWorker; }
+private:
+ InspectorWorkerResource(intptr_t id, const String& url, bool isSharedWorker)
+ : m_id(id)
+ , m_url(url)
+ , m_isSharedWorker(isSharedWorker)
+ {
+ }
+
+ intptr_t m_id;
+ String m_url;
+ bool m_isSharedWorker;
+};
+
+} // namespace WebCore
+
+#endif // InspectorWorkerResource_h
diff --git a/Source/core/inspector/InstrumentingAgents.cpp b/Source/core/inspector/InstrumentingAgents.cpp
new file mode 100644
index 0000000..0666ca9
--- /dev/null
+++ b/Source/core/inspector/InstrumentingAgents.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/InstrumentingAgents.h"
+
+#include "core/inspector/InspectorController.h"
+#include "core/inspector/WorkerInspectorController.h"
+#include "core/page/Page.h"
+#include "core/workers/WorkerContext.h"
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+InstrumentingAgents::InstrumentingAgents()
+ : m_inspectorAgent(0)
+ , m_inspectorPageAgent(0)
+ , m_inspectorCSSAgent(0)
+ , m_inspectorLayerTreeAgent(0)
+ , m_inspectorConsoleAgent(0)
+ , m_inspectorDOMAgent(0)
+ , m_inspectorResourceAgent(0)
+ , m_pageRuntimeAgent(0)
+ , m_workerRuntimeAgent(0)
+ , m_inspectorTimelineAgent(0)
+ , m_inspectorDOMStorageAgent(0)
+ , m_inspectorDatabaseAgent(0)
+ , m_inspectorFileSystemAgent(0)
+ , m_inspectorApplicationCacheAgent(0)
+ , m_inspectorDebuggerAgent(0)
+ , m_pageDebuggerAgent(0)
+ , m_inspectorDOMDebuggerAgent(0)
+ , m_inspectorProfilerAgent(0)
+ , m_inspectorWorkerAgent(0)
+ , m_inspectorCanvasAgent(0)
+{
+}
+
+void InstrumentingAgents::reset()
+{
+ m_inspectorAgent = 0;
+ m_inspectorPageAgent = 0;
+ m_inspectorCSSAgent = 0;
+ m_inspectorLayerTreeAgent = 0;
+ m_inspectorConsoleAgent = 0;
+ m_inspectorDOMAgent = 0;
+ m_inspectorResourceAgent = 0;
+ m_pageRuntimeAgent = 0;
+ m_workerRuntimeAgent = 0;
+ m_inspectorTimelineAgent = 0;
+ m_inspectorDOMStorageAgent = 0;
+ m_inspectorDatabaseAgent = 0;
+ m_inspectorFileSystemAgent = 0;
+ m_inspectorApplicationCacheAgent = 0;
+ m_inspectorDebuggerAgent = 0;
+ m_pageDebuggerAgent = 0;
+ m_inspectorDOMDebuggerAgent = 0;
+ m_inspectorProfilerAgent = 0;
+ m_inspectorWorkerAgent = 0;
+ m_inspectorCanvasAgent = 0;
+}
+
+InstrumentingAgents* instrumentationForPage(Page* page)
+{
+ ASSERT(isMainThread());
+ if (InspectorController* controller = page->inspectorController())
+ return controller->m_instrumentingAgents.get();
+ return 0;
+}
+
+InstrumentingAgents* instrumentationForWorkerContext(WorkerContext* workerContext)
+{
+ if (WorkerInspectorController* controller = workerContext->workerInspectorController())
+ return controller->m_instrumentingAgents.get();
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/InstrumentingAgents.h b/Source/core/inspector/InstrumentingAgents.h
new file mode 100644
index 0000000..0ca9a58
--- /dev/null
+++ b/Source/core/inspector/InstrumentingAgents.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 InstrumentingAgents_h
+#define InstrumentingAgents_h
+
+#include <wtf/FastAllocBase.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class InspectorAgent;
+class InspectorApplicationCacheAgent;
+class InspectorCSSAgent;
+class InspectorCanvasAgent;
+class InspectorConsoleAgent;
+class InspectorDOMAgent;
+class InspectorDOMDebuggerAgent;
+class InspectorDOMStorageAgent;
+class InspectorDatabaseAgent;
+class InspectorDebuggerAgent;
+class InspectorFileSystemAgent;
+class InspectorHeapProfilerAgent;
+class InspectorLayerTreeAgent;
+class InspectorPageAgent;
+class InspectorProfilerAgent;
+class InspectorResourceAgent;
+class InspectorTimelineAgent;
+class InspectorWorkerAgent;
+class Page;
+class PageDebuggerAgent;
+class PageRuntimeAgent;
+class WorkerContext;
+class WorkerRuntimeAgent;
+
+class InstrumentingAgents : public RefCounted<InstrumentingAgents> {
+ WTF_MAKE_NONCOPYABLE(InstrumentingAgents);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ static PassRefPtr<InstrumentingAgents> create()
+ {
+ return adoptRef(new InstrumentingAgents());
+ }
+ ~InstrumentingAgents() { }
+ void reset();
+
+ InspectorAgent* inspectorAgent() const { return m_inspectorAgent; }
+ void setInspectorAgent(InspectorAgent* agent) { m_inspectorAgent = agent; }
+
+ InspectorPageAgent* inspectorPageAgent() const { return m_inspectorPageAgent; }
+ void setInspectorPageAgent(InspectorPageAgent* agent) { m_inspectorPageAgent = agent; }
+
+ InspectorCSSAgent* inspectorCSSAgent() const { return m_inspectorCSSAgent; }
+ void setInspectorCSSAgent(InspectorCSSAgent* agent) { m_inspectorCSSAgent = agent; }
+
+ InspectorConsoleAgent* inspectorConsoleAgent() const { return m_inspectorConsoleAgent; }
+ void setInspectorConsoleAgent(InspectorConsoleAgent* agent) { m_inspectorConsoleAgent = agent; }
+
+ InspectorDOMAgent* inspectorDOMAgent() const { return m_inspectorDOMAgent; }
+ void setInspectorDOMAgent(InspectorDOMAgent* agent) { m_inspectorDOMAgent = agent; }
+
+ InspectorResourceAgent* inspectorResourceAgent() const { return m_inspectorResourceAgent; }
+ void setInspectorResourceAgent(InspectorResourceAgent* agent) { m_inspectorResourceAgent = agent; }
+
+ PageRuntimeAgent* pageRuntimeAgent() const { return m_pageRuntimeAgent; }
+ void setPageRuntimeAgent(PageRuntimeAgent* agent) { m_pageRuntimeAgent = agent; }
+
+ WorkerRuntimeAgent* workerRuntimeAgent() const { return m_workerRuntimeAgent; }
+ void setWorkerRuntimeAgent(WorkerRuntimeAgent* agent) { m_workerRuntimeAgent = agent; }
+
+ InspectorTimelineAgent* inspectorTimelineAgent() const { return m_inspectorTimelineAgent; }
+ void setInspectorTimelineAgent(InspectorTimelineAgent* agent) { m_inspectorTimelineAgent = agent; }
+
+ InspectorDOMStorageAgent* inspectorDOMStorageAgent() const { return m_inspectorDOMStorageAgent; }
+ void setInspectorDOMStorageAgent(InspectorDOMStorageAgent* agent) { m_inspectorDOMStorageAgent = agent; }
+
+ InspectorDatabaseAgent* inspectorDatabaseAgent() const { return m_inspectorDatabaseAgent; }
+ void setInspectorDatabaseAgent(InspectorDatabaseAgent* agent) { m_inspectorDatabaseAgent = agent; }
+
+ InspectorFileSystemAgent* inspectorFileSystemAgent() const { return m_inspectorFileSystemAgent; }
+ void setInspectorFileSystemAgent(InspectorFileSystemAgent* agent) { m_inspectorFileSystemAgent = agent; }
+
+ InspectorApplicationCacheAgent* inspectorApplicationCacheAgent() const { return m_inspectorApplicationCacheAgent; }
+ void setInspectorApplicationCacheAgent(InspectorApplicationCacheAgent* agent) { m_inspectorApplicationCacheAgent = agent; }
+
+ InspectorDebuggerAgent* inspectorDebuggerAgent() const { return m_inspectorDebuggerAgent; }
+ void setInspectorDebuggerAgent(InspectorDebuggerAgent* agent) { m_inspectorDebuggerAgent = agent; }
+
+ PageDebuggerAgent* pageDebuggerAgent() const { return m_pageDebuggerAgent; }
+ void setPageDebuggerAgent(PageDebuggerAgent* agent) { m_pageDebuggerAgent = agent; }
+
+ InspectorDOMDebuggerAgent* inspectorDOMDebuggerAgent() const { return m_inspectorDOMDebuggerAgent; }
+ void setInspectorDOMDebuggerAgent(InspectorDOMDebuggerAgent* agent) { m_inspectorDOMDebuggerAgent = agent; }
+
+ InspectorProfilerAgent* inspectorProfilerAgent() const { return m_inspectorProfilerAgent; }
+ void setInspectorProfilerAgent(InspectorProfilerAgent* agent) { m_inspectorProfilerAgent = agent; }
+
+ InspectorHeapProfilerAgent* inspectorHeapProfilerAgent() const { return m_inspectorHeapProfilerAgent; }
+ void setInspectorHeapProfilerAgent(InspectorHeapProfilerAgent* agent) { m_inspectorHeapProfilerAgent = agent; }
+
+ InspectorWorkerAgent* inspectorWorkerAgent() const { return m_inspectorWorkerAgent; }
+ void setInspectorWorkerAgent(InspectorWorkerAgent* agent) { m_inspectorWorkerAgent = agent; }
+
+ InspectorCanvasAgent* inspectorCanvasAgent() const { return m_inspectorCanvasAgent; }
+ void setInspectorCanvasAgent(InspectorCanvasAgent* agent) { m_inspectorCanvasAgent = agent; }
+
+ InspectorLayerTreeAgent* inspectorLayerTreeAgent() const { return m_inspectorLayerTreeAgent; }
+ void setInspectorLayerTreeAgent(InspectorLayerTreeAgent* agent) { m_inspectorLayerTreeAgent = agent; }
+
+private:
+ InstrumentingAgents();
+
+ InspectorAgent* m_inspectorAgent;
+ InspectorPageAgent* m_inspectorPageAgent;
+ InspectorCSSAgent* m_inspectorCSSAgent;
+ InspectorLayerTreeAgent* m_inspectorLayerTreeAgent;
+ InspectorConsoleAgent* m_inspectorConsoleAgent;
+ InspectorDOMAgent* m_inspectorDOMAgent;
+ InspectorResourceAgent* m_inspectorResourceAgent;
+ PageRuntimeAgent* m_pageRuntimeAgent;
+ WorkerRuntimeAgent* m_workerRuntimeAgent;
+ InspectorTimelineAgent* m_inspectorTimelineAgent;
+ InspectorDOMStorageAgent* m_inspectorDOMStorageAgent;
+ InspectorDatabaseAgent* m_inspectorDatabaseAgent;
+ InspectorFileSystemAgent* m_inspectorFileSystemAgent;
+ InspectorApplicationCacheAgent* m_inspectorApplicationCacheAgent;
+ InspectorDebuggerAgent* m_inspectorDebuggerAgent;
+ PageDebuggerAgent* m_pageDebuggerAgent;
+ InspectorDOMDebuggerAgent* m_inspectorDOMDebuggerAgent;
+ InspectorProfilerAgent* m_inspectorProfilerAgent;
+ InspectorHeapProfilerAgent* m_inspectorHeapProfilerAgent;
+ InspectorWorkerAgent* m_inspectorWorkerAgent;
+ InspectorCanvasAgent* m_inspectorCanvasAgent;
+};
+
+InstrumentingAgents* instrumentationForPage(Page*);
+InstrumentingAgents* instrumentationForWorkerContext(WorkerContext*);
+
+}
+
+#endif // !defined(InstrumentingAgents_h)
diff --git a/Source/core/inspector/JavaScriptCallFrame.cpp b/Source/core/inspector/JavaScriptCallFrame.cpp
new file mode 100644
index 0000000..2548acd
--- /dev/null
+++ b/Source/core/inspector/JavaScriptCallFrame.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2010, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/JavaScriptCallFrame.h"
+
+#include "bindings/v8/V8Binding.h"
+
+namespace WebCore {
+
+JavaScriptCallFrame::JavaScriptCallFrame(v8::Handle<v8::Context> debuggerContext, v8::Handle<v8::Object> callFrame)
+ : m_debuggerContext(debuggerContext)
+ , m_callFrame(callFrame)
+{
+}
+
+JavaScriptCallFrame::~JavaScriptCallFrame()
+{
+}
+
+JavaScriptCallFrame* JavaScriptCallFrame::caller()
+{
+ if (!m_caller) {
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(m_debuggerContext.get());
+ v8::Handle<v8::Value> callerFrame = m_callFrame.get()->Get(v8::String::NewSymbol("caller"));
+ if (!callerFrame->IsObject())
+ return 0;
+ m_caller = JavaScriptCallFrame::create(m_debuggerContext.get(), v8::Handle<v8::Object>::Cast(callerFrame));
+ }
+ return m_caller.get();
+}
+
+int JavaScriptCallFrame::sourceID() const
+{
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(m_debuggerContext.get());
+ v8::Handle<v8::Value> result = m_callFrame.get()->Get(v8::String::NewSymbol("sourceID"));
+ if (result->IsInt32())
+ return result->Int32Value();
+ return 0;
+}
+
+int JavaScriptCallFrame::line() const
+{
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(m_debuggerContext.get());
+ v8::Handle<v8::Value> result = m_callFrame.get()->Get(v8::String::NewSymbol("line"));
+ if (result->IsInt32())
+ return result->Int32Value();
+ return 0;
+}
+
+int JavaScriptCallFrame::column() const
+{
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(m_debuggerContext.get());
+ v8::Handle<v8::Value> result = m_callFrame.get()->Get(v8::String::NewSymbol("column"));
+ if (result->IsInt32())
+ return result->Int32Value();
+ return 0;
+}
+
+String JavaScriptCallFrame::functionName() const
+{
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(m_debuggerContext.get());
+ v8::Handle<v8::Value> result = m_callFrame.get()->Get(v8::String::NewSymbol("functionName"));
+ return toWebCoreStringWithUndefinedOrNullCheck(result);
+}
+
+v8::Handle<v8::Value> JavaScriptCallFrame::scopeChain() const
+{
+ v8::Handle<v8::Array> scopeChain = v8::Handle<v8::Array>::Cast(m_callFrame.get()->Get(v8::String::NewSymbol("scopeChain")));
+ v8::Handle<v8::Array> result = v8::Array::New(scopeChain->Length());
+ for (uint32_t i = 0; i < scopeChain->Length(); i++)
+ result->Set(i, scopeChain->Get(i));
+ return result;
+}
+
+int JavaScriptCallFrame::scopeType(int scopeIndex) const
+{
+ v8::Handle<v8::Array> scopeType = v8::Handle<v8::Array>::Cast(m_callFrame.get()->Get(v8::String::NewSymbol("scopeType")));
+ return scopeType->Get(scopeIndex)->Int32Value();
+}
+
+v8::Handle<v8::Value> JavaScriptCallFrame::thisObject() const
+{
+ return m_callFrame.get()->Get(v8::String::NewSymbol("thisObject"));
+}
+
+v8::Handle<v8::Value> JavaScriptCallFrame::evaluate(const String& expression)
+{
+ v8::Handle<v8::Function> evalFunction = v8::Handle<v8::Function>::Cast(m_callFrame.get()->Get(v8::String::NewSymbol("evaluate")));
+ v8::Handle<v8::Value> argv[] = { v8String(expression, m_debuggerContext->GetIsolate()) };
+ return evalFunction->Call(m_callFrame.get(), 1, argv);
+}
+
+v8::Handle<v8::Value> JavaScriptCallFrame::restart()
+{
+ v8::Handle<v8::Function> restartFunction = v8::Handle<v8::Function>::Cast(m_callFrame.get()->Get(v8::String::NewSymbol("restart")));
+ v8::Debug::SetLiveEditEnabled(true);
+ v8::Handle<v8::Value> result = restartFunction->Call(m_callFrame.get(), 0, 0);
+ v8::Debug::SetLiveEditEnabled(false);
+ return result;
+}
+
+v8::Handle<v8::Value> JavaScriptCallFrame::setVariableValue(int scopeNumber, const String& variableName, v8::Handle<v8::Value> newValue)
+{
+ v8::Handle<v8::Function> setVariableValueFunction = v8::Handle<v8::Function>::Cast(m_callFrame.get()->Get(v8::String::NewSymbol("setVariableValue")));
+ v8::Handle<v8::Value> argv[] = {
+ v8::Handle<v8::Value>(v8::Integer::New(scopeNumber)),
+ v8String(variableName, m_debuggerContext->GetIsolate()),
+ newValue
+ };
+ return setVariableValueFunction->Call(m_callFrame.get(), 3, argv);
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/JavaScriptCallFrame.h b/Source/core/inspector/JavaScriptCallFrame.h
new file mode 100644
index 0000000..391af77
--- /dev/null
+++ b/Source/core/inspector/JavaScriptCallFrame.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2010, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 JavaScriptCallFrame_h
+#define JavaScriptCallFrame_h
+
+
+#include "bindings/v8/ScopedPersistent.h"
+#include <v8-debug.h>
+#include "wtf/RefCounted.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class JavaScriptCallFrame : public RefCounted<JavaScriptCallFrame> {
+public:
+ static PassRefPtr<JavaScriptCallFrame> create(v8::Handle<v8::Context> debuggerContext, v8::Handle<v8::Object> callFrame)
+ {
+ return adoptRef(new JavaScriptCallFrame(debuggerContext, callFrame));
+ }
+ ~JavaScriptCallFrame();
+
+ JavaScriptCallFrame* caller();
+
+ int sourceID() const;
+ int line() const;
+ int column() const;
+ String functionName() const;
+
+ v8::Handle<v8::Value> scopeChain() const;
+ int scopeType(int scopeIndex) const;
+ v8::Handle<v8::Value> thisObject() const;
+
+ v8::Handle<v8::Value> evaluate(const String& expression);
+ v8::Handle<v8::Value> restart();
+ v8::Handle<v8::Value> setVariableValue(int scopeNumber, const String& variableName, v8::Handle<v8::Value> newValue);
+
+private:
+ JavaScriptCallFrame(v8::Handle<v8::Context> debuggerContext, v8::Handle<v8::Object> callFrame);
+
+ RefPtr<JavaScriptCallFrame> m_caller;
+ ScopedPersistent<v8::Context> m_debuggerContext;
+ ScopedPersistent<v8::Object> m_callFrame;
+};
+
+} // namespace WebCore
+
+
+#endif // JavaScriptCallFrame_h
diff --git a/Source/core/inspector/JavaScriptCallFrame.idl b/Source/core/inspector/JavaScriptCallFrame.idl
new file mode 100644
index 0000000..ebd87d4
--- /dev/null
+++ b/Source/core/inspector/JavaScriptCallFrame.idl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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. ``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
+ * 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.
+ */
+
+[
+ DoNotCheckConstants,
+ ImplementationLacksVTable
+] interface JavaScriptCallFrame {
+
+ // Scope type
+ const unsigned short GLOBAL_SCOPE = 0;
+ const unsigned short LOCAL_SCOPE = 1;
+ const unsigned short WITH_SCOPE = 2;
+ const unsigned short CLOSURE_SCOPE = 3;
+ const unsigned short CATCH_SCOPE = 4;
+
+ [Custom] void evaluate(DOMString script);
+ [Custom] any restart();
+
+ // Only declarative scope (local, with and catch) is accepted. Returns undefined.
+ [Custom] any setVariableValue(long scopeIndex, DOMString variableName, any newValue);
+
+ readonly attribute JavaScriptCallFrame caller;
+ readonly attribute long sourceID;
+ readonly attribute long line;
+ readonly attribute long column;
+ [CustomGetter] readonly attribute Array scopeChain;
+ [Custom] unsigned short scopeType(long scopeIndex);
+ [CustomGetter] readonly attribute Object thisObject;
+ readonly attribute DOMString functionName;
+ [CustomGetter] readonly attribute DOMString type;
+};
+
diff --git a/Source/core/inspector/MemoryInstrumentationImpl.cpp b/Source/core/inspector/MemoryInstrumentationImpl.cpp
new file mode 100644
index 0000000..b13bb9c
--- /dev/null
+++ b/Source/core/inspector/MemoryInstrumentationImpl.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/MemoryInstrumentationImpl.h"
+
+#include "core/dom/WebCoreMemoryInstrumentation.h"
+#include "core/inspector/HeapGraphSerializer.h"
+#include <wtf/Assertions.h>
+#include <wtf/MemoryInstrumentationHashMap.h>
+#include <wtf/MemoryInstrumentationHashSet.h>
+#include <wtf/MemoryInstrumentationVector.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+TypeNameToSizeMap MemoryInstrumentationClientImpl::sizesMap() const
+{
+ // TypeToSizeMap uses const char* as the key.
+ // Thus it could happen that we have two different keys with equal string.
+ TypeNameToSizeMap sizesMap;
+ for (TypeToSizeMap::const_iterator i = m_totalSizes.begin(); i != m_totalSizes.end(); ++i) {
+ String objectType(i->key);
+ TypeNameToSizeMap::AddResult result = sizesMap.add(objectType, i->value);
+ if (!result.isNewEntry)
+ result.iterator->value += i->value;
+ }
+
+ return sizesMap;
+}
+
+void MemoryInstrumentationClientImpl::countObjectSize(const void* object, MemoryObjectType objectType, size_t size)
+{
+ ASSERT(objectType);
+
+ TypeToSizeMap::AddResult result = m_totalSizes.add(objectType, size);
+ if (!result.isNewEntry)
+ result.iterator->value += size;
+ ++m_totalCountedObjects;
+
+ if (!checkInstrumentedObjects())
+ return;
+
+ if (object)
+ m_countedObjects.add(object, size);
+}
+
+bool MemoryInstrumentationClientImpl::visited(const void* object)
+{
+ return !m_visitedObjects.add(object).isNewEntry;
+}
+
+bool MemoryInstrumentationClientImpl::checkCountedObject(const void* object)
+{
+ if (!checkInstrumentedObjects())
+ return true;
+ if (!m_allocatedObjects.contains(object)) {
+ ++m_totalObjectsNotInAllocatedSet;
+ return false;
+ }
+ return true;
+}
+
+void MemoryInstrumentationClientImpl::reportNode(const MemoryObjectInfo& node)
+{
+ if (m_graphSerializer)
+ m_graphSerializer->reportNode(node);
+}
+
+void MemoryInstrumentationClientImpl::reportEdge(const void* target, const char* name, MemberType memberType)
+{
+ if (m_graphSerializer)
+ m_graphSerializer->reportEdge(target, name, memberType);
+}
+
+void MemoryInstrumentationClientImpl::reportLeaf(const MemoryObjectInfo& target, const char* edgeName)
+{
+ if (m_graphSerializer)
+ m_graphSerializer->reportLeaf(target, edgeName);
+}
+
+void MemoryInstrumentationClientImpl::reportBaseAddress(const void* base, const void* real)
+{
+ if (m_graphSerializer)
+ m_graphSerializer->reportBaseAddress(base, real);
+}
+
+int MemoryInstrumentationClientImpl::registerString(const char* string)
+{
+ if (m_graphSerializer)
+ return m_graphSerializer->registerString(string);
+ return -1;
+}
+
+void MemoryInstrumentationClientImpl::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorMemoryAgent);
+ info.addMember(m_totalSizes, "totalSizes");
+ info.addMember(m_visitedObjects, "visitedObjects");
+ info.addMember(m_allocatedObjects, "allocatedObjects");
+ info.addMember(m_countedObjects, "countedObjects");
+ info.addMember(m_graphSerializer, "graphSerializer");
+}
+
+void MemoryInstrumentationImpl::processDeferredObjects()
+{
+ while (!m_deferredObjects.isEmpty()) {
+ OwnPtr<WrapperBase> pointer = m_deferredObjects.last().release();
+ m_deferredObjects.removeLast();
+ pointer->process(this);
+ }
+}
+
+void MemoryInstrumentationImpl::deferObject(PassOwnPtr<WrapperBase> pointer)
+{
+ m_deferredObjects.append(pointer);
+}
+
+void MemoryInstrumentationImpl::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::InspectorMemoryAgent);
+ info.addMember(m_deferredObjects, "deferredObjects");
+}
+
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/MemoryInstrumentationImpl.h b/Source/core/inspector/MemoryInstrumentationImpl.h
new file mode 100644
index 0000000..aae2772
--- /dev/null
+++ b/Source/core/inspector/MemoryInstrumentationImpl.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2012 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 MemoryInstrumentationImpl_h
+#define MemoryInstrumentationImpl_h
+
+
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/MemoryInstrumentation.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+using WTF::MemoryObjectType;
+using WTF::MemberType;
+
+namespace WebCore {
+
+class HeapGraphSerializer;
+
+typedef HashSet<const void*> VisitedObjects;
+typedef HashMap<String, size_t> TypeNameToSizeMap;
+
+class MemoryInstrumentationClientImpl : public WTF::MemoryInstrumentationClient {
+public:
+ typedef HashMap<const void*, size_t> ObjectToSizeMap;
+
+ explicit MemoryInstrumentationClientImpl(HeapGraphSerializer* serializer)
+ : m_totalCountedObjects(0)
+ , m_totalObjectsNotInAllocatedSet(0)
+ , m_graphSerializer(serializer)
+ { }
+
+ size_t totalSize(MemoryObjectType objectType) const
+ {
+ TypeToSizeMap::const_iterator i = m_totalSizes.find(objectType);
+ return i == m_totalSizes.end() ? 0 : i->value;
+ }
+
+ size_t reportedSizeForAllTypes() const
+ {
+ size_t size = 0;
+ for (TypeToSizeMap::const_iterator i = m_totalSizes.begin(); i != m_totalSizes.end(); ++i)
+ size += i->value;
+ return size;
+ }
+
+ TypeNameToSizeMap sizesMap() const;
+ VisitedObjects& allocatedObjects() { return m_allocatedObjects; }
+ const ObjectToSizeMap& countedObjects() { return m_countedObjects; }
+
+ bool checkInstrumentedObjects() const { return !m_allocatedObjects.isEmpty(); }
+ size_t visitedObjects() const { return m_visitedObjects.size(); }
+ size_t totalCountedObjects() const { return m_totalCountedObjects; }
+ size_t totalObjectsNotInAllocatedSet() const { return m_totalObjectsNotInAllocatedSet; }
+
+ virtual void countObjectSize(const void*, MemoryObjectType, size_t) OVERRIDE;
+ virtual bool visited(const void*) OVERRIDE;
+ virtual bool checkCountedObject(const void*) OVERRIDE;
+ virtual void reportNode(const MemoryObjectInfo&) OVERRIDE;
+ virtual void reportEdge(const void*, const char*, MemberType) OVERRIDE;
+ virtual void reportLeaf(const MemoryObjectInfo&, const char*) OVERRIDE;
+ virtual void reportBaseAddress(const void*, const void*) OVERRIDE;
+ virtual int registerString(const char*) OVERRIDE;
+
+ void reportMemoryUsage(MemoryObjectInfo*) const;
+
+private:
+ typedef HashMap<MemoryObjectType, size_t> TypeToSizeMap;
+ TypeToSizeMap m_totalSizes;
+ VisitedObjects m_visitedObjects;
+ VisitedObjects m_allocatedObjects;
+ ObjectToSizeMap m_countedObjects;
+ size_t m_totalCountedObjects;
+ size_t m_totalObjectsNotInAllocatedSet;
+ HeapGraphSerializer* m_graphSerializer;
+};
+
+class MemoryInstrumentationImpl : public WTF::MemoryInstrumentation {
+public:
+ explicit MemoryInstrumentationImpl(WTF::MemoryInstrumentationClient* client)
+ : MemoryInstrumentation(client)
+ {
+ }
+
+ size_t selfSize() const;
+
+ void reportMemoryUsage(MemoryObjectInfo*) const;
+
+private:
+ virtual void deferObject(PassOwnPtr<WrapperBase>) OVERRIDE;
+ virtual void processDeferredObjects() OVERRIDE;
+
+ Vector<OwnPtr<WrapperBase> > m_deferredObjects;
+};
+
+} // namespace WebCore
+
+#endif // !defined(MemoryInstrumentationImpl_h)
+
diff --git a/Source/core/inspector/NetworkResourcesData.cpp b/Source/core/inspector/NetworkResourcesData.cpp
new file mode 100644
index 0000000..efb6932
--- /dev/null
+++ b/Source/core/inspector/NetworkResourcesData.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2011 Google 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 GOOGLE 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 GOOGLE 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 "core/inspector/NetworkResourcesData.h"
+
+#include "core/dom/DOMImplementation.h"
+#include "core/loader/TextResourceDecoder.h"
+#include "core/loader/cache/CachedResource.h"
+#include "core/platform/SharedBuffer.h"
+#include "core/platform/network/ResourceResponse.h"
+#include <wtf/MemoryInstrumentationHashMap.h>
+
+namespace {
+// 100MB
+static size_t maximumResourcesContentSize = 100 * 1000 * 1000;
+
+// 10MB
+static size_t maximumSingleResourceContentSize = 10 * 1000 * 1000;
+}
+
+namespace WebCore {
+
+
+PassRefPtr<XHRReplayData> XHRReplayData::create(const String &method, const KURL& url, bool async, PassRefPtr<FormData> formData, bool includeCredentials)
+{
+ return adoptRef(new XHRReplayData(method, url, async, formData, includeCredentials));
+}
+
+void XHRReplayData::addHeader(const AtomicString& key, const String& value)
+{
+ m_headers.set(key, value);
+}
+
+XHRReplayData::XHRReplayData(const String &method, const KURL& url, bool async, PassRefPtr<FormData> formData, bool includeCredentials)
+ : m_method(method)
+ , m_url(url)
+ , m_async(async)
+ , m_formData(formData)
+ , m_includeCredentials(includeCredentials)
+{
+}
+
+void XHRReplayData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this);
+ info.addMember(m_method, "method");
+ info.addMember(m_url, "url");
+ info.addMember(m_formData, "formData");
+ info.addMember(m_headers, "headers");
+}
+
+// ResourceData
+NetworkResourcesData::ResourceData::ResourceData(const String& requestId, const String& loaderId)
+ : m_requestId(requestId)
+ , m_loaderId(loaderId)
+ , m_base64Encoded(false)
+ , m_isContentEvicted(false)
+ , m_type(InspectorPageAgent::OtherResource)
+ , m_cachedResource(0)
+{
+}
+
+void NetworkResourcesData::ResourceData::setContent(const String& content, bool base64Encoded)
+{
+ ASSERT(!hasData());
+ ASSERT(!hasContent());
+ m_content = content;
+ m_base64Encoded = base64Encoded;
+}
+
+static size_t contentSizeInBytes(const String& content)
+{
+ return content.isNull() ? 0 : content.impl()->sizeInBytes();
+}
+
+unsigned NetworkResourcesData::ResourceData::removeContent()
+{
+ unsigned result = 0;
+ if (hasData()) {
+ ASSERT(!hasContent());
+ result = m_dataBuffer->size();
+ m_dataBuffer = nullptr;
+ }
+
+ if (hasContent()) {
+ ASSERT(!hasData());
+ result = contentSizeInBytes(m_content);
+ m_content = String();
+ }
+ return result;
+}
+
+unsigned NetworkResourcesData::ResourceData::evictContent()
+{
+ m_isContentEvicted = true;
+ return removeContent();
+}
+
+size_t NetworkResourcesData::ResourceData::dataLength() const
+{
+ return m_dataBuffer ? m_dataBuffer->size() : 0;
+}
+
+void NetworkResourcesData::ResourceData::appendData(const char* data, size_t dataLength)
+{
+ ASSERT(!hasContent());
+ if (!m_dataBuffer)
+ m_dataBuffer = SharedBuffer::create(data, dataLength);
+ else
+ m_dataBuffer->append(data, dataLength);
+}
+
+size_t NetworkResourcesData::ResourceData::decodeDataToContent()
+{
+ ASSERT(!hasContent());
+ size_t dataLength = m_dataBuffer->size();
+ m_content = m_decoder->decode(m_dataBuffer->data(), m_dataBuffer->size());
+ m_content.append(m_decoder->flush());
+ m_dataBuffer = nullptr;
+ return contentSizeInBytes(m_content) - dataLength;
+}
+
+void NetworkResourcesData::ResourceData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this);
+ info.addMember(m_requestId, "requestId");
+ info.addMember(m_loaderId, "loaderId");
+ info.addMember(m_frameId, "frameId");
+ info.addMember(m_url, "url");
+ info.addMember(m_content, "content");
+ info.addMember(m_xhrReplayData, "xhrReplayData");
+ info.addMember(m_dataBuffer, "dataBuffer");
+ info.addMember(m_textEncodingName, "textEncodingName");
+ info.addMember(m_decoder, "decoder");
+ info.addMember(m_buffer, "buffer");
+ info.addMember(m_cachedResource, "cachedResource");
+}
+
+// NetworkResourcesData
+NetworkResourcesData::NetworkResourcesData()
+ : m_contentSize(0)
+ , m_maximumResourcesContentSize(maximumResourcesContentSize)
+ , m_maximumSingleResourceContentSize(maximumSingleResourceContentSize)
+{
+}
+
+NetworkResourcesData::~NetworkResourcesData()
+{
+ clear();
+}
+
+void NetworkResourcesData::resourceCreated(const String& requestId, const String& loaderId)
+{
+ ensureNoDataForRequestId(requestId);
+ m_requestIdToResourceDataMap.set(requestId, new ResourceData(requestId, loaderId));
+}
+
+static PassRefPtr<TextResourceDecoder> createOtherResourceTextDecoder(const String& mimeType, const String& textEncodingName)
+{
+ RefPtr<TextResourceDecoder> decoder;
+ if (!textEncodingName.isEmpty())
+ decoder = TextResourceDecoder::create("text/plain", textEncodingName);
+ else if (DOMImplementation::isXMLMIMEType(mimeType.lower())) {
+ decoder = TextResourceDecoder::create("application/xml");
+ decoder->useLenientXMLDecoding();
+ } else if (equalIgnoringCase(mimeType, "text/html"))
+ decoder = TextResourceDecoder::create("text/html", "UTF-8");
+ else if (mimeType == "text/plain")
+ decoder = TextResourceDecoder::create("text/plain", "ISO-8859-1");
+ return decoder;
+}
+
+void NetworkResourcesData::responseReceived(const String& requestId, const String& frameId, const ResourceResponse& response)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return;
+ resourceData->setFrameId(frameId);
+ resourceData->setUrl(response.url());
+ resourceData->setDecoder(createOtherResourceTextDecoder(response.mimeType(), response.textEncodingName()));
+ resourceData->setHTTPStatusCode(response.httpStatusCode());
+}
+
+void NetworkResourcesData::setResourceType(const String& requestId, InspectorPageAgent::ResourceType type)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return;
+ resourceData->setType(type);
+}
+
+InspectorPageAgent::ResourceType NetworkResourcesData::resourceType(const String& requestId)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return InspectorPageAgent::OtherResource;
+ return resourceData->type();
+}
+
+void NetworkResourcesData::setResourceContent(const String& requestId, const String& content, bool base64Encoded)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return;
+ size_t dataLength = contentSizeInBytes(content);
+ if (dataLength > m_maximumSingleResourceContentSize)
+ return;
+ if (resourceData->isContentEvicted())
+ return;
+ if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
+ // We can not be sure that we didn't try to save this request data while it was loading, so remove it, if any.
+ if (resourceData->hasContent())
+ m_contentSize -= resourceData->removeContent();
+ m_requestIdsDeque.append(requestId);
+ resourceData->setContent(content, base64Encoded);
+ m_contentSize += dataLength;
+ }
+}
+
+void NetworkResourcesData::maybeAddResourceData(const String& requestId, const char* data, size_t dataLength)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return;
+ if (!resourceData->decoder())
+ return;
+ if (resourceData->dataLength() + dataLength > m_maximumSingleResourceContentSize)
+ m_contentSize -= resourceData->evictContent();
+ if (resourceData->isContentEvicted())
+ return;
+ if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
+ m_requestIdsDeque.append(requestId);
+ resourceData->appendData(data, dataLength);
+ m_contentSize += dataLength;
+ }
+}
+
+void NetworkResourcesData::maybeDecodeDataToContent(const String& requestId)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return;
+ if (!resourceData->hasData())
+ return;
+ m_contentSize += resourceData->decodeDataToContent();
+ size_t dataLength = contentSizeInBytes(resourceData->content());
+ if (dataLength > m_maximumSingleResourceContentSize)
+ m_contentSize -= resourceData->evictContent();
+}
+
+void NetworkResourcesData::addCachedResource(const String& requestId, CachedResource* cachedResource)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return;
+ resourceData->setCachedResource(cachedResource);
+}
+
+void NetworkResourcesData::addResourceSharedBuffer(const String& requestId, PassRefPtr<SharedBuffer> buffer, const String& textEncodingName)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return;
+ resourceData->setBuffer(buffer);
+ resourceData->setTextEncodingName(textEncodingName);
+}
+
+NetworkResourcesData::ResourceData const* NetworkResourcesData::data(const String& requestId)
+{
+ return resourceDataForRequestId(requestId);
+}
+
+XHRReplayData* NetworkResourcesData::xhrReplayData(const String& requestId)
+{
+ if (m_reusedXHRReplayDataRequestIds.contains(requestId))
+ return xhrReplayData(m_reusedXHRReplayDataRequestIds.get(requestId));
+
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return 0;
+ return resourceData->xhrReplayData();
+}
+
+void NetworkResourcesData::setXHRReplayData(const String& requestId, XHRReplayData* xhrReplayData)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData) {
+ Vector<String> result;
+ ReusedRequestIds::iterator it;
+ ReusedRequestIds::iterator end = m_reusedXHRReplayDataRequestIds.end();
+ for (it = m_reusedXHRReplayDataRequestIds.begin(); it != end; ++it) {
+ if (it->value == requestId)
+ setXHRReplayData(it->key, xhrReplayData);
+ }
+ return;
+ }
+
+ resourceData->setXHRReplayData(xhrReplayData);
+}
+
+void NetworkResourcesData::reuseXHRReplayData(const String& requestId, const String& reusedRequestId)
+{
+ ResourceData* reusedResourceData = resourceDataForRequestId(reusedRequestId);
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!reusedResourceData || !resourceData) {
+ m_reusedXHRReplayDataRequestIds.set(requestId, reusedRequestId);
+ return;
+ }
+
+ resourceData->setXHRReplayData(reusedResourceData->xhrReplayData());
+}
+
+Vector<String> NetworkResourcesData::removeCachedResource(CachedResource* cachedResource)
+{
+ Vector<String> result;
+ ResourceDataMap::iterator it;
+ ResourceDataMap::iterator end = m_requestIdToResourceDataMap.end();
+ for (it = m_requestIdToResourceDataMap.begin(); it != end; ++it) {
+ ResourceData* resourceData = it->value;
+ if (resourceData->cachedResource() == cachedResource) {
+ resourceData->setCachedResource(0);
+ result.append(it->key);
+ }
+ }
+
+ return result;
+}
+
+void NetworkResourcesData::clear(const String& preservedLoaderId)
+{
+ m_requestIdsDeque.clear();
+ m_contentSize = 0;
+
+ ResourceDataMap preservedMap;
+
+ ResourceDataMap::iterator it;
+ ResourceDataMap::iterator end = m_requestIdToResourceDataMap.end();
+ for (it = m_requestIdToResourceDataMap.begin(); it != end; ++it) {
+ ResourceData* resourceData = it->value;
+ if (!preservedLoaderId.isNull() && resourceData->loaderId() == preservedLoaderId)
+ preservedMap.set(it->key, it->value);
+ else
+ delete resourceData;
+ }
+ m_requestIdToResourceDataMap.swap(preservedMap);
+
+ m_reusedXHRReplayDataRequestIds.clear();
+}
+
+void NetworkResourcesData::setResourcesDataSizeLimits(size_t maximumResourcesContentSize, size_t maximumSingleResourceContentSize)
+{
+ clear();
+ m_maximumResourcesContentSize = maximumResourcesContentSize;
+ m_maximumSingleResourceContentSize = maximumSingleResourceContentSize;
+}
+
+NetworkResourcesData::ResourceData* NetworkResourcesData::resourceDataForRequestId(const String& requestId)
+{
+ if (requestId.isNull())
+ return 0;
+ return m_requestIdToResourceDataMap.get(requestId);
+}
+
+void NetworkResourcesData::ensureNoDataForRequestId(const String& requestId)
+{
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (!resourceData)
+ return;
+ if (resourceData->hasContent() || resourceData->hasData())
+ m_contentSize -= resourceData->evictContent();
+ delete resourceData;
+ m_requestIdToResourceDataMap.remove(requestId);
+}
+
+bool NetworkResourcesData::ensureFreeSpace(size_t size)
+{
+ if (size > m_maximumResourcesContentSize)
+ return false;
+
+ while (size > m_maximumResourcesContentSize - m_contentSize) {
+ String requestId = m_requestIdsDeque.takeFirst();
+ ResourceData* resourceData = resourceDataForRequestId(requestId);
+ if (resourceData)
+ m_contentSize -= resourceData->evictContent();
+ }
+ return true;
+}
+
+void NetworkResourcesData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+{
+ MemoryClassInfo info(memoryObjectInfo, this);
+ info.addMember(m_requestIdsDeque, "requestIdsDeque");
+ info.addMember(m_reusedXHRReplayDataRequestIds, "reusedXHRReplayDataRequestIds");
+ info.addMember(m_requestIdToResourceDataMap, "requestIdToResourceDataMap");
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/NetworkResourcesData.h b/Source/core/inspector/NetworkResourcesData.h
new file mode 100644
index 0000000..4394a91
--- /dev/null
+++ b/Source/core/inspector/NetworkResourcesData.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2011 Google 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 GOOGLE 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 GOOGLE 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 NetworkResourcesData_h
+#define NetworkResourcesData_h
+
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/loader/TextResourceDecoder.h"
+#include "core/platform/network/HTTPHeaderMap.h"
+#include <wtf/Deque.h>
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+
+
+namespace WebCore {
+
+class CachedResource;
+class FormData;
+class SharedBuffer;
+class TextResourceDecoder;
+
+class XHRReplayData : public RefCounted<XHRReplayData> {
+public:
+ static PassRefPtr<XHRReplayData> create(const String &method, const KURL&, bool async, PassRefPtr<FormData>, bool includeCredentials);
+
+ void addHeader(const AtomicString& key, const String& value);
+ const String& method() const { return m_method; }
+ const KURL& url() const { return m_url; }
+ bool async() const { return m_async; }
+ PassRefPtr<FormData> formData() const { return m_formData; }
+ const HTTPHeaderMap& headers() const { return m_headers; }
+ bool includeCredentials() const { return m_includeCredentials; }
+ void reportMemoryUsage(MemoryObjectInfo*) const;
+private:
+ XHRReplayData(const String &method, const KURL&, bool async, PassRefPtr<FormData>, bool includeCredentials);
+
+ String m_method;
+ KURL m_url;
+ bool m_async;
+ RefPtr<FormData> m_formData;
+ HTTPHeaderMap m_headers;
+ bool m_includeCredentials;
+};
+
+class NetworkResourcesData {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ class ResourceData {
+ WTF_MAKE_FAST_ALLOCATED;
+ friend class NetworkResourcesData;
+ public:
+ ResourceData(const String& requestId, const String& loaderId);
+
+ String requestId() const { return m_requestId; }
+ String loaderId() const { return m_loaderId; }
+
+ String frameId() const { return m_frameId; }
+ void setFrameId(const String& frameId) { m_frameId = frameId; }
+
+ String url() const { return m_url; }
+ void setUrl(const String& url) { m_url = url; }
+
+ bool hasContent() const { return !m_content.isNull(); }
+ String content() const { return m_content; }
+ void setContent(const String&, bool base64Encoded);
+
+ bool base64Encoded() const { return m_base64Encoded; }
+
+ unsigned removeContent();
+ bool isContentEvicted() const { return m_isContentEvicted; }
+ unsigned evictContent();
+
+ InspectorPageAgent::ResourceType type() const { return m_type; }
+ void setType(InspectorPageAgent::ResourceType type) { m_type = type; }
+
+ int httpStatusCode() const { return m_httpStatusCode; }
+ void setHTTPStatusCode(int httpStatusCode) { m_httpStatusCode = httpStatusCode; }
+
+ String textEncodingName() const { return m_textEncodingName; }
+ void setTextEncodingName(const String& textEncodingName) { m_textEncodingName = textEncodingName; }
+
+ PassRefPtr<TextResourceDecoder> decoder() const { return m_decoder; }
+ void setDecoder(PassRefPtr<TextResourceDecoder> decoder) { m_decoder = decoder; }
+
+ PassRefPtr<SharedBuffer> buffer() const { return m_buffer; }
+ void setBuffer(PassRefPtr<SharedBuffer> buffer) { m_buffer = buffer; }
+
+ CachedResource* cachedResource() const { return m_cachedResource; }
+ void setCachedResource(CachedResource* cachedResource) { m_cachedResource = cachedResource; }
+
+ XHRReplayData* xhrReplayData() const { return m_xhrReplayData.get(); }
+ void setXHRReplayData(XHRReplayData* xhrReplayData) { m_xhrReplayData = xhrReplayData; }
+
+ void reportMemoryUsage(MemoryObjectInfo*) const;
+
+ private:
+ bool hasData() const { return m_dataBuffer; }
+ size_t dataLength() const;
+ void appendData(const char* data, size_t dataLength);
+ size_t decodeDataToContent();
+
+ String m_requestId;
+ String m_loaderId;
+ String m_frameId;
+ String m_url;
+ String m_content;
+ RefPtr<XHRReplayData> m_xhrReplayData;
+ bool m_base64Encoded;
+ RefPtr<SharedBuffer> m_dataBuffer;
+ bool m_isContentEvicted;
+ InspectorPageAgent::ResourceType m_type;
+ int m_httpStatusCode;
+
+ String m_textEncodingName;
+ RefPtr<TextResourceDecoder> m_decoder;
+
+ RefPtr<SharedBuffer> m_buffer;
+ CachedResource* m_cachedResource;
+ };
+
+ NetworkResourcesData();
+
+ ~NetworkResourcesData();
+
+ void resourceCreated(const String& requestId, const String& loaderId);
+ void responseReceived(const String& requestId, const String& frameId, const ResourceResponse&);
+ void setResourceType(const String& requestId, InspectorPageAgent::ResourceType);
+ InspectorPageAgent::ResourceType resourceType(const String& requestId);
+ void setResourceContent(const String& requestId, const String& content, bool base64Encoded = false);
+ void maybeAddResourceData(const String& requestId, const char* data, size_t dataLength);
+ void maybeDecodeDataToContent(const String& requestId);
+ void addCachedResource(const String& requestId, CachedResource*);
+ void addResourceSharedBuffer(const String& requestId, PassRefPtr<SharedBuffer>, const String& textEncodingName);
+ ResourceData const* data(const String& requestId);
+ Vector<String> removeCachedResource(CachedResource*);
+ void clear(const String& preservedLoaderId = String());
+
+ void setResourcesDataSizeLimits(size_t maximumResourcesContentSize, size_t maximumSingleResourceContentSize);
+ void setXHRReplayData(const String& requestId, XHRReplayData*);
+ void reuseXHRReplayData(const String& requestId, const String& reusedRequestId);
+ XHRReplayData* xhrReplayData(const String& requestId);
+
+ void reportMemoryUsage(MemoryObjectInfo*) const;
+
+private:
+ ResourceData* resourceDataForRequestId(const String& requestId);
+ void ensureNoDataForRequestId(const String& requestId);
+ bool ensureFreeSpace(size_t);
+
+ Deque<String> m_requestIdsDeque;
+
+ typedef HashMap<String, String> ReusedRequestIds;
+ ReusedRequestIds m_reusedXHRReplayDataRequestIds;
+ typedef HashMap<String, ResourceData*> ResourceDataMap;
+ ResourceDataMap m_requestIdToResourceDataMap;
+ size_t m_contentSize;
+ size_t m_maximumResourcesContentSize;
+ size_t m_maximumSingleResourceContentSize;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(NetworkResourcesData_h)
diff --git a/Source/core/inspector/PageConsoleAgent.cpp b/Source/core/inspector/PageConsoleAgent.cpp
new file mode 100644
index 0000000..2caee57
--- /dev/null
+++ b/Source/core/inspector/PageConsoleAgent.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/PageConsoleAgent.h"
+
+#include "bindings/v8/ScriptObject.h"
+#include "core/dom/Node.h"
+#include "core/inspector/InjectedScriptHost.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorAgent.h"
+#include "core/inspector/InspectorDOMAgent.h"
+#include "core/page/DOMWindow.h"
+
+namespace WebCore {
+
+PageConsoleAgent::PageConsoleAgent(InstrumentingAgents* instrumentingAgents, InspectorAgent* inspectorAgent, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, InspectorDOMAgent* domAgent)
+ : InspectorConsoleAgent(instrumentingAgents, state, injectedScriptManager)
+ , m_inspectorAgent(inspectorAgent)
+ , m_inspectorDOMAgent(domAgent)
+{
+}
+
+PageConsoleAgent::~PageConsoleAgent()
+{
+ m_inspectorAgent = 0;
+ m_inspectorDOMAgent = 0;
+}
+
+void PageConsoleAgent::clearMessages(ErrorString* errorString)
+{
+ m_inspectorDOMAgent->releaseDanglingNodes();
+ InspectorConsoleAgent::clearMessages(errorString);
+}
+
+class InspectableNode : public InjectedScriptHost::InspectableObject {
+public:
+ explicit InspectableNode(Node* node) : m_node(node) { }
+ virtual ScriptValue get(ScriptState* state)
+ {
+ return InjectedScriptHost::nodeAsScriptValue(state, m_node);
+ }
+private:
+ Node* m_node;
+};
+
+void PageConsoleAgent::addInspectedNode(ErrorString* errorString, int nodeId)
+{
+ Node* node = m_inspectorDOMAgent->nodeForId(nodeId);
+ if (!node || node->isInShadowTree()) {
+ *errorString = "nodeId is not valid";
+ return;
+ }
+ m_injectedScriptManager->injectedScriptHost()->addInspectedObject(adoptPtr(new InspectableNode(node)));
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/PageConsoleAgent.h b/Source/core/inspector/PageConsoleAgent.h
new file mode 100644
index 0000000..13607b9
--- /dev/null
+++ b/Source/core/inspector/PageConsoleAgent.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 PageConsoleAgent_h
+#define PageConsoleAgent_h
+
+#include "core/inspector/InspectorConsoleAgent.h"
+#include <wtf/PassOwnPtr.h>
+
+
+namespace WebCore {
+
+class InspectorAgent;
+class InspectorDOMAgent;
+
+class PageConsoleAgent : public InspectorConsoleAgent {
+ WTF_MAKE_NONCOPYABLE(PageConsoleAgent);
+public:
+ static PassOwnPtr<PageConsoleAgent> create(InstrumentingAgents* instrumentingAgents, InspectorAgent* agent, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, InspectorDOMAgent* domAgent)
+ {
+ return adoptPtr(new PageConsoleAgent(instrumentingAgents, agent, state, injectedScriptManager, domAgent));
+ }
+ virtual ~PageConsoleAgent();
+
+ virtual bool isWorkerAgent() OVERRIDE { return false; }
+
+private:
+ PageConsoleAgent(InstrumentingAgents*, InspectorAgent*, InspectorCompositeState*, InjectedScriptManager*, InspectorDOMAgent*);
+ virtual void clearMessages(ErrorString*);
+ virtual void addInspectedNode(ErrorString*, int nodeId);
+
+ InspectorAgent* m_inspectorAgent;
+ InspectorDOMAgent* m_inspectorDOMAgent;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(PageConsoleAgent_h)
diff --git a/Source/core/inspector/PageDebuggerAgent.cpp b/Source/core/inspector/PageDebuggerAgent.cpp
new file mode 100644
index 0000000..f108a37
--- /dev/null
+++ b/Source/core/inspector/PageDebuggerAgent.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/PageDebuggerAgent.h"
+
+#include "bindings/v8/PageScriptDebugServer.h"
+#include "core/inspector/InspectorOverlay.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/page/Page.h"
+#include "core/page/PageConsole.h"
+
+namespace WebCore {
+
+PassOwnPtr<PageDebuggerAgent> PageDebuggerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InspectorPageAgent* pageAgent, InjectedScriptManager* injectedScriptManager, InspectorOverlay* overlay)
+{
+ return adoptPtr(new PageDebuggerAgent(instrumentingAgents, inspectorState, pageAgent, injectedScriptManager, overlay));
+}
+
+PageDebuggerAgent::PageDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InspectorPageAgent* pageAgent, InjectedScriptManager* injectedScriptManager, InspectorOverlay* overlay)
+ : InspectorDebuggerAgent(instrumentingAgents, inspectorState, injectedScriptManager)
+ , m_pageAgent(pageAgent)
+ , m_overlay(overlay)
+{
+}
+
+PageDebuggerAgent::~PageDebuggerAgent()
+{
+}
+
+void PageDebuggerAgent::enable()
+{
+ InspectorDebuggerAgent::enable();
+ m_instrumentingAgents->setPageDebuggerAgent(this);
+}
+
+void PageDebuggerAgent::disable()
+{
+ InspectorDebuggerAgent::disable();
+ m_instrumentingAgents->setPageDebuggerAgent(0);
+}
+
+void PageDebuggerAgent::startListeningScriptDebugServer()
+{
+ scriptDebugServer().addListener(this, m_pageAgent->page());
+}
+
+void PageDebuggerAgent::stopListeningScriptDebugServer()
+{
+ scriptDebugServer().removeListener(this, m_pageAgent->page());
+}
+
+PageScriptDebugServer& PageDebuggerAgent::scriptDebugServer()
+{
+ return PageScriptDebugServer::shared();
+}
+
+void PageDebuggerAgent::muteConsole()
+{
+ PageConsole::mute();
+}
+
+void PageDebuggerAgent::unmuteConsole()
+{
+ PageConsole::unmute();
+}
+
+InjectedScript PageDebuggerAgent::injectedScriptForEval(ErrorString* errorString, const int* executionContextId)
+{
+ if (!executionContextId) {
+ ScriptState* scriptState = mainWorldScriptState(m_pageAgent->mainFrame());
+ return injectedScriptManager()->injectedScriptFor(scriptState);
+ }
+ InjectedScript injectedScript = injectedScriptManager()->injectedScriptForId(*executionContextId);
+ if (injectedScript.hasNoValue())
+ *errorString = "Execution context with given id not found.";
+ return injectedScript;
+}
+
+void PageDebuggerAgent::setOverlayMessage(ErrorString*, const String* message)
+{
+ m_overlay->setPausedInDebuggerMessage(message);
+}
+
+void PageDebuggerAgent::didClearMainFrameWindowObject()
+{
+ reset();
+ scriptDebugServer().setScriptPreprocessor(m_pageAgent->scriptPreprocessor());
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/PageDebuggerAgent.h b/Source/core/inspector/PageDebuggerAgent.h
new file mode 100644
index 0000000..61d0a0a
--- /dev/null
+++ b/Source/core/inspector/PageDebuggerAgent.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 PageDebuggerAgent_h
+#define PageDebuggerAgent_h
+
+#include "bindings/v8/PageScriptDebugServer.h"
+#include "core/inspector/InspectorDebuggerAgent.h"
+
+namespace WebCore {
+
+class InspectorOverlay;
+class InspectorPageAgent;
+class Page;
+class PageScriptDebugServer;
+
+class PageDebuggerAgent : public InspectorDebuggerAgent {
+ WTF_MAKE_NONCOPYABLE(PageDebuggerAgent);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ static PassOwnPtr<PageDebuggerAgent> create(InstrumentingAgents*, InspectorCompositeState*, InspectorPageAgent*, InjectedScriptManager*, InspectorOverlay*);
+ virtual ~PageDebuggerAgent();
+
+ void didClearMainFrameWindowObject();
+
+protected:
+ virtual void enable();
+ virtual void disable();
+
+private:
+ virtual void startListeningScriptDebugServer();
+ virtual void stopListeningScriptDebugServer();
+ virtual PageScriptDebugServer& scriptDebugServer();
+ virtual void muteConsole();
+ virtual void unmuteConsole();
+
+ virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId);
+ virtual void setOverlayMessage(ErrorString*, const String*);
+
+ PageDebuggerAgent(InstrumentingAgents*, InspectorCompositeState*, InspectorPageAgent*, InjectedScriptManager*, InspectorOverlay*);
+ InspectorPageAgent* m_pageAgent;
+ InspectorOverlay* m_overlay;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(PageDebuggerAgent_h)
diff --git a/Source/core/inspector/PageRuntimeAgent.cpp b/Source/core/inspector/PageRuntimeAgent.cpp
new file mode 100644
index 0000000..37e7ed5
--- /dev/null
+++ b/Source/core/inspector/PageRuntimeAgent.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/PageRuntimeAgent.h"
+
+#include "bindings/v8/ScriptController.h"
+#include "core/dom/Document.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorPageAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/page/Page.h"
+#include "core/page/PageConsole.h"
+#include "core/page/SecurityOrigin.h"
+
+using WebCore::TypeBuilder::Runtime::ExecutionContextDescription;
+
+namespace WebCore {
+
+namespace PageRuntimeAgentState {
+static const char runtimeEnabled[] = "runtimeEnabled";
+};
+
+PageRuntimeAgent::PageRuntimeAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, Page* page, InspectorPageAgent* pageAgent)
+ : InspectorRuntimeAgent(instrumentingAgents, state, injectedScriptManager)
+ , m_inspectedPage(page)
+ , m_pageAgent(pageAgent)
+ , m_frontend(0)
+ , m_mainWorldContextCreated(false)
+{
+ m_instrumentingAgents->setPageRuntimeAgent(this);
+}
+
+PageRuntimeAgent::~PageRuntimeAgent()
+{
+ m_instrumentingAgents->setPageRuntimeAgent(0);
+}
+
+void PageRuntimeAgent::setFrontend(InspectorFrontend* frontend)
+{
+ m_frontend = frontend->runtime();
+}
+
+void PageRuntimeAgent::clearFrontend()
+{
+ m_frontend = 0;
+ String errorString;
+ disable(&errorString);
+}
+
+void PageRuntimeAgent::restore()
+{
+ if (m_state->getBoolean(PageRuntimeAgentState::runtimeEnabled)) {
+ String error;
+ enable(&error);
+ }
+}
+
+void PageRuntimeAgent::enable(ErrorString* errorString)
+{
+ if (m_enabled)
+ return;
+
+ InspectorRuntimeAgent::enable(errorString);
+ m_state->setBoolean(PageRuntimeAgentState::runtimeEnabled, true);
+ // Only report existing contexts if the page did commit load, otherwise we may
+ // unintentionally initialize contexts in the frames which may trigger some listeners
+ // that are expected to be triggered only after the load is committed, see http://crbug.com/131623
+ if (m_mainWorldContextCreated)
+ reportExecutionContextCreation();
+}
+
+void PageRuntimeAgent::disable(ErrorString* errorString)
+{
+ if (!m_enabled)
+ return;
+
+ InspectorRuntimeAgent::disable(errorString);
+ m_state->setBoolean(PageRuntimeAgentState::runtimeEnabled, false);
+}
+
+void PageRuntimeAgent::didCreateMainWorldContext(Frame* frame)
+{
+ m_mainWorldContextCreated = true;
+
+ if (!m_enabled)
+ return;
+ ASSERT(m_frontend);
+ String frameId = m_pageAgent->frameId(frame);
+ ScriptState* scriptState = mainWorldScriptState(frame);
+ notifyContextCreated(frameId, scriptState, 0, true);
+}
+
+void PageRuntimeAgent::didCreateIsolatedContext(Frame* frame, ScriptState* scriptState, SecurityOrigin* origin)
+{
+ if (!m_enabled)
+ return;
+ ASSERT(m_frontend);
+ String frameId = m_pageAgent->frameId(frame);
+ notifyContextCreated(frameId, scriptState, origin, false);
+}
+
+InjectedScript PageRuntimeAgent::injectedScriptForEval(ErrorString* errorString, const int* executionContextId)
+{
+ if (!executionContextId) {
+ ScriptState* scriptState = mainWorldScriptState(m_inspectedPage->mainFrame());
+ InjectedScript result = injectedScriptManager()->injectedScriptFor(scriptState);
+ if (result.hasNoValue())
+ *errorString = "Internal error: main world execution context not found.";
+ return result;
+ }
+ InjectedScript injectedScript = injectedScriptManager()->injectedScriptForId(*executionContextId);
+ if (injectedScript.hasNoValue())
+ *errorString = "Execution context with given id not found.";
+ return injectedScript;
+}
+
+void PageRuntimeAgent::muteConsole()
+{
+ PageConsole::mute();
+}
+
+void PageRuntimeAgent::unmuteConsole()
+{
+ PageConsole::unmute();
+}
+
+void PageRuntimeAgent::reportExecutionContextCreation()
+{
+ Vector<std::pair<ScriptState*, SecurityOrigin*> > isolatedContexts;
+ for (Frame* frame = m_inspectedPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript))
+ continue;
+ String frameId = m_pageAgent->frameId(frame);
+
+ ScriptState* scriptState = mainWorldScriptState(frame);
+ notifyContextCreated(frameId, scriptState, 0, true);
+ frame->script()->collectIsolatedContexts(isolatedContexts);
+ if (isolatedContexts.isEmpty())
+ continue;
+ for (size_t i = 0; i< isolatedContexts.size(); i++)
+ notifyContextCreated(frameId, isolatedContexts[i].first, isolatedContexts[i].second, false);
+ isolatedContexts.clear();
+ }
+}
+
+void PageRuntimeAgent::notifyContextCreated(const String& frameId, ScriptState* scriptState, SecurityOrigin* securityOrigin, bool isPageContext)
+{
+ ASSERT(securityOrigin || isPageContext);
+ int executionContextId = injectedScriptManager()->injectedScriptIdFor(scriptState);
+ String name = securityOrigin ? securityOrigin->toRawString() : "";
+ m_frontend->executionContextCreated(ExecutionContextDescription::create()
+ .setId(executionContextId)
+ .setIsPageContext(isPageContext)
+ .setName(name)
+ .setFrameId(frameId)
+ .release());
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/PageRuntimeAgent.h b/Source/core/inspector/PageRuntimeAgent.h
new file mode 100644
index 0000000..bdf131a
--- /dev/null
+++ b/Source/core/inspector/PageRuntimeAgent.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 PageRuntimeAgent_h
+#define PageRuntimeAgent_h
+
+
+#include "InspectorFrontend.h"
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/InspectorRuntimeAgent.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class InspectorPageAgent;
+class Page;
+class SecurityOrigin;
+
+class PageRuntimeAgent : public InspectorRuntimeAgent {
+public:
+ static PassOwnPtr<PageRuntimeAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, Page* page, InspectorPageAgent* pageAgent)
+ {
+ return adoptPtr(new PageRuntimeAgent(instrumentingAgents, state, injectedScriptManager, page, pageAgent));
+ }
+ virtual ~PageRuntimeAgent();
+ virtual void setFrontend(InspectorFrontend*);
+ virtual void clearFrontend();
+ virtual void restore();
+ virtual void enable(ErrorString*);
+ virtual void disable(ErrorString*);
+
+ void didCreateMainWorldContext(Frame*);
+ void didCreateIsolatedContext(Frame*, ScriptState*, SecurityOrigin*);
+
+private:
+ PageRuntimeAgent(InstrumentingAgents*, InspectorCompositeState*, InjectedScriptManager*, Page*, InspectorPageAgent*);
+
+ virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId);
+ virtual void muteConsole();
+ virtual void unmuteConsole();
+ void reportExecutionContextCreation();
+ void notifyContextCreated(const String& frameId, ScriptState*, SecurityOrigin*, bool isPageContext);
+
+ Page* m_inspectedPage;
+ InspectorPageAgent* m_pageAgent;
+ InspectorFrontend::Runtime* m_frontend;
+ bool m_mainWorldContextCreated;
+};
+
+} // namespace WebCore
+
+
+#endif // !defined(InspectorPagerAgent_h)
diff --git a/Source/core/inspector/ScriptArguments.cpp b/Source/core/inspector/ScriptArguments.cpp
new file mode 100644
index 0000000..516cd04
--- /dev/null
+++ b/Source/core/inspector/ScriptArguments.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/ScriptArguments.h"
+
+#include "bindings/v8/ScriptValue.h"
+
+namespace WebCore {
+
+PassRefPtr<ScriptArguments> ScriptArguments::create(ScriptState* scriptState, Vector<ScriptValue>& arguments)
+{
+ return adoptRef(new ScriptArguments(scriptState, arguments));
+}
+
+ScriptArguments::ScriptArguments(ScriptState* scriptState, Vector<ScriptValue>& arguments)
+ : m_scriptState(scriptState)
+{
+ m_arguments.swap(arguments);
+}
+
+ScriptArguments::~ScriptArguments()
+{
+}
+
+const ScriptValue &ScriptArguments::argumentAt(size_t index) const
+{
+ ASSERT(m_arguments.size() > index);
+ return m_arguments[index];
+}
+
+ScriptState* ScriptArguments::globalState() const
+{
+ return m_scriptState.get();
+}
+
+bool ScriptArguments::getFirstArgumentAsString(String& result, bool checkForNullOrUndefined)
+{
+ if (!argumentCount())
+ return false;
+
+ const ScriptValue& value = argumentAt(0);
+ if (checkForNullOrUndefined && (value.isNull() || value.isUndefined()))
+ return false;
+
+ if (!globalState()) {
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ result = value.toString(globalState());
+ return true;
+}
+
+bool ScriptArguments::isEqual(ScriptArguments* other) const
+{
+ if (!other)
+ return false;
+
+ if (m_arguments.size() != other->m_arguments.size())
+ return false;
+ if (!globalState() && m_arguments.size())
+ return false;
+
+ for (size_t i = 0; i < m_arguments.size(); ++i) {
+ if (!m_arguments[i].isEqual(other->globalState(), other->m_arguments[i]))
+ return false;
+ }
+ return true;
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/ScriptArguments.h b/Source/core/inspector/ScriptArguments.h
new file mode 100644
index 0000000..e8d5443
--- /dev/null
+++ b/Source/core/inspector/ScriptArguments.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 ScriptArguments_h
+#define ScriptArguments_h
+
+#include "bindings/v8/ScriptState.h"
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ScriptValue;
+
+class ScriptArguments : public RefCounted<ScriptArguments> {
+public:
+ static PassRefPtr<ScriptArguments> create(ScriptState*, Vector<ScriptValue>& arguments);
+
+ ~ScriptArguments();
+
+ const ScriptValue& argumentAt(size_t) const;
+ size_t argumentCount() const { return m_arguments.size(); }
+
+ ScriptState* globalState() const;
+
+ bool getFirstArgumentAsString(WTF::String& result, bool checkForNullOrUndefined = false);
+ bool isEqual(ScriptArguments*) const;
+
+private:
+ ScriptArguments(ScriptState*, Vector<ScriptValue>& arguments);
+
+ ScriptStateProtectedPtr m_scriptState;
+ Vector<ScriptValue> m_arguments;
+};
+
+} // namespace WebCore
+
+#endif // ScriptArguments_h
diff --git a/Source/core/inspector/ScriptBreakpoint.h b/Source/core/inspector/ScriptBreakpoint.h
new file mode 100644
index 0000000..11e8d51
--- /dev/null
+++ b/Source/core/inspector/ScriptBreakpoint.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 ScriptBreakpoint_h
+#define ScriptBreakpoint_h
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+struct ScriptBreakpoint {
+ ScriptBreakpoint()
+ {
+ }
+
+ ScriptBreakpoint(int lineNumber, int columnNumber, const String& condition)
+ : lineNumber(lineNumber)
+ , columnNumber(columnNumber)
+ , condition(condition)
+ {
+ }
+
+ int lineNumber;
+ int columnNumber;
+ String condition;
+};
+
+} // namespace WebCore
+
+#endif // !defined(ScriptBreakpoint_h)
diff --git a/Source/core/inspector/ScriptCallFrame.cpp b/Source/core/inspector/ScriptCallFrame.cpp
new file mode 100644
index 0000000..67a3c12
--- /dev/null
+++ b/Source/core/inspector/ScriptCallFrame.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/ScriptCallFrame.h"
+
+#include "InspectorFrontend.h"
+#include "core/inspector/InspectorValues.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ScriptCallFrame::ScriptCallFrame(const String& functionName, const String& scriptName, unsigned lineNumber, unsigned column)
+ : m_functionName(functionName)
+ , m_scriptName(scriptName)
+ , m_lineNumber(lineNumber)
+ , m_column(column)
+{
+}
+
+ScriptCallFrame::~ScriptCallFrame()
+{
+}
+
+bool ScriptCallFrame::isEqual(const ScriptCallFrame& o) const
+{
+ return m_functionName == o.m_functionName
+ && m_scriptName == o.m_scriptName
+ && m_lineNumber == o.m_lineNumber;
+}
+
+PassRefPtr<TypeBuilder::Console::CallFrame> ScriptCallFrame::buildInspectorObject() const
+{
+ return TypeBuilder::Console::CallFrame::create()
+ .setFunctionName(m_functionName)
+ .setUrl(m_scriptName)
+ .setLineNumber(m_lineNumber)
+ .setColumnNumber(m_column)
+ .release();
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/ScriptCallFrame.h b/Source/core/inspector/ScriptCallFrame.h
new file mode 100644
index 0000000..93fc006
--- /dev/null
+++ b/Source/core/inspector/ScriptCallFrame.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 ScriptCallFrame_h
+#define ScriptCallFrame_h
+
+#include "InspectorTypeBuilder.h"
+
+#include <wtf/Forward.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InspectorObject;
+
+class ScriptCallFrame {
+public:
+ ScriptCallFrame(const String& functionName, const String& scriptName, unsigned lineNumber, unsigned column = 0);
+ ~ScriptCallFrame();
+
+ const String& functionName() const { return m_functionName; }
+ const String& sourceURL() const { return m_scriptName; }
+ unsigned lineNumber() const { return m_lineNumber; }
+ unsigned columnNumber() const { return m_column; }
+
+ bool isEqual(const ScriptCallFrame&) const;
+
+ PassRefPtr<TypeBuilder::Console::CallFrame> buildInspectorObject() const;
+
+private:
+ String m_functionName;
+ String m_scriptName;
+ unsigned m_lineNumber;
+ unsigned m_column;
+};
+
+} // namespace WebCore
+
+#endif // ScriptCallFrame_h
diff --git a/Source/core/inspector/ScriptCallStack.cpp b/Source/core/inspector/ScriptCallStack.cpp
new file mode 100644
index 0000000..bc72ddc
--- /dev/null
+++ b/Source/core/inspector/ScriptCallStack.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2008, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/ScriptCallStack.h"
+
+#include "InspectorTypeBuilder.h"
+#include "core/inspector/InspectorValues.h"
+
+namespace WebCore {
+
+PassRefPtr<ScriptCallStack> ScriptCallStack::create(Vector<ScriptCallFrame>& frames)
+{
+ return adoptRef(new ScriptCallStack(frames));
+}
+
+ScriptCallStack::ScriptCallStack(Vector<ScriptCallFrame>& frames)
+{
+ m_frames.swap(frames);
+}
+
+ScriptCallStack::~ScriptCallStack()
+{
+}
+
+const ScriptCallFrame &ScriptCallStack::at(size_t index) const
+{
+ ASSERT(m_frames.size() > index);
+ return m_frames[index];
+}
+
+size_t ScriptCallStack::size() const
+{
+ return m_frames.size();
+}
+
+bool ScriptCallStack::isEqual(ScriptCallStack* o) const
+{
+ if (!o)
+ return false;
+
+ size_t frameCount = o->m_frames.size();
+ if (frameCount != m_frames.size())
+ return false;
+
+ for (size_t i = 0; i < frameCount; ++i) {
+ if (!m_frames[i].isEqual(o->m_frames[i]))
+ return false;
+ }
+
+ return true;
+}
+
+PassRefPtr<TypeBuilder::Array<TypeBuilder::Console::CallFrame> > ScriptCallStack::buildInspectorArray() const
+{
+ RefPtr<TypeBuilder::Array<TypeBuilder::Console::CallFrame> > frames = TypeBuilder::Array<TypeBuilder::Console::CallFrame>::create();
+ for (size_t i = 0; i < m_frames.size(); i++)
+ frames->addItem(m_frames.at(i).buildInspectorObject());
+ return frames;
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/ScriptCallStack.h b/Source/core/inspector/ScriptCallStack.h
new file mode 100644
index 0000000..3796fe1
--- /dev/null
+++ b/Source/core/inspector/ScriptCallStack.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2008, 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 ScriptCallStack_h
+#define ScriptCallStack_h
+
+#include "InspectorTypeBuilder.h"
+
+#include "core/inspector/ScriptCallFrame.h"
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class InspectorArray;
+
+class ScriptCallStack : public RefCounted<ScriptCallStack> {
+public:
+ static const size_t maxCallStackSizeToCapture = 200;
+
+ static PassRefPtr<ScriptCallStack> create(Vector<ScriptCallFrame>&);
+
+ ~ScriptCallStack();
+
+ const ScriptCallFrame &at(size_t) const;
+ size_t size() const;
+
+ bool isEqual(ScriptCallStack*) const;
+
+ PassRefPtr<TypeBuilder::Array<TypeBuilder::Console::CallFrame> > buildInspectorArray() const;
+
+private:
+ ScriptCallStack(Vector<ScriptCallFrame>&);
+
+ Vector<ScriptCallFrame> m_frames;
+};
+
+} // namespace WebCore
+
+#endif // ScriptCallStack_h
diff --git a/Source/core/inspector/ScriptDebugListener.h b/Source/core/inspector/ScriptDebugListener.h
new file mode 100644
index 0000000..ae76fdf
--- /dev/null
+++ b/Source/core/inspector/ScriptDebugListener.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 ScriptDebugListener_h
+#define ScriptDebugListener_h
+
+
+#include "bindings/v8/ScriptState.h"
+#include <wtf/Forward.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class ScriptValue;
+
+class ScriptDebugListener {
+public:
+ class Script {
+ public:
+ Script()
+ : startLine(0)
+ , startColumn(0)
+ , endLine(0)
+ , endColumn(0)
+ , isContentScript(false)
+ {
+ }
+
+ String url;
+ String source;
+ String sourceMappingURL;
+ int startLine;
+ int startColumn;
+ int endLine;
+ int endColumn;
+ bool isContentScript;
+
+ void reportMemoryUsage(MemoryObjectInfo*) const;
+ };
+
+ virtual ~ScriptDebugListener() { }
+
+ virtual void didParseSource(const String& scriptId, const Script&) = 0;
+ virtual void failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage) = 0;
+ virtual void didPause(ScriptState*, const ScriptValue& callFrames, const ScriptValue& exception) = 0;
+ virtual void didContinue() = 0;
+};
+
+} // namespace WebCore
+
+
+#endif // ScriptDebugListener_h
diff --git a/Source/core/inspector/ScriptGCEventListener.h b/Source/core/inspector/ScriptGCEventListener.h
new file mode 100644
index 0000000..5f8a18f
--- /dev/null
+++ b/Source/core/inspector/ScriptGCEventListener.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 ScriptGCEventListener_h
+#define ScriptGCEventListener_h
+
+
+namespace WebCore {
+
+class ScriptGCEventListener
+{
+public:
+ virtual void didGC(double startTime, double endTime, size_t collectedBytes) = 0;
+ virtual ~ScriptGCEventListener(){}
+};
+
+} // namespace WebCore
+
+#endif // !defined(ScriptGCEventListener_h)
diff --git a/Source/core/inspector/ScriptProfile.cpp b/Source/core/inspector/ScriptProfile.cpp
new file mode 100644
index 0000000..ff5a02d
--- /dev/null
+++ b/Source/core/inspector/ScriptProfile.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/ScriptProfile.h"
+
+#include "bindings/v8/V8Binding.h"
+#include "core/inspector/InspectorValues.h"
+#include <v8-profiler.h>
+#include "wtf/PassRefPtr.h"
+#include "wtf/RefPtr.h"
+
+namespace WebCore {
+
+ScriptProfile::~ScriptProfile()
+{
+ const_cast<v8::CpuProfile*>(m_profile)->Delete();
+}
+
+String ScriptProfile::title() const
+{
+ v8::HandleScope scope;
+ return toWebCoreString(m_profile->GetTitle());
+}
+
+unsigned int ScriptProfile::uid() const
+{
+ return m_profile->GetUid();
+}
+
+PassRefPtr<ScriptProfileNode> ScriptProfile::head() const
+{
+ return ScriptProfileNode::create(m_profile->GetTopDownRoot());
+}
+
+double ScriptProfile::idleTime() const
+{
+ return m_idleTime;
+}
+
+static PassRefPtr<TypeBuilder::Profiler::CPUProfileNode> buildInspectorObjectFor(const v8::CpuProfileNode* node)
+{
+ v8::HandleScope handleScope;
+
+ RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode> > children = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>::create();
+ const int childrenCount = node->GetChildrenCount();
+ for (int i = 0; i < childrenCount; i++) {
+ const v8::CpuProfileNode* child = node->GetChild(i);
+ children->addItem(buildInspectorObjectFor(child));
+ }
+
+ RefPtr<TypeBuilder::Profiler::CPUProfileNode> result = TypeBuilder::Profiler::CPUProfileNode::create()
+ .setFunctionName(toWebCoreString(node->GetFunctionName()))
+ .setUrl(toWebCoreString(node->GetScriptResourceName()))
+ .setLineNumber(node->GetLineNumber())
+ .setTotalTime(node->GetTotalTime())
+ .setSelfTime(node->GetSelfTime())
+ .setNumberOfCalls(0)
+ .setVisible(true)
+ .setCallUID(node->GetCallUid())
+ .setChildren(children.release());
+ result->setId(node->GetNodeId());
+ return result.release();
+}
+
+PassRefPtr<TypeBuilder::Profiler::CPUProfileNode> ScriptProfile::buildInspectorObjectForHead() const
+{
+ return buildInspectorObjectFor(m_profile->GetTopDownRoot());
+}
+
+PassRefPtr<TypeBuilder::Array<int> > ScriptProfile::buildInspectorObjectForSamples() const
+{
+ RefPtr<TypeBuilder::Array<int> > array = TypeBuilder::Array<int>::create();
+ int count = m_profile->GetSamplesCount();
+ for (int i = 0; i < count; i++)
+ array->addItem(m_profile->GetSample(i)->GetNodeId());
+ return array.release();
+}
+
+
+} // namespace WebCore
diff --git a/Source/core/inspector/ScriptProfile.h b/Source/core/inspector/ScriptProfile.h
new file mode 100644
index 0000000..de86412
--- /dev/null
+++ b/Source/core/inspector/ScriptProfile.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2010, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 ScriptProfile_h
+#define ScriptProfile_h
+
+#include "InspectorTypeBuilder.h"
+#include "core/inspector/ScriptProfileNode.h"
+#include "wtf/RefCounted.h"
+#include "wtf/text/WTFString.h"
+
+namespace v8 {
+class CpuProfile;
+}
+
+namespace WebCore {
+
+class InspectorObject;
+
+class ScriptProfile : public RefCounted<ScriptProfile> {
+public:
+ static PassRefPtr<ScriptProfile> create(const v8::CpuProfile* profile, double idleTime)
+ {
+ return adoptRef(new ScriptProfile(profile, idleTime));
+ }
+ virtual ~ScriptProfile();
+
+ String title() const;
+ unsigned int uid() const;
+ PassRefPtr<ScriptProfileNode> head() const;
+ double idleTime() const;
+
+ PassRefPtr<TypeBuilder::Profiler::CPUProfileNode> buildInspectorObjectForHead() const;
+ PassRefPtr<TypeBuilder::Array<int> > buildInspectorObjectForSamples() const;
+
+private:
+ ScriptProfile(const v8::CpuProfile* profile, double idleTime)
+ : m_profile(profile)
+ , m_idleTime(idleTime)
+ {}
+
+ const v8::CpuProfile* m_profile;
+ double m_idleTime;
+};
+
+} // namespace WebCore
+
+#endif // ScriptProfile_h
diff --git a/Source/core/inspector/ScriptProfile.idl b/Source/core/inspector/ScriptProfile.idl
new file mode 100644
index 0000000..8569aae
--- /dev/null
+++ b/Source/core/inspector/ScriptProfile.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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 COMPUTER, INC. ``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 COMPUTER, INC. OR
+ * 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.
+ */
+
+[
+] interface ScriptProfile {
+ readonly attribute DOMString title;
+ readonly attribute unsigned long uid;
+ readonly attribute ScriptProfileNode head;
+ readonly attribute double idleTime;
+};
+
diff --git a/Source/core/inspector/ScriptProfileNode.cpp b/Source/core/inspector/ScriptProfileNode.cpp
new file mode 100644
index 0000000..782dc05
--- /dev/null
+++ b/Source/core/inspector/ScriptProfileNode.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2010, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/ScriptProfileNode.h"
+
+#include "bindings/v8/V8Binding.h"
+
+#include <v8-profiler.h>
+
+namespace WebCore {
+
+String ScriptProfileNode::functionName() const
+{
+ return toWebCoreString(m_profileNode->GetFunctionName());
+}
+
+String ScriptProfileNode::url() const
+{
+ return toWebCoreString(m_profileNode->GetScriptResourceName());
+}
+
+unsigned long ScriptProfileNode::lineNumber() const
+{
+ return m_profileNode->GetLineNumber();
+}
+
+double ScriptProfileNode::totalTime() const
+{
+ return m_profileNode->GetTotalTime();
+}
+
+double ScriptProfileNode::selfTime() const
+{
+ return m_profileNode->GetSelfTime();
+}
+
+unsigned long ScriptProfileNode::numberOfCalls() const
+{
+ return 0;
+}
+
+ProfileNodesList ScriptProfileNode::children() const
+{
+ const int childrenCount = m_profileNode->GetChildrenCount();
+ ProfileNodesList result(childrenCount);
+ for (int i = 0; i < childrenCount; ++i)
+ result[i] = ScriptProfileNode::create(m_profileNode->GetChild(i));
+ return result;
+}
+
+bool ScriptProfileNode::visible() const
+{
+ return true;
+}
+
+unsigned long ScriptProfileNode::callUID() const
+{
+ return m_profileNode->GetCallUid();
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/ScriptProfileNode.h b/Source/core/inspector/ScriptProfileNode.h
new file mode 100644
index 0000000..d2fb117
--- /dev/null
+++ b/Source/core/inspector/ScriptProfileNode.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2010, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 ScriptProfileNode_h
+#define ScriptProfileNode_h
+
+#include "wtf/RefCounted.h"
+#include "wtf/text/WTFString.h"
+
+namespace v8 {
+class CpuProfileNode;
+}
+
+namespace WebCore {
+
+class ScriptProfileNode;
+
+typedef Vector<RefPtr<ScriptProfileNode> > ProfileNodesList;
+
+class ScriptProfileNode : public RefCounted<ScriptProfileNode> {
+public:
+ static PassRefPtr<ScriptProfileNode> create(const v8::CpuProfileNode* profileNode)
+ {
+ return adoptRef(new ScriptProfileNode(profileNode));
+ }
+ virtual ~ScriptProfileNode() {}
+
+ String functionName() const;
+ String url() const;
+ unsigned long lineNumber() const;
+ double totalTime() const;
+ double selfTime() const;
+ unsigned long numberOfCalls() const;
+ ProfileNodesList children() const;
+ bool visible() const;
+ unsigned long callUID() const;
+
+protected:
+ ScriptProfileNode(const v8::CpuProfileNode* profileNode)
+ : m_profileNode(profileNode)
+ {}
+
+private:
+ const v8::CpuProfileNode* m_profileNode;
+};
+
+} // namespace WebCore
+
+#endif // ScriptProfileNode_h
diff --git a/Source/core/inspector/ScriptProfileNode.idl b/Source/core/inspector/ScriptProfileNode.idl
new file mode 100644
index 0000000..de7bc62
--- /dev/null
+++ b/Source/core/inspector/ScriptProfileNode.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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 COMPUTER, INC. ``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 COMPUTER, INC. OR
+ * 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.
+ */
+
+[
+] interface ScriptProfileNode {
+ readonly attribute DOMString functionName;
+ readonly attribute DOMString url;
+ readonly attribute unsigned long lineNumber;
+ readonly attribute double totalTime;
+ readonly attribute double selfTime;
+ readonly attribute unsigned long numberOfCalls;
+ sequence<ScriptProfileNode> children();
+ readonly attribute boolean visible;
+ readonly attribute unsigned long callUID;
+};
+
diff --git a/Source/core/inspector/TimelineRecordFactory.cpp b/Source/core/inspector/TimelineRecordFactory.cpp
new file mode 100644
index 0000000..e82ce1a
--- /dev/null
+++ b/Source/core/inspector/TimelineRecordFactory.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/TimelineRecordFactory.h"
+
+#include "bindings/v8/ScriptCallStackFactory.h"
+#include "core/dom/Event.h"
+#include "core/inspector/InspectorValues.h"
+#include "core/inspector/ScriptCallStack.h"
+#include "core/platform/graphics/FloatQuad.h"
+#include "core/platform/graphics/IntRect.h"
+#include "core/platform/graphics/LayoutRect.h"
+#include "core/platform/network/ResourceRequest.h"
+#include "core/platform/network/ResourceResponse.h"
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createGenericRecord(double startTime, int maxCallStackDepth)
+{
+ RefPtr<InspectorObject> record = InspectorObject::create();
+ record->setNumber("startTime", startTime);
+
+ if (maxCallStackDepth) {
+ RefPtr<ScriptCallStack> stackTrace = createScriptCallStack(maxCallStackDepth, true);
+ if (stackTrace && stackTrace->size())
+ record->setValue("stackTrace", stackTrace->buildInspectorArray());
+ }
+ return record.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createBackgroundRecord(double startTime, const String& threadName)
+{
+ RefPtr<InspectorObject> record = InspectorObject::create();
+ record->setNumber("startTime", startTime);
+ record->setString("thread", threadName);
+ return record.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createGCEventData(const size_t usedHeapSizeDelta)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setNumber("usedHeapSizeDelta", usedHeapSizeDelta);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createFunctionCallData(const String& scriptName, int scriptLine)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("scriptName", scriptName);
+ data->setNumber("scriptLine", scriptLine);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createEventDispatchData(const Event& event)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("type", event.type().string());
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createGenericTimerData(int timerId)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setNumber("timerId", timerId);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createTimerInstallData(int timerId, int timeout, bool singleShot)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setNumber("timerId", timerId);
+ data->setNumber("timeout", timeout);
+ data->setBoolean("singleShot", singleShot);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createXHRReadyStateChangeData(const String& url, int readyState)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("url", url);
+ data->setNumber("readyState", readyState);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createXHRLoadData(const String& url)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("url", url);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createEvaluateScriptData(const String& url, double lineNumber)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("url", url);
+ data->setNumber("lineNumber", lineNumber);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createTimeStampData(const String& message)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("message", message);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createScheduleResourceRequestData(const String& url)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("url", url);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createResourceSendRequestData(const String& requestId, const ResourceRequest& request)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("requestId", requestId);
+ data->setString("url", request.url().string());
+ data->setString("requestMethod", request.httpMethod());
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createResourceReceiveResponseData(const String& requestId, const ResourceResponse& response)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("requestId", requestId);
+ data->setNumber("statusCode", response.httpStatusCode());
+ data->setString("mimeType", response.mimeType());
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createResourceFinishData(const String& requestId, bool didFail, double finishTime)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("requestId", requestId);
+ data->setBoolean("didFail", didFail);
+ if (finishTime)
+ data->setNumber("networkTime", finishTime);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createReceiveResourceData(const String& requestId, int length)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("requestId", requestId);
+ data->setNumber("encodedDataLength", length);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createLayoutData(unsigned dirtyObjects, unsigned totalObjects, bool partialLayout)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setNumber("dirtyObjects", dirtyObjects);
+ data->setNumber("totalObjects", totalObjects);
+ data->setBoolean("partialLayout", partialLayout);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createDecodeImageData(const String& imageType)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setString("imageType", imageType);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createResizeImageData(bool shouldCache)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setBoolean("cached", shouldCache);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createMarkData(bool isMainFrame)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setBoolean("isMainFrame", isMainFrame);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createParseHTMLData(unsigned startLine)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setNumber("startLine", startLine);
+ return data.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createAnimationFrameData(int callbackId)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setNumber("id", callbackId);
+ return data.release();
+}
+
+static PassRefPtr<InspectorArray> createQuad(const FloatQuad& quad)
+{
+ RefPtr<InspectorArray> array = InspectorArray::create();
+ array->pushNumber(quad.p1().x());
+ array->pushNumber(quad.p1().y());
+ array->pushNumber(quad.p2().x());
+ array->pushNumber(quad.p2().y());
+ array->pushNumber(quad.p3().x());
+ array->pushNumber(quad.p3().y());
+ array->pushNumber(quad.p4().x());
+ array->pushNumber(quad.p4().y());
+ return array.release();
+}
+
+PassRefPtr<InspectorObject> TimelineRecordFactory::createPaintData(const FloatQuad& quad)
+{
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setArray("clip", createQuad(quad));
+ return data.release();
+}
+
+void TimelineRecordFactory::appendLayoutRoot(InspectorObject* data, const FloatQuad& quad)
+{
+ data->setArray("root", createQuad(quad));
+}
+
+void TimelineRecordFactory::appendStyleRecalcDetails(InspectorObject* data, unsigned elementCount)
+{
+ data->setNumber("elementCount", elementCount);
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/TimelineRecordFactory.h b/Source/core/inspector/TimelineRecordFactory.h
new file mode 100644
index 0000000..e13b61e
--- /dev/null
+++ b/Source/core/inspector/TimelineRecordFactory.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 TimelineRecordFactory_h
+#define TimelineRecordFactory_h
+
+#include "core/inspector/InspectorValues.h"
+#include "core/platform/KURL.h"
+#include "core/platform/graphics/LayoutRect.h"
+#include <wtf/Forward.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+ class Event;
+ class FloatQuad;
+ class InspectorFrontend;
+ class InspectorObject;
+ class IntRect;
+ class ResourceRequest;
+ class ResourceResponse;
+
+ class TimelineRecordFactory {
+ public:
+ static PassRefPtr<InspectorObject> createGenericRecord(double startTime, int maxCallStackDepth);
+ static PassRefPtr<InspectorObject> createBackgroundRecord(double startTime, const String& thread);
+
+ static PassRefPtr<InspectorObject> createGCEventData(const size_t usedHeapSizeDelta);
+
+ static PassRefPtr<InspectorObject> createFunctionCallData(const String& scriptName, int scriptLine);
+
+ static PassRefPtr<InspectorObject> createEventDispatchData(const Event&);
+
+ static PassRefPtr<InspectorObject> createGenericTimerData(int timerId);
+
+ static PassRefPtr<InspectorObject> createTimerInstallData(int timerId, int timeout, bool singleShot);
+
+ static PassRefPtr<InspectorObject> createXHRReadyStateChangeData(const String& url, int readyState);
+
+ static PassRefPtr<InspectorObject> createXHRLoadData(const String& url);
+
+ static PassRefPtr<InspectorObject> createEvaluateScriptData(const String&, double lineNumber);
+
+ static PassRefPtr<InspectorObject> createTimeStampData(const String&);
+
+ static PassRefPtr<InspectorObject> createResourceSendRequestData(const String& requestId, const ResourceRequest&);
+
+ static PassRefPtr<InspectorObject> createScheduleResourceRequestData(const String&);
+
+ static PassRefPtr<InspectorObject> createResourceReceiveResponseData(const String& requestId, const ResourceResponse&);
+
+ static PassRefPtr<InspectorObject> createReceiveResourceData(const String& requestId, int length);
+
+ static PassRefPtr<InspectorObject> createResourceFinishData(const String& requestId, bool didFail, double finishTime);
+
+ static PassRefPtr<InspectorObject> createLayoutData(unsigned dirtyObjects, unsigned totalObjects, bool partialLayout);
+
+ static PassRefPtr<InspectorObject> createDecodeImageData(const String& imageType);
+
+ static PassRefPtr<InspectorObject> createResizeImageData(bool shouldCache);
+
+ static PassRefPtr<InspectorObject> createMarkData(bool isMainFrame);
+
+ static PassRefPtr<InspectorObject> createParseHTMLData(unsigned startLine);
+
+ static PassRefPtr<InspectorObject> createAnimationFrameData(int callbackId);
+
+ static PassRefPtr<InspectorObject> createPaintData(const FloatQuad&);
+
+ static void appendLayoutRoot(InspectorObject* data, const FloatQuad&);
+
+ static void appendStyleRecalcDetails(InspectorObject* data, unsigned elementCount);
+
+ static inline PassRefPtr<InspectorObject> createWebSocketCreateData(unsigned long identifier, const KURL& url, const String& protocol)
+ {
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setNumber("identifier", identifier);
+ data->setString("url", url.string());
+ if (!protocol.isNull())
+ data->setString("webSocketProtocol", protocol);
+ return data.release();
+ }
+
+ static inline PassRefPtr<InspectorObject> createGenericWebSocketData(unsigned long identifier)
+ {
+ RefPtr<InspectorObject> data = InspectorObject::create();
+ data->setNumber("identifier", identifier);
+ return data.release();
+ }
+ private:
+ TimelineRecordFactory() { }
+ };
+
+} // namespace WebCore
+
+#endif // !defined(TimelineRecordFactory_h)
diff --git a/Source/core/inspector/TimelineTraceEventProcessor.cpp b/Source/core/inspector/TimelineTraceEventProcessor.cpp
new file mode 100644
index 0000000..83550b9
--- /dev/null
+++ b/Source/core/inspector/TimelineTraceEventProcessor.cpp
@@ -0,0 +1,323 @@
+/*
+* Copyright (C) 2013 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 "core/inspector/TimelineTraceEventProcessor.h"
+
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorInstrumentation.h"
+#include "core/inspector/TimelineRecordFactory.h"
+
+#include <wtf/CurrentTime.h>
+#include <wtf/MainThread.h>
+#include <wtf/ThreadSpecific.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+namespace {
+
+class TraceEventDispatcher {
+ WTF_MAKE_NONCOPYABLE(TraceEventDispatcher);
+public:
+ static TraceEventDispatcher* instance()
+ {
+ DEFINE_STATIC_LOCAL(TraceEventDispatcher, instance, ());
+ return &instance;
+ }
+
+ void addProcessor(TimelineTraceEventProcessor* processor, InspectorClient* client)
+ {
+ MutexLocker locker(m_mutex);
+
+ m_processors.append(processor);
+ if (m_processors.size() == 1)
+ client->setTraceEventCallback(dispatchEventOnAnyThread);
+ }
+
+ void removeProcessor(TimelineTraceEventProcessor* processor, InspectorClient* client)
+ {
+ MutexLocker locker(m_mutex);
+
+ size_t index = m_processors.find(processor);
+ if (index == notFound) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ m_processors.remove(index);
+ if (m_processors.isEmpty())
+ client->setTraceEventCallback(0);
+ }
+
+private:
+ TraceEventDispatcher() { }
+
+ static void dispatchEventOnAnyThread(char phase, const unsigned char*, const char* name, unsigned long long id,
+ int numArgs, const char* const* argNames, const unsigned char* argTypes, const unsigned long long* argValues,
+ unsigned char flags)
+ {
+ TraceEventDispatcher* self = instance();
+ Vector<RefPtr<TimelineTraceEventProcessor> > processors;
+ {
+ MutexLocker locker(self->m_mutex);
+ processors = self->m_processors;
+ }
+ for (int i = 0, size = processors.size(); i < size; ++i) {
+ processors[i]->processEventOnAnyThread(static_cast<TimelineTraceEventProcessor::TraceEventPhase>(phase),
+ name, id, numArgs, argNames, argTypes, argValues, flags);
+ }
+ }
+
+ Mutex m_mutex;
+ Vector<RefPtr<TimelineTraceEventProcessor> > m_processors;
+};
+
+} // namespce
+
+
+TimelineRecordStack::TimelineRecordStack(WeakPtr<InspectorTimelineAgent> timelineAgent)
+ : m_timelineAgent(timelineAgent)
+{
+}
+
+void TimelineRecordStack::addScopedRecord(PassRefPtr<InspectorObject> record)
+{
+ m_stack.append(Entry(record));
+}
+
+void TimelineRecordStack::closeScopedRecord(double endTime)
+{
+ if (m_stack.isEmpty())
+ return;
+ Entry last = m_stack.last();
+ m_stack.removeLast();
+ last.record->setNumber("endTime", endTime);
+ if (last.children->length())
+ last.record->setArray("children", last.children);
+ addInstantRecord(last.record);
+}
+
+void TimelineRecordStack::addInstantRecord(PassRefPtr<InspectorObject> record)
+{
+ if (m_stack.isEmpty())
+ send(record);
+ else
+ m_stack.last().children->pushObject(record);
+}
+
+#ifndef NDEBUG
+bool TimelineRecordStack::isOpenRecordOfType(const String& type)
+{
+ String lastRecordType;
+ return m_stack.isEmpty() || (m_stack.last().record->getString("type", &lastRecordType) && type == lastRecordType);
+}
+#endif
+
+void TimelineRecordStack::send(PassRefPtr<InspectorObject> record)
+{
+ InspectorTimelineAgent* timelineAgent = m_timelineAgent.get();
+ if (!timelineAgent)
+ return;
+ timelineAgent->sendEvent(record);
+}
+
+TimelineTraceEventProcessor::TimelineTraceEventProcessor(WeakPtr<InspectorTimelineAgent> timelineAgent, InspectorClient *client)
+ : m_timelineAgent(timelineAgent)
+ , m_timeConverter(timelineAgent.get()->timeConverter())
+ , m_inspectorClient(client)
+ , m_pageId(reinterpret_cast<unsigned long long>(m_timelineAgent.get()->page()))
+ , m_layerId(0)
+{
+ registerHandler(InstrumentationEvents::BeginFrame, TracePhaseInstant, &TimelineTraceEventProcessor::onBeginFrame);
+ registerHandler(InstrumentationEvents::PaintLayer, TracePhaseBegin, &TimelineTraceEventProcessor::onPaintLayerBegin);
+ registerHandler(InstrumentationEvents::PaintLayer, TracePhaseEnd, &TimelineTraceEventProcessor::onPaintLayerEnd);
+ registerHandler(InstrumentationEvents::RasterTask, TracePhaseBegin, &TimelineTraceEventProcessor::onRasterTaskBegin);
+ registerHandler(InstrumentationEvents::RasterTask, TracePhaseEnd, &TimelineTraceEventProcessor::onRasterTaskEnd);
+ registerHandler(InstrumentationEvents::Layer, TracePhaseDeleteObject, &TimelineTraceEventProcessor::onLayerDeleted);
+ registerHandler(InstrumentationEvents::Paint, TracePhaseInstant, &TimelineTraceEventProcessor::onPaint);
+ registerHandler(PlatformInstrumentation::ImageDecodeEvent, TracePhaseBegin, &TimelineTraceEventProcessor::onImageDecodeBegin);
+ registerHandler(PlatformInstrumentation::ImageDecodeEvent, TracePhaseEnd, &TimelineTraceEventProcessor::onImageDecodeEnd);
+
+ TraceEventDispatcher::instance()->addProcessor(this, m_inspectorClient);
+}
+
+TimelineTraceEventProcessor::~TimelineTraceEventProcessor()
+{
+}
+
+void TimelineTraceEventProcessor::registerHandler(const char* name, TraceEventPhase phase, TraceEventHandler handler)
+{
+ m_handlersByType.set(std::make_pair(name, phase), handler);
+}
+
+void TimelineTraceEventProcessor::shutdown()
+{
+ TraceEventDispatcher::instance()->removeProcessor(this, m_inspectorClient);
+}
+
+size_t TimelineTraceEventProcessor::TraceEvent::findParameter(const char* name) const
+{
+ for (int i = 0; i < m_argumentCount; ++i) {
+ if (!strcmp(name, m_argumentNames[i]))
+ return i;
+ }
+ return notFound;
+}
+
+const TimelineTraceEventProcessor::TraceValueUnion& TimelineTraceEventProcessor::TraceEvent::parameter(const char* name, TraceValueTypes expectedType) const
+{
+ static TraceValueUnion missingValue;
+ size_t index = findParameter(name);
+ if (index == notFound || m_argumentTypes[index] != expectedType) {
+ ASSERT_NOT_REACHED();
+ return missingValue;
+ }
+ return *reinterpret_cast<const TraceValueUnion*>(m_argumentValues + index);
+}
+
+void TimelineTraceEventProcessor::processEventOnAnyThread(TraceEventPhase phase, const char* name, unsigned long long id,
+ int numArgs, const char* const* argNames, const unsigned char* argTypes, const unsigned long long* argValues,
+ unsigned char)
+{
+ HandlersMap::iterator it = m_handlersByType.find(std::make_pair(name, phase));
+ if (it == m_handlersByType.end())
+ return;
+
+ TraceEvent event(WTF::monotonicallyIncreasingTime(), phase, name, id, currentThread(), numArgs, argNames, argTypes, argValues);
+
+ if (!isMainThread()) {
+ MutexLocker locker(m_backgroundEventsMutex);
+ m_backgroundEvents.append(event);
+ return;
+ }
+ (this->*(it->value))(event);
+}
+
+void TimelineTraceEventProcessor::onBeginFrame(const TraceEvent&)
+{
+ processBackgroundEvents();
+}
+
+void TimelineTraceEventProcessor::onPaintLayerBegin(const TraceEvent& event)
+{
+ m_layerId = event.asUInt(InstrumentationEventArguments::LayerId);
+ ASSERT(m_layerId);
+}
+
+void TimelineTraceEventProcessor::onPaintLayerEnd(const TraceEvent&)
+{
+ m_layerId = 0;
+}
+
+void TimelineTraceEventProcessor::onRasterTaskBegin(const TraceEvent& event)
+{
+ unsigned long long layerId = event.asUInt(InstrumentationEventArguments::LayerId);
+ if (!m_knownLayers.contains(layerId))
+ return;
+ TimelineThreadState& state = threadState(event.threadIdentifier());
+ ASSERT(!state.inRasterizeEvent);
+ state.inRasterizeEvent = true;
+ RefPtr<InspectorObject> record = createRecord(event, TimelineRecordType::Rasterize);
+ state.recordStack.addScopedRecord(record.release());
+}
+
+void TimelineTraceEventProcessor::onRasterTaskEnd(const TraceEvent& event)
+{
+ TimelineThreadState& state = threadState(event.threadIdentifier());
+ if (!state.inRasterizeEvent)
+ return;
+ ASSERT(state.recordStack.isOpenRecordOfType(TimelineRecordType::Rasterize));
+ state.recordStack.closeScopedRecord(m_timeConverter.fromMonotonicallyIncreasingTime(event.timestamp()));
+ state.inRasterizeEvent = false;
+}
+
+void TimelineTraceEventProcessor::onImageDecodeBegin(const TraceEvent& event)
+{
+ TimelineThreadState& state = threadState(event.threadIdentifier());
+ if (!state.inRasterizeEvent)
+ return;
+ state.recordStack.addScopedRecord(createRecord(event, TimelineRecordType::DecodeImage));
+}
+
+void TimelineTraceEventProcessor::onImageDecodeEnd(const TraceEvent& event)
+{
+ TimelineThreadState& state = threadState(event.threadIdentifier());
+ if (!state.inRasterizeEvent)
+ return;
+ ASSERT(state.recordStack.isOpenRecordOfType(TimelineRecordType::DecodeImage));
+ state.recordStack.closeScopedRecord(m_timeConverter.fromMonotonicallyIncreasingTime(event.timestamp()));
+}
+
+void TimelineTraceEventProcessor::onLayerDeleted(const TraceEvent& event)
+{
+ unsigned long long id = event.id();
+ ASSERT(id);
+ processBackgroundEvents();
+ m_knownLayers.remove(id);
+}
+
+void TimelineTraceEventProcessor::onPaint(const TraceEvent& event)
+{
+ if (!m_layerId)
+ return;
+
+ unsigned long long pageId = event.asUInt(InstrumentationEventArguments::PageId);
+ if (pageId == m_pageId)
+ m_knownLayers.add(m_layerId);
+}
+
+PassRefPtr<InspectorObject> TimelineTraceEventProcessor::createRecord(const TraceEvent& event, const String& recordType, PassRefPtr<InspectorObject> data)
+{
+ double startTime = m_timeConverter.fromMonotonicallyIncreasingTime(event.timestamp());
+ RefPtr<InspectorObject> record = TimelineRecordFactory::createBackgroundRecord(startTime, String::number(event.threadIdentifier()));
+ record->setString("type", recordType);
+ record->setObject("data", data ? data : InspectorObject::create());
+ return record.release();
+}
+
+void TimelineTraceEventProcessor::processBackgroundEvents()
+{
+ ASSERT(isMainThread());
+ Vector<TraceEvent> events;
+ {
+ MutexLocker locker(m_backgroundEventsMutex);
+ events.reserveCapacity(m_backgroundEvents.capacity());
+ m_backgroundEvents.swap(events);
+ }
+ for (size_t i = 0, size = events.size(); i < size; ++i) {
+ const TraceEvent& event = events[i];
+ HandlersMap::iterator it = m_handlersByType.find(std::make_pair(event.name(), event.phase()));
+ ASSERT(it != m_handlersByType.end() && it->value);
+ (this->*(it->value))(event);
+ }
+}
+
+} // namespace WebCore
+
diff --git a/Source/core/inspector/TimelineTraceEventProcessor.h b/Source/core/inspector/TimelineTraceEventProcessor.h
new file mode 100644
index 0000000..67760d2
--- /dev/null
+++ b/Source/core/inspector/TimelineTraceEventProcessor.h
@@ -0,0 +1,260 @@
+/*
+* Copyright (C) 2013 Google 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:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+* OWNER OR 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 TimelineTraceEventProcessor_h
+#define TimelineTraceEventProcessor_h
+
+
+#include "core/inspector/InspectorTimelineAgent.h"
+#include "core/inspector/InspectorValues.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class InspectorClient;
+class InspectorTimelineAgent;
+class Page;
+
+class TimelineRecordStack {
+private:
+ struct Entry {
+ Entry(PassRefPtr<InspectorObject> record)
+ : record(record)
+ , children(InspectorArray::create())
+ {
+ }
+
+ RefPtr<InspectorObject> record;
+ RefPtr<InspectorArray> children;
+ };
+
+public:
+ TimelineRecordStack() { }
+ TimelineRecordStack(WeakPtr<InspectorTimelineAgent>);
+
+ void addScopedRecord(PassRefPtr<InspectorObject> record);
+ void closeScopedRecord(double endTime);
+ void addInstantRecord(PassRefPtr<InspectorObject> record);
+
+#ifndef NDEBUG
+ bool isOpenRecordOfType(const String& type);
+#endif
+
+private:
+ void send(PassRefPtr<InspectorObject>);
+
+ WeakPtr<InspectorTimelineAgent> m_timelineAgent;
+ Vector<Entry> m_stack;
+};
+
+class TimelineTraceEventProcessor : public ThreadSafeRefCounted<TimelineTraceEventProcessor> {
+public:
+ // FIXME: re-use definitions in TraceEvent.h once it's promoted to all platforms.
+ enum TraceEventPhase {
+ TracePhaseBegin = 'B',
+ TracePhaseEnd = 'E',
+ TracePhaseInstant = 'I',
+ TracePhaseCreateObject = 'N',
+ TracePhaseDeleteObject = 'D'
+ };
+
+ TimelineTraceEventProcessor(WeakPtr<InspectorTimelineAgent>, InspectorClient*);
+ ~TimelineTraceEventProcessor();
+
+ void shutdown();
+ void processEventOnAnyThread(TraceEventPhase, const char* name, unsigned long long id,
+ int numArgs, const char* const* argNames, const unsigned char* argTypes, const unsigned long long* argValues,
+ unsigned char flags);
+
+private:
+ // FIXME: use the definition in TraceEvent.h once we expose the latter to all plaforms.
+ union TraceValueUnion {
+ bool m_bool;
+ unsigned long long m_uint;
+ long long m_int;
+ double m_double;
+ const void* m_pointer;
+ const char* m_string;
+ };
+
+ enum TraceValueTypes {
+ TypeBool = 1,
+ TypeUInt = 2,
+ TypeInt = 3,
+ TypeDouble = 4,
+ TypePointer = 5,
+ TypeString = 6,
+ TypeCopyString = 7
+ };
+
+ struct TimelineThreadState {
+ TimelineThreadState() { }
+
+ TimelineThreadState(WeakPtr<InspectorTimelineAgent> timelineAgent)
+ : recordStack(timelineAgent)
+ , inRasterizeEvent(false)
+ {
+ }
+
+ TimelineRecordStack recordStack;
+ bool inRasterizeEvent;
+ };
+
+ class TraceEvent {
+ public:
+ TraceEvent()
+ : m_name(0)
+ , m_argumentCount(0)
+ {
+ }
+
+ TraceEvent(double timestamp, TraceEventPhase phase, const char* name, unsigned long long id, ThreadIdentifier threadIdentifier,
+ int argumentCount, const char* const* argumentNames, const unsigned char* argumentTypes, const unsigned long long* argumentValues)
+ : m_timestamp(timestamp)
+ , m_phase(phase)
+ , m_name(name)
+ , m_id(id)
+ , m_threadIdentifier(threadIdentifier)
+ , m_argumentCount(argumentCount)
+ {
+ if (m_argumentCount > MaxArguments) {
+ ASSERT_NOT_REACHED();
+ m_argumentCount = MaxArguments;
+ }
+ for (int i = 0; i < m_argumentCount; ++i) {
+ m_argumentNames[i] = argumentNames[i];
+ m_argumentTypes[i] = argumentTypes[i];
+ m_argumentValues[i] = argumentValues[i];
+ }
+ }
+
+ double timestamp() const { return m_timestamp; }
+ TraceEventPhase phase() const { return m_phase; }
+ const char* name() const { return m_name; }
+ unsigned long long id() const { return m_id; }
+ ThreadIdentifier threadIdentifier() const { return m_threadIdentifier; }
+ int argumentCount() const { return m_argumentCount; }
+ bool isNull() const { return !m_name; }
+
+ bool asBool(const char* name) const
+ {
+ return parameter(name, TypeBool).m_bool;
+ }
+ long long asInt(const char* name) const
+ {
+ size_t index = findParameter(name);
+ if (index == notFound || (m_argumentTypes[index] != TypeInt && m_argumentTypes[index] != TypeUInt)) {
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+ return reinterpret_cast<const TraceValueUnion*>(m_argumentValues + index)->m_int;
+ }
+ unsigned long long asUInt(const char* name) const
+ {
+ return asInt(name);
+ }
+ double asDouble(const char* name) const
+ {
+ return parameter(name, TypeDouble).m_double;
+ }
+ const char* asString(const char* name) const
+ {
+ return parameter(name, TypeString).m_string;
+ }
+
+ private:
+ enum { MaxArguments = 2 };
+
+ size_t findParameter(const char*) const;
+ const TraceValueUnion& parameter(const char* name, TraceValueTypes expectedType) const;
+
+ double m_timestamp;
+ TraceEventPhase m_phase;
+ const char* m_name;
+ unsigned long long m_id;
+ ThreadIdentifier m_threadIdentifier;
+ int m_argumentCount;
+ const char* m_argumentNames[MaxArguments];
+ unsigned char m_argumentTypes[MaxArguments];
+ unsigned long long m_argumentValues[MaxArguments];
+ };
+
+ typedef void (TimelineTraceEventProcessor::*TraceEventHandler)(const TraceEvent&);
+
+ TimelineThreadState& threadState(ThreadIdentifier thread)
+ {
+ ThreadStateMap::iterator it = m_threadStates.find(thread);
+ if (it != m_threadStates.end())
+ return it->value;
+ return m_threadStates.add(thread, TimelineThreadState(m_timelineAgent)).iterator->value;
+ }
+
+ void processBackgroundEvents();
+ PassRefPtr<InspectorObject> createRecord(const TraceEvent&, const String& recordType, PassRefPtr<InspectorObject> data = 0);
+
+ void registerHandler(const char* name, TraceEventPhase, TraceEventHandler);
+
+ void onBeginFrame(const TraceEvent&);
+ void onPaintLayerBegin(const TraceEvent&);
+ void onPaintLayerEnd(const TraceEvent&);
+ void onRasterTaskBegin(const TraceEvent&);
+ void onRasterTaskEnd(const TraceEvent&);
+ void onImageDecodeBegin(const TraceEvent&);
+ void onImageDecodeEnd(const TraceEvent&);
+ void onLayerDeleted(const TraceEvent&);
+ void onPaint(const TraceEvent&);
+
+ WeakPtr<InspectorTimelineAgent> m_timelineAgent;
+ TimelineTimeConverter m_timeConverter;
+ InspectorClient* m_inspectorClient;
+ unsigned long long m_pageId;
+
+ typedef HashMap<std::pair<String, int>, TraceEventHandler> HandlersMap;
+ HandlersMap m_handlersByType;
+ Mutex m_backgroundEventsMutex;
+ Vector<TraceEvent> m_backgroundEvents;
+
+ typedef HashMap<ThreadIdentifier, TimelineThreadState> ThreadStateMap;
+ ThreadStateMap m_threadStates;
+
+ HashSet<unsigned long long> m_knownLayers;
+ unsigned long long m_layerId;
+};
+
+} // namespace WebCore
+
+#endif // !defined(TimelineTraceEventProcessor_h)
diff --git a/Source/core/inspector/WorkerConsoleAgent.cpp b/Source/core/inspector/WorkerConsoleAgent.cpp
new file mode 100644
index 0000000..2dda5ba
--- /dev/null
+++ b/Source/core/inspector/WorkerConsoleAgent.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/WorkerConsoleAgent.h"
+
+namespace WebCore {
+
+WorkerConsoleAgent::WorkerConsoleAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager)
+ : InspectorConsoleAgent(instrumentingAgents, state, injectedScriptManager)
+{
+}
+
+WorkerConsoleAgent::~WorkerConsoleAgent()
+{
+}
+
+void WorkerConsoleAgent::addInspectedNode(ErrorString* error, int)
+{
+ *error = "addInspectedNode is not supported for workers";
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/WorkerConsoleAgent.h b/Source/core/inspector/WorkerConsoleAgent.h
new file mode 100644
index 0000000..27ec0ac
--- /dev/null
+++ b/Source/core/inspector/WorkerConsoleAgent.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 WorkerConsoleAgent_h
+#define WorkerConsoleAgent_h
+
+#include "core/inspector/InspectorConsoleAgent.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WorkerConsoleAgent : public InspectorConsoleAgent {
+ WTF_MAKE_NONCOPYABLE(WorkerConsoleAgent);
+public:
+ static PassOwnPtr<WorkerConsoleAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager)
+ {
+ return adoptPtr(new WorkerConsoleAgent(instrumentingAgents, state, injectedScriptManager));
+ }
+ virtual ~WorkerConsoleAgent();
+
+ virtual bool isWorkerAgent() OVERRIDE { return true; }
+
+private:
+ WorkerConsoleAgent(InstrumentingAgents*, InspectorCompositeState*, InjectedScriptManager*);
+ virtual void addInspectedNode(ErrorString*, int nodeId);
+};
+
+} // namespace WebCore
+
+#endif // !defined(WorkerConsoleAgent_h)
diff --git a/Source/core/inspector/WorkerDebuggerAgent.cpp b/Source/core/inspector/WorkerDebuggerAgent.cpp
new file mode 100644
index 0000000..b7a4c22
--- /dev/null
+++ b/Source/core/inspector/WorkerDebuggerAgent.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/WorkerDebuggerAgent.h"
+
+#include "bindings/v8/ScriptDebugServer.h"
+#include "core/workers/WorkerContext.h"
+#include "core/workers/WorkerThread.h"
+#include <wtf/MessageQueue.h>
+
+namespace WebCore {
+
+namespace {
+
+Mutex& workerDebuggerAgentsMutex()
+{
+ AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
+ return mutex;
+}
+
+typedef HashMap<WorkerThread*, WorkerDebuggerAgent*> WorkerDebuggerAgents;
+
+WorkerDebuggerAgents& workerDebuggerAgents()
+{
+ DEFINE_STATIC_LOCAL(WorkerDebuggerAgents, agents, ());
+ return agents;
+}
+
+
+class RunInspectorCommandsTask : public ScriptDebugServer::Task {
+public:
+ RunInspectorCommandsTask(WorkerThread* thread, WorkerContext* workerContext)
+ : m_thread(thread)
+ , m_workerContext(workerContext) { }
+ virtual ~RunInspectorCommandsTask() { }
+ virtual void run()
+ {
+ // Process all queued debugger commands. It is safe to use m_workerContext here
+ // because it is alive if RunWorkerLoop is not terminated, otherwise it will
+ // just be ignored. WorkerThread is certainly alive if this task is being executed.
+ while (MessageQueueMessageReceived == m_thread->runLoop().runInMode(m_workerContext, WorkerDebuggerAgent::debuggerTaskMode, WorkerRunLoop::DontWaitForMessage)) { }
+ }
+
+private:
+ WorkerThread* m_thread;
+ WorkerContext* m_workerContext;
+};
+
+} // namespace
+
+const char* WorkerDebuggerAgent::debuggerTaskMode = "debugger";
+
+PassOwnPtr<WorkerDebuggerAgent> WorkerDebuggerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, WorkerContext* inspectedWorkerContext, InjectedScriptManager* injectedScriptManager)
+{
+ return adoptPtr(new WorkerDebuggerAgent(instrumentingAgents, inspectorState, inspectedWorkerContext, injectedScriptManager));
+}
+
+WorkerDebuggerAgent::WorkerDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, WorkerContext* inspectedWorkerContext, InjectedScriptManager* injectedScriptManager)
+ : InspectorDebuggerAgent(instrumentingAgents, inspectorState, injectedScriptManager)
+ , m_scriptDebugServer(inspectedWorkerContext, WorkerDebuggerAgent::debuggerTaskMode)
+ , m_inspectedWorkerContext(inspectedWorkerContext)
+{
+ MutexLocker lock(workerDebuggerAgentsMutex());
+ workerDebuggerAgents().set(inspectedWorkerContext->thread(), this);
+}
+
+WorkerDebuggerAgent::~WorkerDebuggerAgent()
+{
+ MutexLocker lock(workerDebuggerAgentsMutex());
+ ASSERT(workerDebuggerAgents().contains(m_inspectedWorkerContext->thread()));
+ workerDebuggerAgents().remove(m_inspectedWorkerContext->thread());
+}
+
+void WorkerDebuggerAgent::interruptAndDispatchInspectorCommands(WorkerThread* thread)
+{
+ MutexLocker lock(workerDebuggerAgentsMutex());
+ WorkerDebuggerAgent* agent = workerDebuggerAgents().get(thread);
+ if (agent)
+ agent->m_scriptDebugServer.interruptAndRunTask(adoptPtr(new RunInspectorCommandsTask(thread, agent->m_inspectedWorkerContext)));
+}
+
+void WorkerDebuggerAgent::startListeningScriptDebugServer()
+{
+ scriptDebugServer().addListener(this);
+}
+
+void WorkerDebuggerAgent::stopListeningScriptDebugServer()
+{
+ scriptDebugServer().removeListener(this);
+}
+
+WorkerScriptDebugServer& WorkerDebuggerAgent::scriptDebugServer()
+{
+ return m_scriptDebugServer;
+}
+
+InjectedScript WorkerDebuggerAgent::injectedScriptForEval(ErrorString* error, const int* executionContextId)
+{
+ if (executionContextId) {
+ *error = "Execution context id is not supported for workers as there is only one execution context.";
+ return InjectedScript();
+ }
+ ScriptState* scriptState = scriptStateFromWorkerContext(m_inspectedWorkerContext);
+ return injectedScriptManager()->injectedScriptFor(scriptState);
+}
+
+void WorkerDebuggerAgent::muteConsole()
+{
+ // We don't need to mute console for workers.
+}
+
+void WorkerDebuggerAgent::unmuteConsole()
+{
+ // We don't need to mute console for workers.
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/WorkerDebuggerAgent.h b/Source/core/inspector/WorkerDebuggerAgent.h
new file mode 100644
index 0000000..b406a1d
--- /dev/null
+++ b/Source/core/inspector/WorkerDebuggerAgent.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 WorkerDebuggerAgent_h
+#define WorkerDebuggerAgent_h
+
+#include "bindings/v8/WorkerScriptDebugServer.h"
+#include "core/inspector/InspectorDebuggerAgent.h"
+
+namespace WebCore {
+
+class WorkerContext;
+class WorkerThread;
+
+class WorkerDebuggerAgent : public InspectorDebuggerAgent {
+ WTF_MAKE_NONCOPYABLE(WorkerDebuggerAgent);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ static PassOwnPtr<WorkerDebuggerAgent> create(InstrumentingAgents*, InspectorCompositeState*, WorkerContext*, InjectedScriptManager*);
+ virtual ~WorkerDebuggerAgent();
+
+ static const char* debuggerTaskMode;
+ static void interruptAndDispatchInspectorCommands(WorkerThread*);
+
+private:
+ WorkerDebuggerAgent(InstrumentingAgents*, InspectorCompositeState*, WorkerContext*, InjectedScriptManager*);
+
+ virtual void startListeningScriptDebugServer();
+ virtual void stopListeningScriptDebugServer();
+ virtual WorkerScriptDebugServer& scriptDebugServer();
+ virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId);
+ virtual void muteConsole();
+ virtual void unmuteConsole();
+
+ WorkerScriptDebugServer m_scriptDebugServer;
+ WorkerContext* m_inspectedWorkerContext;
+};
+
+} // namespace WebCore
+
+#endif // !defined(WorkerDebuggerAgent_h)
diff --git a/Source/core/inspector/WorkerInspectorController.cpp b/Source/core/inspector/WorkerInspectorController.cpp
new file mode 100644
index 0000000..21994ea
--- /dev/null
+++ b/Source/core/inspector/WorkerInspectorController.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/WorkerInspectorController.h"
+
+#include "InspectorBackendDispatcher.h"
+#include "InspectorFrontend.h"
+#include "core/inspector/InjectedScriptHost.h"
+#include "core/inspector/InjectedScriptManager.h"
+#include "core/inspector/InspectorClient.h"
+#include "core/inspector/InspectorConsoleAgent.h"
+#include "core/inspector/InspectorFrontendChannel.h"
+#include "core/inspector/InspectorHeapProfilerAgent.h"
+#include "core/inspector/InspectorProfilerAgent.h"
+#include "core/inspector/InspectorState.h"
+#include "core/inspector/InspectorStateClient.h"
+#include "core/inspector/InspectorTimelineAgent.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/inspector/WorkerConsoleAgent.h"
+#include "core/inspector/WorkerDebuggerAgent.h"
+#include "core/inspector/WorkerRuntimeAgent.h"
+#include "core/workers/WorkerContext.h"
+#include "core/workers/WorkerReportingProxy.h"
+#include "core/workers/WorkerThread.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+namespace {
+
+class PageInspectorProxy : public InspectorFrontendChannel {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ explicit PageInspectorProxy(WorkerContext* workerContext) : m_workerContext(workerContext) { }
+ virtual ~PageInspectorProxy() { }
+private:
+ virtual bool sendMessageToFrontend(const String& message)
+ {
+ m_workerContext->thread()->workerReportingProxy().postMessageToPageInspector(message);
+ return true;
+ }
+ WorkerContext* m_workerContext;
+};
+
+class WorkerStateClient : public InspectorStateClient {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ WorkerStateClient(WorkerContext* context) : m_workerContext(context) { }
+ virtual ~WorkerStateClient() { }
+
+private:
+ virtual void updateInspectorStateCookie(const String& cookie)
+ {
+ m_workerContext->thread()->workerReportingProxy().updateInspectorStateCookie(cookie);
+ }
+
+ WorkerContext* m_workerContext;
+};
+
+}
+
+WorkerInspectorController::WorkerInspectorController(WorkerContext* workerContext)
+ : m_workerContext(workerContext)
+ , m_stateClient(adoptPtr(new WorkerStateClient(workerContext)))
+ , m_state(adoptPtr(new InspectorCompositeState(m_stateClient.get())))
+ , m_instrumentingAgents(InstrumentingAgents::create())
+ , m_injectedScriptManager(InjectedScriptManager::createForWorker())
+ , m_runtimeAgent(0)
+{
+ OwnPtr<InspectorRuntimeAgent> runtimeAgent = WorkerRuntimeAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get(), workerContext);
+ m_runtimeAgent = runtimeAgent.get();
+ m_agents.append(runtimeAgent.release());
+
+ OwnPtr<InspectorConsoleAgent> consoleAgent = WorkerConsoleAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get());
+ OwnPtr<InspectorDebuggerAgent> debuggerAgent = WorkerDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), workerContext, m_injectedScriptManager.get());
+ InspectorDebuggerAgent* debuggerAgentPtr = debuggerAgent.get();
+ m_runtimeAgent->setScriptDebugServer(&debuggerAgent->scriptDebugServer());
+ m_agents.append(debuggerAgent.release());
+
+ m_agents.append(InspectorProfilerAgent::create(m_instrumentingAgents.get(), consoleAgent.get(), workerContext, m_state.get(), m_injectedScriptManager.get()));
+ m_agents.append(InspectorHeapProfilerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptManager.get()));
+ m_agents.append(InspectorTimelineAgent::create(m_instrumentingAgents.get(), 0, 0, m_state.get(), InspectorTimelineAgent::WorkerInspector, 0));
+ m_agents.append(consoleAgent.release());
+
+ m_injectedScriptManager->injectedScriptHost()->init(0
+ , 0
+ , 0
+ , 0
+ , 0
+ , debuggerAgentPtr
+ );
+}
+
+WorkerInspectorController::~WorkerInspectorController()
+{
+ m_instrumentingAgents->reset();
+ disconnectFrontend();
+}
+
+void WorkerInspectorController::connectFrontend()
+{
+ ASSERT(!m_frontend);
+ m_state->unmute();
+ m_frontendChannel = adoptPtr(new PageInspectorProxy(m_workerContext));
+ m_frontend = adoptPtr(new InspectorFrontend(m_frontendChannel.get()));
+ m_backendDispatcher = InspectorBackendDispatcher::create(m_frontendChannel.get());
+ m_agents.registerInDispatcher(m_backendDispatcher.get());
+ m_agents.setFrontend(m_frontend.get());
+}
+
+void WorkerInspectorController::disconnectFrontend()
+{
+ if (!m_frontend)
+ return;
+ m_backendDispatcher->clearFrontend();
+ m_backendDispatcher.clear();
+ // Destroying agents would change the state, but we don't want that.
+ // Pre-disconnect state will be used to restore inspector agents.
+ m_state->mute();
+ m_agents.clearFrontend();
+ m_frontend.clear();
+ m_frontendChannel.clear();
+}
+
+void WorkerInspectorController::restoreInspectorStateFromCookie(const String& inspectorCookie)
+{
+ ASSERT(!m_frontend);
+ connectFrontend();
+ m_state->loadFromCookie(inspectorCookie);
+
+ m_agents.restore();
+}
+
+void WorkerInspectorController::dispatchMessageFromFrontend(const String& message)
+{
+ if (m_backendDispatcher)
+ m_backendDispatcher->dispatch(message);
+}
+
+void WorkerInspectorController::resume()
+{
+ ErrorString unused;
+ m_runtimeAgent->run(&unused);
+}
+
+}
diff --git a/Source/core/inspector/WorkerInspectorController.h b/Source/core/inspector/WorkerInspectorController.h
new file mode 100644
index 0000000..ce09a0b
--- /dev/null
+++ b/Source/core/inspector/WorkerInspectorController.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 WorkerInspectorController_h
+#define WorkerInspectorController_h
+
+#include "core/inspector/InspectorBaseAgent.h"
+#include <wtf/FastAllocBase.h>
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class InjectedScriptManager;
+class InspectorBackendDispatcher;
+class InspectorFrontend;
+class InspectorFrontendChannel;
+class InspectorRuntimeAgent;
+class InspectorState;
+class InspectorStateClient;
+class InstrumentingAgents;
+class WorkerContext;
+
+class WorkerInspectorController {
+ WTF_MAKE_NONCOPYABLE(WorkerInspectorController);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ WorkerInspectorController(WorkerContext*);
+ ~WorkerInspectorController();
+
+ bool hasFrontend() const { return m_frontend; }
+ void connectFrontend();
+ void disconnectFrontend();
+ void restoreInspectorStateFromCookie(const String& inspectorCookie);
+ void dispatchMessageFromFrontend(const String&);
+ void resume();
+
+private:
+ friend InstrumentingAgents* instrumentationForWorkerContext(WorkerContext*);
+
+ WorkerContext* m_workerContext;
+ OwnPtr<InspectorStateClient> m_stateClient;
+ OwnPtr<InspectorCompositeState> m_state;
+ RefPtr<InstrumentingAgents> m_instrumentingAgents;
+ OwnPtr<InjectedScriptManager> m_injectedScriptManager;
+ InspectorRuntimeAgent* m_runtimeAgent;
+ InspectorAgentRegistry m_agents;
+ OwnPtr<InspectorFrontendChannel> m_frontendChannel;
+ OwnPtr<InspectorFrontend> m_frontend;
+ RefPtr<InspectorBackendDispatcher> m_backendDispatcher;
+};
+
+}
+
+#endif // !defined(WorkerInspectorController_h)
diff --git a/Source/core/inspector/WorkerRuntimeAgent.cpp b/Source/core/inspector/WorkerRuntimeAgent.cpp
new file mode 100644
index 0000000..43bb707
--- /dev/null
+++ b/Source/core/inspector/WorkerRuntimeAgent.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "core/inspector/WorkerRuntimeAgent.h"
+
+#include "bindings/v8/ScriptState.h"
+#include "core/inspector/InjectedScript.h"
+#include "core/inspector/InstrumentingAgents.h"
+#include "core/inspector/WorkerDebuggerAgent.h"
+#include "core/workers/WorkerContext.h"
+#include "core/workers/WorkerRunLoop.h"
+#include "core/workers/WorkerThread.h"
+
+namespace WebCore {
+
+WorkerRuntimeAgent::WorkerRuntimeAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, WorkerContext* workerContext)
+ : InspectorRuntimeAgent(instrumentingAgents, state, injectedScriptManager)
+ , m_workerContext(workerContext)
+ , m_paused(false)
+{
+ m_instrumentingAgents->setWorkerRuntimeAgent(this);
+}
+
+WorkerRuntimeAgent::~WorkerRuntimeAgent()
+{
+ m_instrumentingAgents->setWorkerRuntimeAgent(0);
+}
+
+InjectedScript WorkerRuntimeAgent::injectedScriptForEval(ErrorString* error, const int* executionContextId)
+{
+ if (executionContextId) {
+ *error = "Execution context id is not supported for workers as there is only one execution context.";
+ return InjectedScript();
+ }
+ ScriptState* scriptState = scriptStateFromWorkerContext(m_workerContext);
+ return injectedScriptManager()->injectedScriptFor(scriptState);
+}
+
+void WorkerRuntimeAgent::muteConsole()
+{
+ // We don't need to mute console for workers.
+}
+
+void WorkerRuntimeAgent::unmuteConsole()
+{
+ // We don't need to mute console for workers.
+}
+
+void WorkerRuntimeAgent::run(ErrorString*)
+{
+ m_paused = false;
+}
+
+void WorkerRuntimeAgent::pauseWorkerContext(WorkerContext* context)
+{
+ m_paused = true;
+ MessageQueueWaitResult result;
+ do {
+ result = context->thread()->runLoop().runInMode(context, WorkerDebuggerAgent::debuggerTaskMode);
+ // Keep waiting until execution is resumed.
+ } while (result == MessageQueueMessageReceived && m_paused);
+}
+
+} // namespace WebCore
diff --git a/Source/core/inspector/WorkerRuntimeAgent.h b/Source/core/inspector/WorkerRuntimeAgent.h
new file mode 100644
index 0000000..67381bb
--- /dev/null
+++ b/Source/core/inspector/WorkerRuntimeAgent.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 WorkerRuntimeAgent_h
+#define WorkerRuntimeAgent_h
+
+#include "core/inspector/InspectorRuntimeAgent.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WorkerContext;
+
+class WorkerRuntimeAgent : public InspectorRuntimeAgent {
+public:
+ static PassOwnPtr<WorkerRuntimeAgent> create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InjectedScriptManager* injectedScriptManager, WorkerContext* context)
+ {
+ return adoptPtr(new WorkerRuntimeAgent(instrumentingAgents, state, injectedScriptManager, context));
+ }
+ virtual ~WorkerRuntimeAgent();
+
+ // Protocol commands.
+ virtual void run(ErrorString*);
+
+ void pauseWorkerContext(WorkerContext*);
+
+private:
+ WorkerRuntimeAgent(InstrumentingAgents*, InspectorCompositeState*, InjectedScriptManager*, WorkerContext*);
+ virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId);
+ virtual void muteConsole();
+ virtual void unmuteConsole();
+ WorkerContext* m_workerContext;
+ bool m_paused;
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorPagerAgent_h)
diff --git a/Source/core/inspector/combine-javascript-resources.pl b/Source/core/inspector/combine-javascript-resources.pl
new file mode 100755
index 0000000..428b6b7
--- /dev/null
+++ b/Source/core/inspector/combine-javascript-resources.pl
@@ -0,0 +1,81 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2008 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. ``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
+# 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.
+
+# Script to combine multiple JavaScript files into one file, based on
+# the script tags in the head of an input HTML file.
+
+use strict;
+use Getopt::Long;
+use File::Basename;
+use File::Path;
+
+my $generatedScriptsDirectory;
+my $outputDirectory;
+my $scriptName;
+my $htmlFile;
+
+GetOptions('output-dir=s' => \$outputDirectory,
+ 'output-script-name=s' => \$scriptName,
+ 'generated-scripts-dir=s' => \$generatedScriptsDirectory,
+ 'input-html=s' => \$htmlFile);
+
+unless (defined $htmlFile and defined $scriptName and defined $outputDirectory) {
+ print "Usage: $0 --input-html <path> --output-dir path --output-script-name <name>\n";
+ exit;
+}
+
+my $htmlDirectory = dirname($htmlFile);
+my $htmlContents;
+
+{
+ local $/;
+ open HTML, $htmlFile or die;
+ $htmlContents = <HTML>;
+ close HTML;
+}
+
+$htmlContents =~ m/<head>(.*)<\/head>/si;
+my $headContents = $1;
+
+mkpath $outputDirectory;
+open SCRIPT_OUT, ">", "$outputDirectory/$scriptName" or die "Can't open $outputDirectory/$scriptName: $!";
+
+while ($headContents =~ m/<script.*src="([^"]*)"[^>]*>/gi) {
+ local $/;
+ open SCRIPT_IN, "$generatedScriptsDirectory/$1" or open SCRIPT_IN, "$htmlDirectory/$1" or die "Can't open $htmlDirectory/$1: $!";
+ print SCRIPT_OUT "/* $1 */\n\n";
+ print SCRIPT_OUT <SCRIPT_IN>;
+ close SCRIPT_IN;
+}
+
+close SCRIPT_OUT;
+
+$headContents =~ s/<script.*src="[^"]*"[^>]*><\/script>\s*//gi;
+$headContents .= "<script type=\"text/javascript\" src=\"$scriptName\"></script>\n";
+$htmlContents =~ s/<head>.*<\/head>/<head>$headContents<\/head>/si;
+
+open HTML, ">", "$outputDirectory/" . basename($htmlFile) or die "Can't open $outputDirectory/" . basename($htmlFile) . ": $!";
+print HTML $htmlContents;
+close HTML;
diff --git a/Source/core/inspector/generate-inspector-protocol-version b/Source/core/inspector/generate-inspector-protocol-version
new file mode 100755
index 0000000..12f4298
--- /dev/null
+++ b/Source/core/inspector/generate-inspector-protocol-version
@@ -0,0 +1,476 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER OR 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.
+#
+# Inspector protocol validator.
+#
+# Tests that subsequent protocol changes are not breaking backwards compatibility.
+# Following violations are reported:
+#
+# - Domain has been removed
+# - Command has been removed
+# - Required command parameter was added or changed from optional
+# - Required response parameter was removed or changed to optional
+# - Event has been removed
+# - Required event parameter was removed or changed to optional
+# - Parameter type has changed.
+#
+# For the parameters with composite types the above checks are also applied
+# recursively to every property of the type.
+#
+# Adding --show_changes to the command line prints out a list of valid public API changes.
+
+import os.path
+import re
+import sys
+
+def list_to_map(items, key):
+ result = {}
+ for item in items:
+ if not "hidden" in item:
+ result[item[key]] = item
+ return result
+
+def named_list_to_map(container, name, key):
+ if name in container:
+ return list_to_map(container[name], key)
+ return {}
+
+def removed(reverse):
+ if reverse:
+ return "added"
+ return "removed"
+
+def required(reverse):
+ if reverse:
+ return "optional"
+ return "required"
+
+def compare_schemas(schema_1, schema_2, reverse):
+ errors = []
+ types_1 = normalize_types_in_schema(schema_1)
+ types_2 = normalize_types_in_schema(schema_2)
+
+ domains_by_name_1 = list_to_map(schema_1, "domain")
+ domains_by_name_2 = list_to_map(schema_2, "domain")
+
+ for name in domains_by_name_1:
+ domain_1 = domains_by_name_1[name]
+ if not name in domains_by_name_2:
+ errors.append("%s: domain has been %s" % (name, removed(reverse)))
+ continue
+ compare_domains(domain_1, domains_by_name_2[name], types_1, types_2, errors, reverse)
+ return errors
+
+def compare_domains(domain_1, domain_2, types_map_1, types_map_2, errors, reverse):
+ domain_name = domain_1["domain"]
+ commands_1 = named_list_to_map(domain_1, "commands", "name")
+ commands_2 = named_list_to_map(domain_2, "commands", "name")
+ for name in commands_1:
+ command_1 = commands_1[name]
+ if not name in commands_2:
+ errors.append("%s.%s: command has been %s" % (domain_1["domain"], name, removed(reverse)))
+ continue
+ compare_commands(domain_name, command_1, commands_2[name], types_map_1, types_map_2, errors, reverse)
+
+ events_1 = named_list_to_map(domain_1, "events", "name")
+ events_2 = named_list_to_map(domain_2, "events", "name")
+ for name in events_1:
+ event_1 = events_1[name]
+ if not name in events_2:
+ errors.append("%s.%s: event has been %s" % (domain_1["domain"], name, removed(reverse)))
+ continue
+ compare_events(domain_name, event_1, events_2[name], types_map_1, types_map_2, errors, reverse)
+
+def compare_commands(domain_name, command_1, command_2, types_map_1, types_map_2, errors, reverse):
+ context = domain_name + "." + command_1["name"]
+
+ params_1 = named_list_to_map(command_1, "parameters", "name")
+ params_2 = named_list_to_map(command_2, "parameters", "name")
+ # Note the reversed order: we allow removing but forbid adding parameters.
+ compare_params_list(context, "parameter", params_2, params_1, types_map_2, types_map_1, 0, errors, not reverse)
+
+ returns_1 = named_list_to_map(command_1, "returns", "name")
+ returns_2 = named_list_to_map(command_2, "returns", "name")
+ compare_params_list(context, "response parameter", returns_1, returns_2, types_map_1, types_map_2, 0, errors, reverse)
+
+def compare_events(domain_name, event_1, event_2, types_map_1, types_map_2, errors, reverse):
+ context = domain_name + "." + event_1["name"]
+ params_1 = named_list_to_map(event_1, "parameters", "name")
+ params_2 = named_list_to_map(event_2, "parameters", "name")
+ compare_params_list(context, "parameter", params_1, params_2, types_map_1, types_map_2, 0, errors, reverse)
+
+def compare_params_list(context, kind, params_1, params_2, types_map_1, types_map_2, depth, errors, reverse):
+ for name in params_1:
+ param_1 = params_1[name]
+ if not name in params_2:
+ if not "optional" in param_1:
+ errors.append("%s.%s: required %s has been %s" % (context, name, kind, removed(reverse)))
+ continue
+
+ param_2 = params_2[name]
+ if param_2 and "optional" in param_2 and not "optional" in param_1:
+ errors.append("%s.%s: %s %s is now %s" % (context, name, required(reverse), kind, required(not reverse)))
+ continue
+ type_1 = extract_type(param_1, types_map_1, errors)
+ type_2 = extract_type(param_2, types_map_2, errors)
+ compare_types(context + "." + name, kind, type_1, type_2, types_map_1, types_map_2, depth, errors, reverse)
+
+def compare_types(context, kind, type_1, type_2, types_map_1, types_map_2, depth, errors, reverse):
+ if depth > 10:
+ return
+
+ base_type_1 = type_1["type"]
+ base_type_2 = type_2["type"]
+
+ if base_type_1 != base_type_2:
+ errors.append("%s: %s base type mismatch, '%s' vs '%s'" % (context, kind, base_type_1, base_type_2))
+ elif base_type_1 == "object":
+ params_1 = named_list_to_map(type_1, "properties", "name")
+ params_2 = named_list_to_map(type_2, "properties", "name")
+ # If both parameters have the same named type use it in the context.
+ if "id" in type_1 and "id" in type_2 and type_1["id"] == type_2["id"]:
+ type_name = type_1["id"]
+ else:
+ type_name = "<object>"
+ context += " %s->%s" % (kind, type_name)
+ compare_params_list(context, "property", params_1, params_2, types_map_1, types_map_2, depth + 1, errors, reverse)
+ elif base_type_1 == "array":
+ item_type_1 = extract_type(type_1["items"], types_map_1, errors)
+ item_type_2 = extract_type(type_2["items"], types_map_2, errors)
+ compare_types(context, kind, item_type_1, item_type_2, types_map_1, types_map_2, depth + 1, errors, reverse)
+
+def extract_type(typed_object, types_map, errors):
+ if "type" in typed_object:
+ result = { "id": "<transient>", "type": typed_object["type"] }
+ if typed_object["type"] == "object":
+ result["properties"] = []
+ elif typed_object["type"] == "array":
+ result["items"] = typed_object["items"]
+ return result
+ elif "$ref" in typed_object:
+ ref = typed_object["$ref"]
+ if not ref in types_map:
+ errors.append("Can not resolve type: %s" % ref)
+ types_map[ref] = { "id": "<transient>", "type": "object" }
+ return types_map[ref]
+
+def normalize_types_in_schema(schema):
+ types = {}
+ for domain in schema:
+ domain_name = domain["domain"]
+ normalize_types(domain, domain_name, types)
+ return types
+
+def normalize_types(obj, domain_name, types):
+ if isinstance(obj, list):
+ for item in obj:
+ normalize_types(item, domain_name, types)
+ elif isinstance(obj, dict):
+ for key, value in obj.items():
+ if key == "$ref" and value.find(".") == -1:
+ obj[key] = "%s.%s" % (domain_name, value)
+ elif key == "id":
+ obj[key] = "%s.%s" % (domain_name, value)
+ types[obj[key]] = obj
+ else:
+ normalize_types(value, domain_name, types)
+
+def load_json(filename):
+ input_file = open(filename, "r")
+ json_string = input_file.read()
+ json_string = re.sub(":\s*true", ": True", json_string)
+ json_string = re.sub(":\s*false", ": False", json_string)
+ return eval(json_string)
+
+def self_test():
+ def create_test_schema_1():
+ return [
+ {
+ "domain": "Network",
+ "types": [
+ {
+ "id": "LoaderId",
+ "type": "string"
+ },
+ {
+ "id": "Headers",
+ "type": "object"
+ },
+ {
+ "id": "Request",
+ "type": "object",
+ "properties": [
+ { "name": "url", "type": "string" },
+ { "name": "method", "type": "string" },
+ { "name": "headers", "$ref": "Headers" },
+ { "name": "becameOptionalField", "type": "string" },
+ { "name": "removedField", "type": "string" },
+ ]
+ }
+ ],
+ "commands": [
+ {
+ "name": "removedCommand",
+ },
+ {
+ "name": "setExtraHTTPHeaders",
+ "parameters": [
+ { "name": "headers", "$ref": "Headers" },
+ { "name": "mismatched", "type": "string" },
+ { "name": "becameOptional", "$ref": "Headers" },
+ { "name": "removedRequired", "$ref": "Headers" },
+ { "name": "becameRequired", "$ref": "Headers", "optional": True },
+ { "name": "removedOptional", "$ref": "Headers", "optional": True },
+ ],
+ "returns": [
+ { "name": "mimeType", "type": "string" },
+ { "name": "becameOptional", "type": "string" },
+ { "name": "removedRequired", "type": "string" },
+ { "name": "becameRequired", "type": "string", "optional": True },
+ { "name": "removedOptional", "type": "string", "optional": True },
+ ]
+ }
+ ],
+ "events": [
+ {
+ "name": "requestWillBeSent",
+ "parameters": [
+ { "name": "frameId", "type": "string", "hidden": True },
+ { "name": "request", "$ref": "Request" },
+ { "name": "becameOptional", "type": "string" },
+ { "name": "removedRequired", "type": "string" },
+ { "name": "becameRequired", "type": "string", "optional": True },
+ { "name": "removedOptional", "type": "string", "optional": True },
+ ]
+ },
+ {
+ "name": "removedEvent",
+ "parameters": [
+ { "name": "errorText", "type": "string" },
+ { "name": "canceled", "type": "boolean", "optional": True }
+ ]
+ }
+ ]
+ },
+ {
+ "domain": "removedDomain"
+ }
+ ]
+
+ def create_test_schema_2():
+ return [
+ {
+ "domain": "Network",
+ "types": [
+ {
+ "id": "LoaderId",
+ "type": "string"
+ },
+ {
+ "id": "Request",
+ "type": "object",
+ "properties": [
+ { "name": "url", "type": "string" },
+ { "name": "method", "type": "string" },
+ { "name": "headers", "type": "object" },
+ { "name": "becameOptionalField", "type": "string", "optional": True },
+ ]
+ }
+ ],
+ "commands": [
+ {
+ "name": "addedCommand",
+ },
+ {
+ "name": "setExtraHTTPHeaders",
+ "parameters": [
+ { "name": "headers", "type": "object" },
+ { "name": "mismatched", "type": "object" },
+ { "name": "becameOptional", "type": "object" , "optional": True },
+ { "name": "addedRequired", "type": "object" },
+ { "name": "becameRequired", "type": "object" },
+ { "name": "addedOptional", "type": "object", "optional": True },
+ ],
+ "returns": [
+ { "name": "mimeType", "type": "string" },
+ { "name": "becameOptional", "type": "string", "optional": True },
+ { "name": "addedRequired", "type": "string"},
+ { "name": "becameRequired", "type": "string" },
+ { "name": "addedOptional", "type": "string", "optional": True },
+ ]
+ }
+ ],
+ "events": [
+ {
+ "name": "requestWillBeSent",
+ "parameters": [
+ { "name": "request", "$ref": "Request" },
+ { "name": "becameOptional", "type": "string", "optional": True },
+ { "name": "addedRequired", "type": "string"},
+ { "name": "becameRequired", "type": "string" },
+ { "name": "addedOptional", "type": "string", "optional": True },
+ ]
+ },
+ {
+ "name": "addedEvent"
+ }
+ ]
+ },
+ {
+ "domain": "addedDomain"
+ }
+ ]
+
+ expected_errors = [
+ "removedDomain: domain has been removed",
+ "Network.removedCommand: command has been removed",
+ "Network.removedEvent: event has been removed",
+ "Network.setExtraHTTPHeaders.mismatched: parameter base type mismatch, 'object' vs 'string'",
+ "Network.setExtraHTTPHeaders.addedRequired: required parameter has been added",
+ "Network.setExtraHTTPHeaders.becameRequired: optional parameter is now required",
+ "Network.setExtraHTTPHeaders.removedRequired: required response parameter has been removed",
+ "Network.setExtraHTTPHeaders.becameOptional: required response parameter is now optional",
+ "Network.requestWillBeSent.removedRequired: required parameter has been removed",
+ "Network.requestWillBeSent.becameOptional: required parameter is now optional",
+ "Network.requestWillBeSent.request parameter->Network.Request.removedField: required property has been removed",
+ "Network.requestWillBeSent.request parameter->Network.Request.becameOptionalField: required property is now optional",
+ ]
+
+ expected_errors_reverse = [
+ "addedDomain: domain has been added",
+ "Network.addedEvent: event has been added",
+ "Network.addedCommand: command has been added",
+ "Network.setExtraHTTPHeaders.mismatched: parameter base type mismatch, 'string' vs 'object'",
+ "Network.setExtraHTTPHeaders.removedRequired: required parameter has been removed",
+ "Network.setExtraHTTPHeaders.becameOptional: required parameter is now optional",
+ "Network.setExtraHTTPHeaders.addedRequired: required response parameter has been added",
+ "Network.setExtraHTTPHeaders.becameRequired: optional response parameter is now required",
+ "Network.requestWillBeSent.becameRequired: optional parameter is now required",
+ "Network.requestWillBeSent.addedRequired: required parameter has been added",
+ ]
+
+ def is_subset(subset, superset, message):
+ for i in range(len(subset)):
+ if subset[i] not in superset:
+ sys.stderr.write("%s error: %s\n" % (message, subset[i]))
+ return False
+ return True
+
+ def errors_match(expected, actual):
+ return (is_subset(actual, expected, "Unexpected") and
+ is_subset(expected, actual, "Missing"))
+
+ return (errors_match(expected_errors,
+ compare_schemas(create_test_schema_1(), create_test_schema_2(), False)) and
+ errors_match(expected_errors_reverse,
+ compare_schemas(create_test_schema_2(), create_test_schema_1(), True)))
+
+
+def main():
+ if not self_test():
+ sys.stderr.write("Self-test failed")
+ return 1
+
+ if len(sys.argv) < 4 or sys.argv[1] != "-o":
+ sys.stderr.write("Usage: %s -o OUTPUT_FILE INPUT_FILE [--show-changes]\n" % sys.argv[0])
+ return 1
+
+ output_path = sys.argv[2]
+ output_file = open(output_path, "w")
+
+ input_path = sys.argv[3]
+ dir_name = os.path.dirname(input_path)
+ schema = load_json(input_path)
+
+ major = schema["version"]["major"]
+ minor = schema["version"]["minor"]
+ version = "%s.%s" % (major, minor)
+ if len(dir_name) == 0:
+ dir_name = "."
+ baseline_path = os.path.normpath(dir_name + "/Inspector-" + version + ".json")
+ baseline_schema = load_json(baseline_path)
+
+ errors = compare_schemas(baseline_schema["domains"], schema["domains"], False)
+ if len(errors) > 0:
+ sys.stderr.write(" Compatibility with %s: FAILED\n" % version)
+ for error in errors:
+ sys.stderr.write( " %s\n" % error)
+ return 1
+
+ if len(sys.argv) > 4 and sys.argv[4] == "--show-changes":
+ changes = compare_schemas(
+ load_json(input_path)["domains"], load_json(baseline_path)["domains"], True)
+ if len(changes) > 0:
+ print " Public changes since %s:" % version
+ for change in changes:
+ print " %s" % change
+
+ output_file.write("""
+#ifndef InspectorProtocolVersion_h
+#define InspectorProtocolVersion_h
+
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+String inspectorProtocolVersion() { return "%s"; }
+
+int inspectorProtocolVersionMajor() { return %s; }
+
+int inspectorProtocolVersionMinor() { return %s; }
+
+bool supportsInspectorProtocolVersion(const String& version)
+{
+ Vector<String> tokens;
+ version.split(".", tokens);
+ if (tokens.size() != 2)
+ return false;
+
+ bool ok = true;
+ int major = tokens[0].toInt(&ok);
+ if (!ok || major != %s)
+ return false;
+
+ int minor = tokens[1].toInt(&ok);
+ if (!ok || minor > %s)
+ return false;
+
+ return true;
+}
+
+}
+
+#endif // !defined(InspectorProtocolVersion_h)
+""" % (version, major, minor, major, minor))
+
+ output_file.close()
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/Source/core/inspector/inline-javascript-imports.py b/Source/core/inspector/inline-javascript-imports.py
new file mode 100755
index 0000000..e0a194f
--- /dev/null
+++ b/Source/core/inspector/inline-javascript-imports.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2011 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER OR 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.
+#
+
+# This script replaces calls to importScripts with script sources
+# in input script file and dumps result into output script file.
+
+from cStringIO import StringIO
+
+import os.path
+import re
+import sys
+
+
+def main(argv):
+
+ if len(argv) < 3:
+ print('usage: %s inputFile importsDir outputFile' % argv[0])
+ return 1
+
+ inputFileName = argv[1]
+ importsDir = argv[2]
+ outputFileName = argv[3]
+
+ inputFile = open(inputFileName, 'r')
+ inputScript = inputFile.read()
+ inputFile.close()
+
+ def replace(match):
+ importFileName = match.group(1)
+ fullPath = os.path.join(importsDir, importFileName)
+ if not os.access(fullPath, os.F_OK):
+ raise Exception('File %s referenced in %s not found on any source paths, '
+ 'check source tree for consistency' %
+ (importFileName, inputFileName))
+ importFile = open(fullPath, 'r')
+ importScript = importFile.read()
+ importFile.close()
+ return importScript
+
+ outputScript = re.sub(r'importScripts?\([\'"]([^\'"]+)[\'"]\)', replace, inputScript)
+
+ outputFile = open(outputFileName, 'w')
+ outputFile.write(outputScript)
+ outputFile.close()
+
+ # Touch output file directory to make sure that Xcode will copy
+ # modified resource files.
+ if sys.platform == 'darwin':
+ outputDirName = os.path.dirname(outputFileName)
+ os.utime(outputDirName, None)
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/Source/core/inspector/xxd.pl b/Source/core/inspector/xxd.pl
new file mode 100644
index 0000000..5ee08a5
--- /dev/null
+++ b/Source/core/inspector/xxd.pl
@@ -0,0 +1,45 @@
+#! /usr/bin/perl
+
+# Copyright (C) 2010-2011 Google 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:
+#
+# # Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# # 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.
+# # Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER OR 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.
+#
+
+$varname = shift;
+$fname = shift;
+$output = shift;
+
+open($input, '<', $fname) or die "Can't open file for read: $fname $!";
+$/ = undef;
+$text = <$input>;
+close($input);
+
+$text = join(', ', map('0x' . unpack("H*", $_), split(undef, $text)));
+
+open($output, '>', $output) or die "Can't open file for write: $output $!";
+print $output "const unsigned char $varname\[\] = {\n$text\n};\n";
+close($output);