summaryrefslogtreecommitdiffstats
path: root/WebCore/inspector
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/inspector')
-rw-r--r--WebCore/inspector/CodeGeneratorInspector.pm1
-rw-r--r--WebCore/inspector/Inspector.idl13
-rw-r--r--WebCore/inspector/InspectorCSSStore.cpp168
-rw-r--r--WebCore/inspector/InspectorCSSStore.h27
-rw-r--r--WebCore/inspector/InspectorClient.h5
-rw-r--r--WebCore/inspector/InspectorController.cpp369
-rw-r--r--WebCore/inspector/InspectorController.h34
-rw-r--r--WebCore/inspector/InspectorDOMAgent.cpp166
-rw-r--r--WebCore/inspector/InspectorDOMAgent.h5
-rw-r--r--WebCore/inspector/InspectorDebuggerAgent.cpp3
-rw-r--r--WebCore/inspector/InspectorProfilerAgent.cpp1
-rw-r--r--WebCore/inspector/InspectorResource.cpp109
-rw-r--r--WebCore/inspector/InspectorResource.h40
-rw-r--r--[-rwxr-xr-x]WebCore/inspector/front-end/AuditFormatters.js10
-rw-r--r--WebCore/inspector/front-end/BreakpointsSidebarPane.js11
-rw-r--r--WebCore/inspector/front-end/CallStackSidebarPane.js34
-rw-r--r--WebCore/inspector/front-end/ConsoleView.js15
-rw-r--r--WebCore/inspector/front-end/ElementsPanel.js39
-rw-r--r--WebCore/inspector/front-end/ElementsTreeOutline.js63
-rw-r--r--WebCore/inspector/front-end/HAREntry.js97
-rw-r--r--WebCore/inspector/front-end/InjectedScript.js4
-rw-r--r--WebCore/inspector/front-end/ProfileDataGridTree.js15
-rw-r--r--WebCore/inspector/front-end/Resource.js11
-rw-r--r--WebCore/inspector/front-end/ResourceView.js21
-rw-r--r--WebCore/inspector/front-end/ResourcesPanel.js45
-rw-r--r--WebCore/inspector/front-end/ScriptsPanel.js9
-rw-r--r--WebCore/inspector/front-end/Settings.js3
-rw-r--r--WebCore/inspector/front-end/StylesSidebarPane.js12
-rw-r--r--WebCore/inspector/front-end/WebKit.qrc1
-rw-r--r--WebCore/inspector/front-end/inspector.css17
-rw-r--r--WebCore/inspector/front-end/inspector.js155
-rw-r--r--WebCore/inspector/front-end/treeoutline.js1
-rw-r--r--WebCore/inspector/front-end/utilities.js9
33 files changed, 1124 insertions, 389 deletions
diff --git a/WebCore/inspector/CodeGeneratorInspector.pm b/WebCore/inspector/CodeGeneratorInspector.pm
index c7907b4..80e243b 100644
--- a/WebCore/inspector/CodeGeneratorInspector.pm
+++ b/WebCore/inspector/CodeGeneratorInspector.pm
@@ -606,6 +606,7 @@ sub generateSource
my @sourceContent = split("\r", $licenseTemplate);
push(@sourceContent, "\n#include \"config.h\"");
push(@sourceContent, "#include \"$className.h\"");
+ push(@sourceContent, "#include <wtf/text/CString.h>");
push(@sourceContent, "");
push(@sourceContent, "#if ENABLE(INSPECTOR)");
push(@sourceContent, "");
diff --git a/WebCore/inspector/Inspector.idl b/WebCore/inspector/Inspector.idl
index 169b188..ae136b2 100644
--- a/WebCore/inspector/Inspector.idl
+++ b/WebCore/inspector/Inspector.idl
@@ -44,13 +44,9 @@ module core {
[notify] void evaluateForTestInFrontend(out long testCallId, out String script);
[notify] void disconnectFromBackend();
[notify] void inspectedURLChanged(out String url);
- [notify] void monitoringXHRWasEnabled();
- [notify] void monitoringXHRWasDisabled();
[notify] void removeResource(out unsigned long identifier);
[notify] void reset();
[notify] void resetProfilesPanel();
- [notify] void resourceTrackingWasEnabled();
- [notify] void resourceTrackingWasDisabled();
[notify] void searchingForNodeWasEnabled();
[notify] void searchingForNodeWasDisabled();
[notify] void setChildNodes(out long parentId, out Array nodes);
@@ -102,6 +98,7 @@ module core {
[handler=Controller] void populateScriptObjects();
[handler=Controller] void getSettings(out Object settings);
+ [handler=Controller] void getInspectorState(out Object state);
[handler=Controller] void storeLastActivePanel(in String panelName);
[handler=Controller] void saveApplicationSettings(in String settings);
@@ -110,11 +107,9 @@ module core {
[handler=Controller] void enableSearchingForNode();
[handler=Controller] void disableSearchingForNode();
- [handler=Controller] void enableMonitoringXHR();
- [handler=Controller] void disableMonitoringXHR();
+ [handler=Controller] void setMonitoringXHREnabled(in boolean enable, out boolean newState);
- [handler=Controller] void enableResourceTracking(in boolean always);
- [handler=Controller] void disableResourceTracking(in boolean always);
+ [handler=Controller] void setResourceTrackingEnabled(in boolean enabled, in boolean always, out boolean newState);
[handler=Controller] void getResourceContent(in unsigned long identifier, out String content);
[handler=Controller] void reloadPage();
@@ -188,7 +183,7 @@ module core {
[handler=DOM] void getInlineStyle(in long nodeId, out Value style);
[handler=DOM] void getComputedStyle(in long nodeId, out Value style);
[handler=DOM] void getStyleSheet(in long styleSheetId, out Object styleSheet);
- [handler=DOM] void getRuleRanges(in long styleSheetId, out Value ranges);
+ [handler=DOM] void getStyleSourceData(in long styleSheetId, out Object styleSourceData);
[handler=DOM] void applyStyleText(in long styleId, in String styleText, in String propertyName, out boolean success, out Value style, out Array changedProperties);
[handler=DOM] void setStyleText(in long styleId, in String styleText, out boolean success);
[handler=DOM] void setStyleProperty(in long styleId, in String name, in String value, out boolean success);
diff --git a/WebCore/inspector/InspectorCSSStore.cpp b/WebCore/inspector/InspectorCSSStore.cpp
index c2dc4f1..b019860 100644
--- a/WebCore/inspector/InspectorCSSStore.cpp
+++ b/WebCore/inspector/InspectorCSSStore.cpp
@@ -37,11 +37,18 @@
#include "CSSStyleDeclaration.h"
#include "CSSStyleRule.h"
#include "CSSStyleSheet.h"
+#include "CachedResource.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "Frame.h"
#include "HTMLHeadElement.h"
#include "InspectorController.h"
#include "InspectorResource.h"
+#include "Node.h"
#include "PlatformString.h"
+#include "SharedBuffer.h"
#include "StyleSheetList.h"
+#include "TextEncoding.h"
namespace WebCore {
@@ -67,6 +74,7 @@ void InspectorCSSStore::reset()
m_styleSheetToOffsets.clear();
m_styleSheetToId.clear();
m_idToStyleSheet.clear();
+ m_idToStyleSheetText.clear();
m_idToDisabledStyle.clear();
m_documentNodeToInspectorStyleSheetMap.clear();
@@ -104,48 +112,145 @@ CSSStyleSheet* InspectorCSSStore::inspectorStyleSheet(Document* ownerDocument, b
return inspectorStyleSheet;
}
-HashMap<long, SourceRange> InspectorCSSStore::getRuleRanges(CSSStyleSheet* styleSheet)
+String InspectorCSSStore::styleSheetText(long styleSheetId)
{
+ IdToStyleSheetTextMap::iterator it = m_idToStyleSheetText.find(styleSheetId);
+ if (it != m_idToStyleSheetText.end())
+ return it->second;
+
+ CSSStyleSheet* styleSheet = styleSheetForId(styleSheetId);
+ if (!styleSheet)
+ return String();
+
+ String result;
+ bool success = false;
+ Node* ownerNode = styleSheet->ownerNode();
+ if (ownerNode && ownerNode->nodeType() == Node::ELEMENT_NODE) {
+ Element* ownerElement = static_cast<Element*>(ownerNode);
+ if (ownerElement->tagName().lower() == "style") {
+ result = inlineStyleSheetText(styleSheet);
+ success = true;
+ }
+ }
+ if (!success)
+ success = resourceStyleSheetText(styleSheet, &result);
+
+ if (success)
+ m_idToStyleSheetText.set(styleSheetId, result);
+ return result;
+}
+
+bool InspectorCSSStore::resourceStyleSheetText(CSSStyleSheet* styleSheet, String* result)
+{
+ return m_inspectorController->resourceContentForURL(styleSheet->finalURL(), styleSheet->document(), result);
+}
+
+String InspectorCSSStore::inlineStyleSheetText(CSSStyleSheet* styleSheet)
+{
+ Node* ownerNode = styleSheet->ownerNode();
+ if (!ownerNode || ownerNode->nodeType() != Node::ELEMENT_NODE || m_styleSheetToId.find(styleSheet) == m_styleSheetToId.end())
+ return String();
+ Element* ownerElement = static_cast<Element*>(ownerNode);
+ if (ownerElement->tagName().lower() != "style")
+ return String();
+ return ownerElement->innerText();
+}
+
+
+// All ranges are: [start; end) (start - inclusive, end - exclusive).
+bool InspectorCSSStore::getStyleSourceData(CSSStyleDeclaration* style, RefPtr<CSSStyleSourceData>* result)
+{
+ if (!style)
+ return false;
+
+ Element* element = inlineStyleElement(style);
+ if (element) {
+ // Inline: style="...".
+ RefPtr<CSSStyleSourceData> styleSourceData = CSSStyleSourceData::create();
+ bool success = getStyleAttributeRanges(element, &styleSourceData);
+ if (!success)
+ return false;
+ *result = styleSourceData;
+ return true;
+ }
+
+ CSSStyleSheet* styleSheet = getParentStyleSheet(style);
if (!styleSheet)
- return HashMap<long, SourceRange>();
- RefPtr<CSSRuleList> originalRuleList = CSSRuleList::create(styleSheet, false);
+ return false;
+
+ Vector<RefPtr<CSSStyleSourceData> >* rangesVector = 0;
StyleSheetToOffsetsMap::iterator it = m_styleSheetToOffsets.find(styleSheet);
- Vector<SourceRange>* offsetVector = 0;
if (it == m_styleSheetToOffsets.end()) {
- InspectorResource* resource = m_inspectorController->resourceForURL(styleSheet->finalURL().string());
- if (resource) {
- offsetVector = new Vector<SourceRange>;
+ String text = styleSheetText(bindStyleSheet(styleSheet));
+ if (!text.isEmpty()) {
RefPtr<CSSStyleSheet> newStyleSheet = CSSStyleSheet::create(styleSheet->ownerNode());
CSSParser p;
- CSSParser::StyleRuleRanges ruleRangeMap;
- p.parseSheet(newStyleSheet.get(), resource->sourceString(), 0, &ruleRangeMap);
- for (unsigned i = 0, length = newStyleSheet->length(); i < length; ++i) {
- CSSStyleRule* rule = asCSSStyleRule(newStyleSheet->item(i));
- if (!rule)
- continue;
- HashMap<CSSStyleRule*, std::pair<unsigned, unsigned> >::iterator it = ruleRangeMap.find(rule);
- if (it != ruleRangeMap.end())
- offsetVector->append(it->second);
- }
- m_styleSheetToOffsets.set(styleSheet, offsetVector);
+ StyleRuleRangeMap ruleRangeMap;
+ p.parseSheet(newStyleSheet.get(), text, 0, &ruleRangeMap);
+ rangesVector = new Vector<RefPtr<CSSStyleSourceData> >;
+ extractRanges(newStyleSheet.get(), ruleRangeMap, rangesVector);
+ m_styleSheetToOffsets.set(styleSheet, rangesVector);
}
} else
- offsetVector = it->second;
- if (!offsetVector)
- return HashMap<long, SourceRange>();
+ rangesVector = it->second;
+ if (!rangesVector)
+ return false;
unsigned ruleIndex = 0;
- HashMap<long, SourceRange> result;
for (unsigned i = 0, length = styleSheet->length(); i < length; ++i) {
- ASSERT(ruleIndex < offsetVector->size());
CSSStyleRule* rule = asCSSStyleRule(styleSheet->item(i));
if (!rule)
continue;
- // This maps the style id to the rule body range.
- result.set(bindStyle(rule->style()), offsetVector->at(ruleIndex));
+ if (rule->style() == style) {
+ ASSERT(ruleIndex < rangesVector->size());
+ *result = rangesVector->at(ruleIndex);
+ return true;
+ }
ruleIndex++;
}
- return result;
+ return false;
+}
+
+void InspectorCSSStore::extractRanges(CSSStyleSheet* styleSheet, const StyleRuleRangeMap& ruleRangeMap, Vector<RefPtr<CSSStyleSourceData> >* rangesVector)
+{
+ for (unsigned i = 0, length = styleSheet->length(); i < length; ++i) {
+ CSSStyleRule* rule = asCSSStyleRule(styleSheet->item(i));
+ if (!rule)
+ continue;
+ StyleRuleRangeMap::const_iterator it = ruleRangeMap.find(rule);
+ if (it != ruleRangeMap.end())
+ rangesVector->append(it->second);
+ }
+}
+
+bool InspectorCSSStore::getStyleAttributeRanges(Node* node, RefPtr<CSSStyleSourceData>* result)
+{
+ if (!node || !node->isStyledElement())
+ return false;
+
+ String styleText = static_cast<StyledElement*>(node)->getAttribute("style");
+ if (styleText.isEmpty()) {
+ (*result)->styleBodyRange.start = 0;
+ (*result)->styleBodyRange.end = 0;
+ return true;
+ }
+
+ RefPtr<CSSMutableStyleDeclaration> tempDeclaration = CSSMutableStyleDeclaration::create();
+ CSSParser p;
+ p.parseDeclaration(tempDeclaration.get(), styleText, result->get());
+ return true;
+}
+
+CSSStyleSheet* InspectorCSSStore::getParentStyleSheet(CSSStyleDeclaration* style)
+{
+ if (!style)
+ return 0;
+
+ StyleSheet* styleSheet = style->stylesheet();
+ if (styleSheet && styleSheet->isCSSStyleSheet())
+ return static_cast<CSSStyleSheet*>(styleSheet);
+
+ return 0;
}
CSSStyleRule* InspectorCSSStore::asCSSStyleRule(StyleBase* styleBase)
@@ -217,6 +322,17 @@ long InspectorCSSStore::bindRule(CSSStyleRule* rule)
return id;
}
+// static
+Element* InspectorCSSStore::inlineStyleElement(CSSStyleDeclaration* style)
+{
+ if (!style || !style->isMutableStyleDeclaration())
+ return 0;
+ Node* node = static_cast<CSSMutableStyleDeclaration*>(style)->node();
+ if (!node || !node->isStyledElement() || static_cast<StyledElement*>(node)->getInlineStyleDecl() != style)
+ return 0;
+ return static_cast<Element*>(node);
+}
+
} // namespace WebCore
#endif // ENABLE(INSPECTOR)
diff --git a/WebCore/inspector/InspectorCSSStore.h b/WebCore/inspector/InspectorCSSStore.h
index 82de622..9b329df 100644
--- a/WebCore/inspector/InspectorCSSStore.h
+++ b/WebCore/inspector/InspectorCSSStore.h
@@ -29,46 +29,54 @@
#ifndef InspectorCSSStore_h
#define InspectorCSSStore_h
+#include "CSSPropertySourceData.h"
+#include "Cache.h"
+
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/RefPtr.h>
-#include <wtf/text/StringHash.h>
namespace WebCore {
-class Document;
-class InspectorController;
class CSSMutableStyleDeclaration;
class CSSStyleDeclaration;
class CSSRuleList;
class CSSStyleRule;
class CSSStyleSheet;
+class Document;
+class Element;
+class InspectorController;
+class Node;
class StyleBase;
typedef std::pair<String, String> PropertyValueAndPriority;
-typedef std::pair<unsigned, unsigned> SourceRange;
typedef HashMap<String, PropertyValueAndPriority> DisabledStyleDeclaration;
typedef HashMap<CSSStyleDeclaration*, long> StyleToIdMap;
typedef HashMap<long, RefPtr<CSSStyleDeclaration> > IdToStyleMap;
typedef HashMap<CSSStyleRule*, long> RuleToIdMap;
typedef HashMap<long, RefPtr<CSSStyleRule> > IdToRuleMap;
-typedef HashMap<CSSStyleSheet*, Vector<SourceRange>* > StyleSheetToOffsetsMap;
+typedef HashMap<CSSStyleSheet*, Vector<RefPtr<CSSStyleSourceData> >* > StyleSheetToOffsetsMap;
typedef HashMap<CSSStyleSheet*, long> StyleSheetToIdMap;
typedef HashMap<long, RefPtr<CSSStyleSheet> > IdToStyleSheetMap;
+typedef HashMap<long, String> IdToStyleSheetTextMap;
typedef HashMap<long, DisabledStyleDeclaration> IdToDisabledStyleMap;
typedef HashMap<RefPtr<Document>, RefPtr<CSSStyleSheet> > DocumentToStyleSheetMap;
class InspectorCSSStore {
public:
+ static CSSStyleSheet* getParentStyleSheet(CSSStyleDeclaration*);
+ static Element* inlineStyleElement(CSSStyleDeclaration*);
+
InspectorCSSStore(InspectorController* inspectorController);
~InspectorCSSStore();
void reset();
- HashMap<long, SourceRange> getRuleRanges(CSSStyleSheet*);
+ bool getStyleSourceData(CSSStyleDeclaration*, RefPtr<CSSStyleSourceData>* result);
CSSStyleDeclaration* styleForId(long styleId);
CSSStyleSheet* styleSheetForId(long styleSheetId);
CSSStyleRule* ruleForId(long styleRuleId);
DisabledStyleDeclaration* disabledStyleForId(long styleId, bool createIfAbsent);
+ String styleSheetText(long styleSheetId);
CSSStyleSheet* inspectorStyleSheet(Document* ownerDocument, bool createIfAbsent);
void removeDocument(Document*);
@@ -78,6 +86,10 @@ public:
private:
static CSSStyleRule* asCSSStyleRule(StyleBase*);
+ String inlineStyleSheetText(CSSStyleSheet*);
+ bool resourceStyleSheetText(CSSStyleSheet*, String* result);
+ void extractRanges(CSSStyleSheet*, const StyleRuleRangeMap&, Vector<RefPtr<CSSStyleSourceData> >* rangesVector);
+ bool getStyleAttributeRanges(Node* parentNode, RefPtr<CSSStyleSourceData>* result);
StyleToIdMap m_styleToId;
IdToStyleMap m_idToStyle;
@@ -85,8 +97,9 @@ private:
IdToRuleMap m_idToRule;
StyleSheetToOffsetsMap m_styleSheetToOffsets;
StyleSheetToIdMap m_styleSheetToId;
- IdToStyleSheetMap m_idToStyleSheet;
IdToDisabledStyleMap m_idToDisabledStyle;
+ IdToStyleSheetMap m_idToStyleSheet;
+ IdToStyleSheetTextMap m_idToStyleSheetText;
DocumentToStyleSheetMap m_documentNodeToInspectorStyleSheetMap;
InspectorController* m_inspectorController;
diff --git a/WebCore/inspector/InspectorClient.h b/WebCore/inspector/InspectorClient.h
index acd8b28..bb71b13 100644
--- a/WebCore/inspector/InspectorClient.h
+++ b/WebCore/inspector/InspectorClient.h
@@ -54,10 +54,7 @@ public:
// 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). Following callbacks allow embedders to track these states.
- virtual void resourceTrackingWasEnabled() { };
- virtual void resourceTrackingWasDisabled() { };
- virtual void timelineProfilerWasStarted() { };
- virtual void timelineProfilerWasStopped() { };
+ virtual void updateInspectorStateCookie(const String&) { };
};
} // namespace WebCore
diff --git a/WebCore/inspector/InspectorController.cpp b/WebCore/inspector/InspectorController.cpp
index 1e131f7..5f8f190 100644
--- a/WebCore/inspector/InspectorController.cpp
+++ b/WebCore/inspector/InspectorController.cpp
@@ -33,6 +33,7 @@
#if ENABLE(INSPECTOR)
#include "CachedResource.h"
+#include "CachedResourceLoader.h"
#include "Chrome.h"
#include "Console.h"
#include "ConsoleMessage.h"
@@ -71,6 +72,7 @@
#include "InspectorTimelineAgent.h"
#include "InspectorValues.h"
#include "InspectorWorkerResource.h"
+#include "IntRect.h"
#include "Page.h"
#include "ProgressTracker.h"
#include "Range.h"
@@ -117,26 +119,28 @@ using namespace std;
namespace WebCore {
-static const char* const resourceTrackingEnabledSettingName = "resourceTrackingEnabled";
-static const char* const debuggerEnabledSettingName = "debuggerEnabled";
-static const char* const profilerEnabledSettingName = "profilerEnabled";
-static const char* const inspectorAttachedHeightName = "inspectorAttachedHeight";
+static const char* const frontendSettingsSettingName = "frontendSettings";
+
+static const char* const debuggerAlwaysEnabledSettingName = "debuggerEnabled";
static const char* const lastActivePanel = "lastActivePanel";
+static const char* const monitoringXHRSettingName = "xhrMonitor";
+static const char* const resourceTrackingAlwaysEnabledSettingName = "resourceTrackingEnabled";
+static const char* const profilerAlwaysEnabledSettingName = "profilerEnabled";
+
+static const char* const timelineProfilerEnabledStateName = "timelineProfilerEnabled";
+static const char* const resourceTrackingEnabledStateName = "resourceTrackingEnabled";
+static const char* const monitoringXHRStateName = "monitoringXHREnabled";
+
+static const char* const inspectorAttachedHeightName = "inspectorAttachedHeight";
+
const char* const InspectorController::ElementsPanel = "elements";
const char* const InspectorController::ConsolePanel = "console";
const char* const InspectorController::ScriptsPanel = "scripts";
const char* const InspectorController::ProfilesPanel = "profiles";
-static const char* const monitoringXHRSettingName = "xhrMonitor";
static int connectedFrontendCount = 0;
-const String& InspectorController::frontendSettingsSettingName()
-{
- DEFINE_STATIC_LOCAL(String, settingName, ("frontendSettings"));
- return settingName;
-}
-
const String& InspectorController::inspectorStartsAttachedSettingName()
{
DEFINE_STATIC_LOCAL(String, settingName, ("inspectorStartsAttached"));
@@ -240,7 +244,7 @@ void InspectorController::setSetting(const String& key, const String& value)
void InspectorController::saveApplicationSettings(const String& settings)
{
- setSetting(InspectorController::frontendSettingsSettingName(), settings);
+ setSetting(frontendSettingsSettingName, settings);
}
void InspectorController::saveSessionSettings(const String& settingsJSON)
@@ -248,10 +252,46 @@ void InspectorController::saveSessionSettings(const String& settingsJSON)
m_sessionSettings = InspectorValue::parseJSON(settingsJSON);
}
+void InspectorController::getInspectorState(RefPtr<InspectorObject>* state)
+{
+ (*state)->setBoolean(monitoringXHRStateName, m_monitoringXHR);
+ (*state)->setBoolean(resourceTrackingEnabledStateName, m_resourceTrackingEnabled);
+}
+
+void InspectorController::updateInspectorStateCookie()
+{
+ RefPtr<InspectorObject> state = InspectorObject::create();
+ state->setBoolean(monitoringXHRStateName, m_monitoringXHR);
+ state->setBoolean(resourceTrackingEnabledStateName, m_resourceTrackingEnabled);
+ state->setBoolean(timelineProfilerEnabledStateName, m_timelineAgent);
+ m_client->updateInspectorStateCookie(state->toJSONString());
+}
+
+void InspectorController::restoreInspectorStateFromCookie(const String& inspectorStateString)
+{
+ RefPtr<InspectorValue> inspectorStateValue = InspectorValue::parseJSON(inspectorStateString);
+ if (!inspectorStateValue)
+ return;
+
+ RefPtr<InspectorObject> inspectorState = inspectorStateValue->asObject();
+ if (!inspectorState)
+ return;
+
+ inspectorState->getBoolean(monitoringXHRStateName, &m_monitoringXHR);
+ inspectorState->getBoolean(resourceTrackingEnabledStateName, &m_resourceTrackingEnabled);
+
+ bool timelineProfilerEnabled = false;
+ inspectorState->getBoolean(timelineProfilerEnabledStateName, &timelineProfilerEnabled);
+ if (timelineProfilerEnabled)
+ startTimelineProfiler();
+ else
+ stopTimelineProfiler();
+}
+
void InspectorController::getSettings(RefPtr<InspectorObject>* settings)
{
*settings = InspectorObject::create();
- (*settings)->setString("application", setting(frontendSettingsSettingName()));
+ (*settings)->setString("application", setting(frontendSettingsSettingName));
(*settings)->setString("session", m_sessionSettings->toJSONString());
}
@@ -460,18 +500,14 @@ void InspectorController::setSearchingForNode(bool enabled)
}
}
-void InspectorController::setMonitoringXHR(bool enabled)
+void InspectorController::setMonitoringXHREnabled(bool enabled, bool* newState)
{
+ *newState = enabled;
if (m_monitoringXHR == enabled)
return;
m_monitoringXHR = enabled;
setSetting(monitoringXHRSettingName, enabled ? "true" : "false");
- if (m_frontend) {
- if (enabled)
- m_frontend->monitoringXHRWasEnabled();
- else
- m_frontend->monitoringXHRWasDisabled();
- }
+ updateInspectorStateCookie();
}
void InspectorController::connectFrontend()
@@ -500,6 +536,13 @@ void InspectorController::connectFrontend()
connectedFrontendCount++;
}
+void InspectorController::reuseFrontend()
+{
+ connectFrontend();
+ restoreDebugger();
+ restoreProfiler();
+}
+
void InspectorController::show()
{
if (!enabled())
@@ -604,18 +647,12 @@ void InspectorController::populateScriptObjects()
if (m_showAfterVisible == lastActivePanel)
m_showAfterVisible = setting(lastActivePanel);
- if (m_nodeToFocus)
- focusNode();
- showPanel(m_showAfterVisible);
- if (m_resourceTrackingEnabled)
- m_frontend->resourceTrackingWasEnabled();
+ showPanel(m_showAfterVisible);
if (m_searchingForNode)
m_frontend->searchingForNodeWasEnabled();
- if (m_monitoringXHR)
- m_frontend->monitoringXHRWasEnabled();
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (m_profilerAgent->enabled())
@@ -628,6 +665,9 @@ void InspectorController::populateScriptObjects()
m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
+ if (m_nodeToFocus)
+ focusNode();
+
if (m_expiredConsoleMessageCount)
m_frontend->updateConsoleMessageExpiredCount(m_expiredConsoleMessageCount);
unsigned messageCount = m_consoleMessages.size();
@@ -661,17 +701,31 @@ void InspectorController::populateScriptObjects()
m_frontend->evaluateForTestInFrontend((*it).first, (*it).second);
m_pendingEvaluateTestCommands.clear();
+ restoreDebugger();
+ restoreProfiler();
+}
+
+void InspectorController::restoreDebugger()
+{
+ ASSERT(m_frontend);
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (InspectorDebuggerAgent::isDebuggerAlwaysEnabled())
enableDebuggerFromFrontend(false);
else {
- String debuggerEnabled = setting(debuggerEnabledSettingName);
+ String debuggerEnabled = setting(debuggerAlwaysEnabledSettingName);
if (debuggerEnabled == "true" || m_attachDebuggerWhenShown)
enableDebugger();
}
+#endif
+}
+
+void InspectorController::restoreProfiler()
+{
+ ASSERT(m_frontend);
+#if ENABLE(JAVASCRIPT_DEBUGGER)
m_profilerAgent->setFrontend(m_frontend.get());
if (!ScriptProfiler::isProfilerAlwaysEnabled()) {
- String profilerEnabledSetting = setting(profilerEnabledSettingName);
+ String profilerEnabledSetting = setting(profilerAlwaysEnabledSettingName);
if (profilerEnabledSetting == "true")
enableProfiler();
}
@@ -798,6 +852,8 @@ void InspectorController::addResource(InspectorResource* resource)
m_knownResources.add(resource->requestURL());
Frame* frame = resource->frame();
+ if (!frame)
+ return;
ResourcesMap* resourceMap = m_frameResources.get(frame);
if (resourceMap)
resourceMap->set(resource->identifier(), resource);
@@ -816,6 +872,8 @@ void InspectorController::removeResource(InspectorResource* resource)
m_knownResources.remove(requestURL);
Frame* frame = resource->frame();
+ if (!frame)
+ return;
ResourcesMap* resourceMap = m_frameResources.get(frame);
if (!resourceMap) {
ASSERT_NOT_REACHED();
@@ -957,7 +1015,7 @@ void InspectorController::willSendRequest(unsigned long identifier, ResourceRequ
// Redirect may have empty URL and we'd like to not crash with invalid HashMap entry.
// See http/tests/misc/will-send-request-returns-null-on-redirect.html
if (!request.url().isEmpty()) {
- resource->endTiming();
+ resource->endTiming(0);
resource->updateResponse(redirectResponse);
// We always store last redirect by the original id key. Rest of the redirects are stored within the last one.
@@ -980,6 +1038,15 @@ void InspectorController::willSendRequest(unsigned long identifier, ResourceRequ
resource->updateScriptObject(m_frontend.get());
}
+void InspectorController::markResourceAsCached(unsigned long identifier)
+{
+ if (!enabled())
+ return;
+
+ if (RefPtr<InspectorResource> resource = getTrackedResource(identifier))
+ resource->markAsCached();
+}
+
void InspectorController::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
{
if (!enabled())
@@ -1014,7 +1081,7 @@ void InspectorController::didReceiveContentLength(unsigned long identifier, int
resource->updateScriptObject(m_frontend.get());
}
-void InspectorController::didFinishLoading(unsigned long identifier)
+void InspectorController::didFinishLoading(unsigned long identifier, double finishTime)
{
if (!enabled())
return;
@@ -1026,7 +1093,7 @@ void InspectorController::didFinishLoading(unsigned long identifier)
if (!resource)
return;
- resource->endTiming();
+ resource->endTiming(finishTime);
// No need to mute this event for main resource since it happens after did commit load.
if (m_frontend)
@@ -1051,7 +1118,7 @@ void InspectorController::didFailLoading(unsigned long identifier, const Resourc
return;
resource->markFailed();
- resource->endTiming();
+ resource->endTiming(0);
// No need to mute this event for main resource since it happens after did commit load.
if (m_frontend)
@@ -1094,40 +1161,33 @@ void InspectorController::scriptImported(unsigned long identifier, const String&
resource->updateScriptObject(m_frontend.get());
}
-void InspectorController::enableResourceTracking(bool always, bool reload)
+void InspectorController::setResourceTrackingEnabled(bool enable)
{
if (!enabled())
return;
- if (always)
- setSetting(resourceTrackingEnabledSettingName, "true");
-
- if (m_resourceTrackingEnabled)
- return;
-
ASSERT(m_inspectedPage);
- m_resourceTrackingEnabled = true;
- if (m_frontend)
- m_frontend->resourceTrackingWasEnabled();
- m_client->resourceTrackingWasEnabled();
-
- if (reload)
- m_inspectedPage->mainFrame()->redirectScheduler()->scheduleRefresh(true);
+ m_resourceTrackingEnabled = enable;
+ updateInspectorStateCookie();
}
-void InspectorController::disableResourceTracking(bool always)
+void InspectorController::setResourceTrackingEnabled(bool enable, bool always, bool* newState)
{
- if (!enabled())
- return;
+ *newState = enable;
if (always)
- setSetting(resourceTrackingEnabledSettingName, "false");
+ setSetting(resourceTrackingAlwaysEnabledSettingName, enable ? "true" : "false");
+
+ if (m_resourceTrackingEnabled == enable)
+ return;
ASSERT(m_inspectedPage);
- m_resourceTrackingEnabled = false;
- if (m_frontend)
- m_frontend->resourceTrackingWasDisabled();
- m_client->resourceTrackingWasDisabled();
+ m_resourceTrackingEnabled = enable;
+
+ if (enable)
+ m_inspectedPage->mainFrame()->redirectScheduler()->scheduleRefresh(true);
+
+ updateInspectorStateCookie();
}
void InspectorController::ensureSettingsLoaded()
@@ -1136,14 +1196,15 @@ void InspectorController::ensureSettingsLoaded()
return;
m_settingsLoaded = true;
- String resourceTracking = setting(resourceTrackingEnabledSettingName);
- if (resourceTracking == "true")
+ String resourceTrackingAlwaysEnabled = setting(resourceTrackingAlwaysEnabledSettingName);
+ if (resourceTrackingAlwaysEnabled == "true")
m_resourceTrackingEnabled = true;
- m_client->resourceTrackingWasEnabled();
- String monitoringXHR = setting(monitoringXHRSettingName);
- if (monitoringXHR == "true")
+ String monitoringXHRAlwaysEnabled = setting(monitoringXHRSettingName);
+ if (monitoringXHRAlwaysEnabled == "true")
m_monitoringXHR = true;
+
+ updateInspectorStateCookie();
}
void InspectorController::startTimelineProfiler()
@@ -1157,7 +1218,8 @@ void InspectorController::startTimelineProfiler()
m_timelineAgent = new InspectorTimelineAgent(m_frontend.get());
if (m_frontend)
m_frontend->timelineProfilerWasStarted();
- m_client->timelineProfilerWasStarted();
+
+ updateInspectorStateCookie();
}
void InspectorController::stopTimelineProfiler()
@@ -1171,7 +1233,8 @@ void InspectorController::stopTimelineProfiler()
m_timelineAgent = 0;
if (m_frontend)
m_frontend->timelineProfilerWasStopped();
- m_client->timelineProfilerWasStopped();
+
+ updateInspectorStateCookie();
}
#if ENABLE(WORKERS)
@@ -1442,6 +1505,56 @@ InspectorDOMStorageResource* InspectorController::getDOMStorageResourceForId(lon
}
#endif
+#if ENABLE(WEB_SOCKETS)
+void InspectorController::didCreateWebSocket(unsigned long identifier, const KURL& requestURL, const KURL& documentURL)
+{
+ if (!enabled())
+ return;
+ ASSERT(m_inspectedPage);
+
+ RefPtr<InspectorResource> resource = InspectorResource::createWebSocket(identifier, requestURL, documentURL);
+ addResource(resource.get());
+
+ if (m_frontend)
+ resource->updateScriptObject(m_frontend.get());
+}
+
+void InspectorController::willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest& request)
+{
+ RefPtr<InspectorResource> resource = getTrackedResource(identifier);
+ if (!resource)
+ return;
+ resource->startTiming();
+ resource->updateWebSocketRequest(request);
+ if (m_frontend)
+ resource->updateScriptObject(m_frontend.get());
+}
+
+void InspectorController::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse& response)
+{
+ RefPtr<InspectorResource> resource = getTrackedResource(identifier);
+ if (!resource)
+ return;
+ // Calling resource->markResponseReceivedTime() here makes resources bar chart confusing, because
+ // we cannot apply the "latency + download" model of regular resources to WebSocket connections.
+ // FIXME: Design a new UI for bar charts of WebSocket resources, and record timing here.
+ resource->updateWebSocketResponse(response);
+ if (m_frontend)
+ resource->updateScriptObject(m_frontend.get());
+}
+
+void InspectorController::didCloseWebSocket(unsigned long identifier)
+{
+ RefPtr<InspectorResource> resource = getTrackedResource(identifier);
+ if (!resource)
+ return;
+
+ resource->endTiming(0);
+ if (m_frontend)
+ resource->updateScriptObject(m_frontend.get());
+}
+#endif // ENABLE(WEB_SOCKETS)
+
#if ENABLE(JAVASCRIPT_DEBUGGER)
void InspectorController::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
{
@@ -1493,14 +1606,14 @@ bool InspectorController::profilerEnabled() const
void InspectorController::enableProfiler(bool always, bool skipRecompile)
{
if (always)
- setSetting(profilerEnabledSettingName, "true");
+ setSetting(profilerAlwaysEnabledSettingName, "true");
m_profilerAgent->enable(skipRecompile);
}
void InspectorController::disableProfiler(bool always)
{
if (always)
- setSetting(profilerEnabledSettingName, "false");
+ setSetting(profilerAlwaysEnabledSettingName, "false");
m_profilerAgent->disable();
}
#endif
@@ -1510,7 +1623,7 @@ void InspectorController::enableDebuggerFromFrontend(bool always)
{
ASSERT(!debuggerEnabled());
if (always)
- setSetting(debuggerEnabledSettingName, "true");
+ setSetting(debuggerAlwaysEnabledSettingName, "true");
ASSERT(m_inspectedPage);
@@ -1541,7 +1654,7 @@ void InspectorController::disableDebugger(bool always)
return;
if (always)
- setSetting(debuggerEnabledSettingName, "false");
+ setSetting(debuggerAlwaysEnabledSettingName, "false");
ASSERT(m_inspectedPage);
@@ -1558,7 +1671,6 @@ void InspectorController::resume()
if (m_debuggerAgent)
m_debuggerAgent->resume();
}
-// JavaScriptDebugListener functions
#endif
@@ -1585,6 +1697,8 @@ void InspectorController::didEvaluateForTestInFrontend(long callId, const String
String InspectorController::breakpointsSettingKey()
{
DEFINE_STATIC_LOCAL(String, keyPrefix, ("breakpoints:"));
+ if (!m_mainResource)
+ return "";
return keyPrefix + InspectorDebuggerAgent::md5Base16(m_mainResource->requestURL());
}
@@ -1744,6 +1858,84 @@ void InspectorController::drawNodeHighlight(GraphicsContext& context) const
drawHighlightForLineBoxesOrSVGRenderer(context, lineBoxQuads);
}
+
+ // Draw node title if necessary.
+
+ if (!m_highlightedNode->isElementNode())
+ return;
+
+ WebCore::Settings* settings = containingFrame->settings();
+ drawElementTitle(context, boundingBox, overlayRect, settings);
+}
+
+void InspectorController::drawElementTitle(GraphicsContext& context, const IntRect& boundingBox, const FloatRect& overlayRect, WebCore::Settings* settings) const
+{
+ static const int rectInflatePx = 4;
+ static const int fontHeightPx = 12;
+ static const int borderWidthPx = 1;
+ static const Color tooltipBackgroundColor(255, 255, 194, 255);
+ static const Color tooltipBorderColor(Color::black);
+ static const Color tooltipFontColor(Color::black);
+
+ Element* element = static_cast<Element*>(m_highlightedNode.get());
+ bool isXHTML = element->document()->isXHTMLDocument();
+ String nodeTitle = isXHTML ? element->nodeName() : element->nodeName().lower();
+ const AtomicString& idValue = element->getIdAttribute();
+ if (!idValue.isNull() && !idValue.isEmpty()) {
+ nodeTitle += "#";
+ nodeTitle += idValue;
+ }
+ if (element->hasClass() && element->isStyledElement()) {
+ const SpaceSplitString& classNamesString = static_cast<StyledElement*>(element)->classNames();
+ size_t classNameCount = classNamesString.size();
+ if (classNameCount) {
+ HashSet<AtomicString> usedClassNames;
+ for (size_t i = 0; i < classNameCount; ++i) {
+ const AtomicString& className = classNamesString[i];
+ if (usedClassNames.contains(className))
+ continue;
+ usedClassNames.add(className);
+ nodeTitle += ".";
+ nodeTitle += className;
+ }
+ }
+ }
+ nodeTitle += " [";
+ nodeTitle += String::number(boundingBox.width());
+ nodeTitle.append(static_cast<UChar>(0x00D7)); // &times;
+ nodeTitle += String::number(boundingBox.height());
+ nodeTitle += "]";
+
+ FontDescription desc;
+ FontFamily family;
+ family.setFamily(settings->fixedFontFamily());
+ desc.setFamily(family);
+ desc.setComputedSize(fontHeightPx);
+ Font font = Font(desc, 0, 0);
+ font.update(0);
+
+ TextRun nodeTitleRun(nodeTitle);
+ IntPoint titleBasePoint = boundingBox.bottomLeft();
+ titleBasePoint.move(rectInflatePx, rectInflatePx);
+ IntRect titleRect = enclosingIntRect(font.selectionRectForText(nodeTitleRun, titleBasePoint, fontHeightPx));
+ titleRect.inflate(rectInflatePx);
+
+ // The initial offsets needed to compensate for a 1px-thick border stroke (which is not a part of the rectangle).
+ int dx = -borderWidthPx;
+ int dy = borderWidthPx;
+ if (titleRect.right() > overlayRect.right())
+ dx += overlayRect.right() - titleRect.right();
+ if (titleRect.x() + dx < overlayRect.x())
+ dx = overlayRect.x() - titleRect.x();
+ if (titleRect.bottom() > overlayRect.bottom())
+ dy += overlayRect.bottom() - titleRect.bottom() - borderWidthPx;
+ titleRect.move(dx, dy);
+ context.setStrokeColor(tooltipBorderColor, DeviceColorSpace);
+ context.setStrokeThickness(borderWidthPx);
+ context.setFillColor(tooltipBackgroundColor, DeviceColorSpace);
+ context.drawRect(titleRect);
+ context.setFillColor(tooltipFontColor, DeviceColorSpace);
+ context.drawText(font, nodeTitleRun, IntPoint(titleRect.x() + rectInflatePx, titleRect.y() + font.height()));
}
void InspectorController::openInInspectedWindow(const String& url)
@@ -1840,6 +2032,49 @@ void InspectorController::getResourceContent(unsigned long identifier, String* c
*content = resource ? resource->sourceString() : String();
}
+bool InspectorController::resourceContentForURL(const KURL& url, Document* frameDocument, String* result)
+{
+ if (!frameDocument)
+ return false;
+
+ String textEncodingName;
+ RefPtr<SharedBuffer> buffer;
+ if (equalIgnoringFragmentIdentifier(url, frameDocument->frame()->loader()->documentLoader()->requestURL())) {
+ textEncodingName = frameDocument->inputEncoding();
+ buffer = frameDocument->frame()->loader()->provisionalDocumentLoader()->mainResourceData();
+ } else {
+ const String& urlString = url.string();
+ CachedResource* cachedResource = frameDocument->cachedResourceLoader()->cachedResource(urlString);
+ if (!cachedResource)
+ cachedResource = cache()->resourceForURL(urlString);
+
+ ASSERT(cachedResource); // FIXME(apavlov): This might be too aggressive.
+
+ bool isUnpurgeable = true;
+ if (cachedResource->isPurgeable()) {
+ // If the resource is purgeable then make it unpurgeable to get
+ // its data. This might fail, in which case we return an
+ // empty String.
+ if (!cachedResource->makePurgeable(false))
+ isUnpurgeable = false;
+ }
+ if (isUnpurgeable) {
+ textEncodingName = cachedResource->encoding();
+ buffer = cachedResource->data();
+ }
+ }
+
+ if (buffer) {
+ TextEncoding encoding(textEncodingName);
+ if (!encoding.isValid())
+ encoding = WindowsLatin1Encoding();
+ *result = encoding.decode(buffer->data(), buffer->size());
+ return true;
+ }
+
+ return false;
+}
+
void InspectorController::reloadPage()
{
m_inspectedPage->mainFrame()->redirectScheduler()->scheduleRefresh(true);
diff --git a/WebCore/inspector/InspectorController.h b/WebCore/inspector/InspectorController.h
index 40099c6..6752044 100644
--- a/WebCore/inspector/InspectorController.h
+++ b/WebCore/inspector/InspectorController.h
@@ -50,6 +50,7 @@ class Database;
class Document;
class DocumentLoader;
class Element;
+class FloatRect;
class GraphicsContext;
class HitTestResult;
class InjectedScript;
@@ -72,6 +73,7 @@ class InspectorStorageAgent;
class InspectorTimelineAgent;
class InspectorValue;
class InspectorWorkerResource;
+class IntRect;
class KURL;
class Node;
class Page;
@@ -89,6 +91,11 @@ class StorageArea;
class InspectorApplicationCacheAgent;
#endif
+#if ENABLE(WEB_SOCKETS)
+class WebSocketHandshakeRequest;
+class WebSocketHandshakeResponse;
+#endif
+
class InspectorController : public Noncopyable {
public:
typedef HashMap<unsigned long, RefPtr<InspectorResource> > ResourcesMap;
@@ -122,6 +129,8 @@ public:
void saveSessionSettings(const String&);
void getSettings(RefPtr<InspectorObject>*);
+ void restoreInspectorStateFromCookie(const String& inspectorState);
+
void inspect(Node*);
void highlight(Node*);
void hideHighlight();
@@ -136,6 +145,7 @@ public:
// transport via InspectorClient. After migration, webInspector parameter should
// be removed.
void connectFrontend();
+ void reuseFrontend();
void disconnectFrontend();
void addMessageToConsole(MessageSource, MessageType, MessageLevel, ScriptCallStack*, const String& message);
@@ -158,15 +168,16 @@ public:
void identifierForInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&);
void willSendRequest(unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse);
+ void markResourceAsCached(unsigned long identifier);
void didReceiveResponse(unsigned long identifier, const ResourceResponse&);
void didReceiveContentLength(unsigned long identifier, int lengthReceived);
- void didFinishLoading(unsigned long identifier);
+ void didFinishLoading(unsigned long identifier, double finishTime);
void didFailLoading(unsigned long identifier, const ResourceError&);
void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString, const String& url, const String& sendURL, unsigned sendLineNumber);
void scriptImported(unsigned long identifier, const String& sourceString);
- void enableResourceTracking(bool always = false, bool reload = true);
- void disableResourceTracking(bool always = false);
+ void setResourceTrackingEnabled(bool enabled);
+ void setResourceTrackingEnabled(bool enabled, bool always, bool* newState);
bool resourceTrackingEnabled() const { return m_resourceTrackingEnabled; }
void ensureSettingsLoaded();
@@ -209,13 +220,21 @@ public:
void setDOMStorageItem(long storageId, const String& key, const String& value, bool* success);
void removeDOMStorageItem(long storageId, const String& key, bool* success);
#endif
+#if ENABLE(WEB_SOCKETS)
+ void didCreateWebSocket(unsigned long identifier, const KURL& requestURL, const KURL& documentURL);
+ void willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest&);
+ void didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse&);
+ void didCloseWebSocket(unsigned long identifier);
+#endif
const ResourcesMap& resources() const { return m_resources; }
InspectorResource* resourceForURL(const String& url);
+ bool resourceContentForURL(const KURL& url, Document* loaderDocument, String* result);
bool hasFrontend() const { return m_frontend; }
void drawNodeHighlight(GraphicsContext&) const;
void openInInspectedWindow(const String& url);
+ void drawElementTitle(GraphicsContext&, const IntRect& boundingBox, const FloatRect& overlayRect, WebCore::Settings*) const;
void count(const String& title, unsigned lineNumber, const String& sourceID);
@@ -258,13 +277,16 @@ public:
static const String& inspectorStartsAttachedSettingName();
private:
- static const String& frontendSettingsSettingName();
+ void updateInspectorStateCookie();
+ void getInspectorState(RefPtr<InspectorObject>* state);
friend class InspectorBackend;
friend class InspectorBackendDispatcher;
friend class InjectedScriptHost;
void populateScriptObjects();
+ void restoreDebugger();
+ void restoreProfiler();
void unbindAllResources();
// Following are used from InspectorBackend and internally.
@@ -272,9 +294,7 @@ private:
void enableSearchingForNode() { setSearchingForNode(true); }
void disableSearchingForNode() { setSearchingForNode(false); }
- void setMonitoringXHR(bool enabled);
- void enableMonitoringXHR() { setMonitoringXHR(true); }
- void disableMonitoringXHR() { setMonitoringXHR(false); }
+ void setMonitoringXHREnabled(bool enabled, bool* newState);
void storeLastActivePanel(const String& panelName);
InspectorDOMAgent* domAgent() { return m_domAgent.get(); }
void releaseFrontendLifetimeAgents();
diff --git a/WebCore/inspector/InspectorDOMAgent.cpp b/WebCore/inspector/InspectorDOMAgent.cpp
index 23c22aa..f1df5b0 100644
--- a/WebCore/inspector/InspectorDOMAgent.cpp
+++ b/WebCore/inspector/InspectorDOMAgent.cpp
@@ -37,6 +37,7 @@
#include "CSSComputedStyleDeclaration.h"
#include "CSSMutableStyleDeclaration.h"
#include "CSSPropertyNames.h"
+#include "CSSPropertySourceData.h"
#include "CSSRule.h"
#include "CSSRuleList.h"
#include "CSSStyleRule.h"
@@ -707,7 +708,7 @@ void InspectorDOMAgent::performSearch(const String& whitespaceTrimmedQuery, bool
m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
continue;
}
-
+
m_pendingMatchJobs.append(new MatchExactIdJob(document, whitespaceTrimmedQuery));
m_pendingMatchJobs.append(new MatchExactClassNamesJob(document, whitespaceTrimmedQuery));
m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
@@ -776,38 +777,70 @@ void InspectorDOMAgent::removeDOMBreakpoint(long nodeId, long type)
bool InspectorDOMAgent::shouldBreakOnNodeInsertion(Node*, Node* parent, PassRefPtr<InspectorValue>* details)
{
- if (!hasBreakpoint(parent, SubtreeModified))
- return false;
- RefPtr<InspectorObject> detailsObject = InspectorObject::create();
- detailsObject->setObject("breakpoint", createBreakpoint(parent, SubtreeModified));
- *details = detailsObject;
- return true;
+ if (hasBreakpoint(parent, SubtreeModified)) {
+ *details = descriptionForDOMEvent(parent, SubtreeModified, true);
+ return true;
+ }
+ return false;
}
bool InspectorDOMAgent::shouldBreakOnNodeRemoval(Node* node, PassRefPtr<InspectorValue>* details)
{
- bool hasNodeRemovedBreakpoint = hasBreakpoint(node, NodeRemoved);
- bool hasAnyBreakpoint = hasNodeRemovedBreakpoint || hasBreakpoint(innerParentNode(node), SubtreeModified);
- if (!hasAnyBreakpoint)
- return false;
-
- RefPtr<InspectorObject> detailsObject = InspectorObject::create();
- if (hasNodeRemovedBreakpoint)
- detailsObject->setObject("breakpoint", createBreakpoint(node, NodeRemoved));
- else
- detailsObject->setObject("breakpoint", createBreakpoint(innerParentNode(node), SubtreeModified));
- *details = detailsObject;
- return true;
+ if (hasBreakpoint(node, NodeRemoved)) {
+ *details = descriptionForDOMEvent(node, NodeRemoved, false);
+ return true;
+ }
+ if (hasBreakpoint(innerParentNode(node), SubtreeModified)) {
+ *details = descriptionForDOMEvent(node, SubtreeModified, false);
+ return true;
+ }
+ return false;
}
bool InspectorDOMAgent::shouldBreakOnAttributeModification(Element* element, PassRefPtr<InspectorValue>* details)
{
- if (!hasBreakpoint(element, AttributeModified))
- return false;
- RefPtr<InspectorObject> detailsObject = InspectorObject::create();
- detailsObject->setObject("breakpoint", createBreakpoint(element, AttributeModified));
- *details = detailsObject;
- return true;
+ if (hasBreakpoint(element, AttributeModified)) {
+ *details = descriptionForDOMEvent(element, AttributeModified, false);
+ return true;
+ }
+ return false;
+}
+
+PassRefPtr<InspectorValue> InspectorDOMAgent::descriptionForDOMEvent(Node* target, long breakpointType, bool insertion)
+{
+ ASSERT(hasBreakpoint(target, breakpointType));
+
+ RefPtr<InspectorObject> description = InspectorObject::create();
+ 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.
+ long targetNodeId = pushNodePathToFrontend(target);
+ ASSERT(targetNodeId);
+ description->setNumber("targetNodeId", targetNodeId);
+
+ // Find breakpoint owner node.
+ if (!insertion)
+ breakpointOwner = innerParentNode(target);
+ ASSERT(breakpointOwner);
+ while (!(m_breakpoints.get(breakpointOwner) & (1 << breakpointType))) {
+ breakpointOwner = innerParentNode(breakpointOwner);
+ ASSERT(breakpointOwner);
+ }
+
+ if (breakpointType == SubtreeModified)
+ description->setBoolean("insertion", insertion);
+ }
+
+ long breakpointOwnerNodeId = m_documentNodeToIdMap.get(breakpointOwner);
+ ASSERT(breakpointOwnerNodeId);
+
+ RefPtr<InspectorObject> breakpoint = InspectorObject::create();
+ breakpoint->setNumber("nodeId", breakpointOwnerNodeId);
+ breakpoint->setNumber("type", breakpointType);
+ description->setObject("breakpoint", breakpoint);
+
+ return description;
}
String InspectorDOMAgent::documentURLString(Document* document) const
@@ -1087,23 +1120,6 @@ void InspectorDOMAgent::didModifyDOMAttr(Element* element)
m_frontend->attributesUpdated(id, buildArrayForElementAttributes(element));
}
-PassRefPtr<InspectorObject> InspectorDOMAgent::createBreakpoint(Node* node, long type)
-{
- RefPtr<InspectorObject> breakpoint = InspectorObject::create();
-
- // Find breakpoint owner.
- while (!(m_breakpoints.get(node) & (1 << type))) {
- node = innerParentNode(node);
- ASSERT(node);
- }
- long nodeId = m_documentNodeToIdMap.get(node);
- ASSERT(nodeId);
-
- breakpoint->setNumber("nodeId", nodeId);
- breakpoint->setNumber("type", type);
- return breakpoint.release();
-}
-
bool InspectorDOMAgent::hasBreakpoint(Node* node, long type)
{
uint32_t rootBit = 1 << type;
@@ -1148,7 +1164,7 @@ void InspectorDOMAgent::getStyles(long nodeId, bool authorOnly, RefPtr<Inspector
result->setObject("computedStyle", buildObjectForStyle(computedStyleInfo.get(), false));
CSSStyleSelector* selector = element->ownerDocument()->styleSelector();
- RefPtr<CSSRuleList> matchedRules = selector->styleRulesForElement(element, authorOnly);
+ RefPtr<CSSRuleList> matchedRules = selector->styleRulesForElement(element, authorOnly, true);
result->setArray("matchedCSSRules", buildArrayForCSSRules(node->ownerDocument(), matchedRules.get()));
result->setObject("styleAttributes", buildObjectForAttributeStyles(element));
@@ -1163,7 +1179,7 @@ void InspectorDOMAgent::getStyles(long nodeId, bool authorOnly, RefPtr<Inspector
parentStyle->setObject("inlineStyle", buildObjectForStyle(parentElement->style(), true));
CSSStyleSelector* parentSelector = parentElement->ownerDocument()->styleSelector();
- RefPtr<CSSRuleList> parentMatchedRules = parentSelector->styleRulesForElement(parentElement, authorOnly);
+ RefPtr<CSSRuleList> parentMatchedRules = parentSelector->styleRulesForElement(parentElement, authorOnly, true);
parentStyle->setArray("matchedCSSRules", buildArrayForCSSRules(parentElement->ownerDocument(), parentMatchedRules.get()));
parentElement = parentElement->parentElement();
@@ -1191,26 +1207,34 @@ void InspectorDOMAgent::getStyleSheet(long styleSheetId, RefPtr<InspectorObject>
*styleSheetObject = buildObjectForStyleSheet(styleSheet->document(), styleSheet);
}
-void InspectorDOMAgent::getRuleRanges(long styleSheetId, RefPtr<InspectorValue>* ruleRange)
+void InspectorDOMAgent::getStyleSourceData(long styleId, RefPtr<InspectorObject>* dataObject)
{
- CSSStyleSheet* styleSheet = cssStore()->styleSheetForId(styleSheetId);
- if (styleSheet && styleSheet->document()) {
- HashMap<long, SourceRange> ruleRanges = cssStore()->getRuleRanges(styleSheet);
- if (!ruleRanges.size())
- return;
- RefPtr<InspectorObject> result = InspectorObject::create();
- for (HashMap<long, SourceRange>::iterator it = ruleRanges.begin(); it != ruleRanges.end(); ++it) {
- if (it->second.second) {
- RefPtr<InspectorObject> ruleRange = InspectorObject::create();
- result->setObject(String::number(it->first).utf8().data(), ruleRange);
- RefPtr<InspectorObject> bodyRange = InspectorObject::create();
- ruleRange->setObject("bodyRange", bodyRange);
- bodyRange->setNumber("start", it->second.first);
- bodyRange->setNumber("end", it->second.second);
- }
- }
- *ruleRange = result.release();
+ CSSStyleDeclaration* style = cssStore()->styleForId(styleId);
+ if (!style)
+ return;
+ RefPtr<CSSStyleSourceData> sourceData = CSSStyleSourceData::create();
+ bool success = cssStore()->getStyleSourceData(style, &sourceData);
+ if (!success)
+ return;
+ RefPtr<InspectorObject> result = InspectorObject::create();
+ RefPtr<InspectorObject> bodyRange = InspectorObject::create();
+ result->setObject("bodyRange", bodyRange);
+ bodyRange->setNumber("start", sourceData->styleBodyRange.start);
+ bodyRange->setNumber("end", sourceData->styleBodyRange.end);
+ RefPtr<InspectorArray> propertyRanges = InspectorArray::create();
+ result->setArray("propertyData", propertyRanges);
+ Vector<CSSPropertySourceData>& propertyData = sourceData->propertyData;
+ for (Vector<CSSPropertySourceData>::iterator it = propertyData.begin(); it != propertyData.end(); ++it) {
+ RefPtr<InspectorObject> propertyRange = InspectorObject::create();
+ propertyRange->setString("name", it->name);
+ propertyRange->setString("value", it->value);
+ propertyRange->setBoolean("important", it->important);
+ propertyRange->setBoolean("parsed", it->parsedOk);
+ propertyRange->setNumber("start", it->range.start);
+ propertyRange->setNumber("end", it->range.end);
+ propertyRanges->pushObject(propertyRange);
}
+ *dataObject = result.release();
}
void InspectorDOMAgent::getInlineStyle(long nodeId, RefPtr<InspectorValue>* style)
@@ -1267,7 +1291,7 @@ PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForPseudoElements(Elemen
RefPtr<RenderStyle> renderStyle = element->styleForRenderer();
for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
- RefPtr<CSSRuleList> matchedRules = selector->pseudoStyleRulesForElement(element, pseudoId, authorOnly);
+ RefPtr<CSSRuleList> matchedRules = selector->pseudoStyleRulesForElement(element, pseudoId, authorOnly, true);
if (matchedRules && matchedRules->length()) {
RefPtr<InspectorObject> pseudoStyles = InspectorObject::create();
pseudoStyles->setNumber("pseudoId", static_cast<int>(pseudoId));
@@ -1469,7 +1493,7 @@ PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForStyle(CSSStyleDecla
if (bind) {
long styleId = cssStore()->bindStyle(style);
result->setNumber("id", styleId);
- CSSStyleSheet* parentStyleSheet = getParentStyleSheet(style);
+ CSSStyleSheet* parentStyleSheet = InspectorCSSStore::getParentStyleSheet(style);
if (parentStyleSheet)
result->setNumber("parentStyleSheetId", cssStore()->bindStyleSheet(parentStyleSheet));
@@ -1681,20 +1705,6 @@ PassRefPtr<InspectorArray> InspectorDOMAgent::toArray(const Vector<String>& data
return result.release();
}
-CSSStyleSheet* InspectorDOMAgent::getParentStyleSheet(CSSStyleDeclaration* style)
-{
- CSSStyleSheet* parentStyleSheet = style->parentRule() ? style->parentRule()->parentStyleSheet() : 0;
- if (!parentStyleSheet) {
- StyleBase* parent = style->parent();
- if (parent && parent->isCSSStyleSheet()) {
- parentStyleSheet = static_cast<CSSStyleSheet*>(parent);
- if (!parentStyleSheet->length())
- return 0;
- }
- }
- return parentStyleSheet;
-}
-
void InspectorDOMAgent::onMatchJobsTimer(Timer<InspectorDOMAgent>*)
{
if (!m_pendingMatchJobs.size()) {
diff --git a/WebCore/inspector/InspectorDOMAgent.h b/WebCore/inspector/InspectorDOMAgent.h
index 9751e8e..7d86997 100644
--- a/WebCore/inspector/InspectorDOMAgent.h
+++ b/WebCore/inspector/InspectorDOMAgent.h
@@ -123,7 +123,7 @@ namespace WebCore {
void getInlineStyle(long nodeId, RefPtr<InspectorValue>* styles);
void getComputedStyle(long nodeId, RefPtr<InspectorValue>* styles);
void getStyleSheet(long styleSheetId, RefPtr<InspectorObject>* styleSheetObject);
- void getRuleRanges(long styleSheetId, RefPtr<InspectorValue>* ruleRange);
+ void getStyleSourceData(long styleId, RefPtr<InspectorObject>* dataObject);
void applyStyleText(long styleId, const String& styleText, const String& propertyName, bool* success, RefPtr<InspectorValue>* styleObject, RefPtr<InspectorArray>* changedProperties);
void setStyleText(long styleId, const String& cssText, bool* success);
void setStyleProperty(long styleId, const String& name, const String& value, bool* success);
@@ -148,7 +148,6 @@ namespace WebCore {
void copyNode(long nodeId);
private:
- static CSSStyleSheet* getParentStyleSheet(CSSStyleDeclaration*);
void startListening(Document* document);
void stopListening(Document* document);
@@ -162,8 +161,8 @@ namespace WebCore {
bool pushDocumentToFrontend();
bool hasBreakpoint(Node* node, long type);
- PassRefPtr<InspectorObject> createBreakpoint(Node* node, long type);
void updateSubtreeBreakpoints(Node* root, uint32_t rootMask, bool value);
+ PassRefPtr<InspectorValue> descriptionForDOMEvent(Node* target, long breakpointType, bool insertion);
PassRefPtr<InspectorObject> buildObjectForAttributeStyles(Element* element);
PassRefPtr<InspectorArray> buildArrayForCSSRules(Document* ownerDocument, CSSRuleList*);
diff --git a/WebCore/inspector/InspectorDebuggerAgent.cpp b/WebCore/inspector/InspectorDebuggerAgent.cpp
index fd9fdf3..3875be0 100644
--- a/WebCore/inspector/InspectorDebuggerAgent.cpp
+++ b/WebCore/inspector/InspectorDebuggerAgent.cpp
@@ -38,6 +38,7 @@
#include "PlatformString.h"
#include "ScriptDebugServer.h"
#include <wtf/MD5.h>
+#include <wtf/text/CString.h>
namespace WebCore {
@@ -292,7 +293,7 @@ void InspectorDebuggerAgent::didPause(ScriptState* scriptState)
m_pausedScriptState = scriptState;
RefPtr<InspectorObject> details = InspectorObject::create();
details->setValue("callFrames", currentCallFrames());
- details->setValue("reason", m_breakProgramReason);
+ details->setValue("status", m_breakProgramReason);
m_frontend->pausedScript(details);
}
diff --git a/WebCore/inspector/InspectorProfilerAgent.cpp b/WebCore/inspector/InspectorProfilerAgent.cpp
index 9161c3b..09b2b32 100644
--- a/WebCore/inspector/InspectorProfilerAgent.cpp
+++ b/WebCore/inspector/InspectorProfilerAgent.cpp
@@ -43,6 +43,7 @@
#include "ScriptProfile.h"
#include "ScriptProfiler.h"
#include <wtf/OwnPtr.h>
+#include <wtf/text/CString.h>
#if USE(JSC)
#include "JSDOMWindow.h"
diff --git a/WebCore/inspector/InspectorResource.cpp b/WebCore/inspector/InspectorResource.cpp
index be77827..ac2c9a0 100644
--- a/WebCore/inspector/InspectorResource.cpp
+++ b/WebCore/inspector/InspectorResource.cpp
@@ -43,14 +43,39 @@
#include "ResourceLoadTiming.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
+#include "StringBuffer.h"
#include "TextEncoding.h"
+#include "WebSocketHandshakeRequest.h"
+#include "WebSocketHandshakeResponse.h"
+
+#include <wtf/Assertions.h>
namespace WebCore {
+#if ENABLE(WEB_SOCKETS)
+// Create human-readable binary representation, like "01:23:45:67:89:AB:CD:EF".
+static String createReadableStringFromBinary(const unsigned char* value, size_t length)
+{
+ ASSERT(length > 0);
+ static const char hexDigits[17] = "0123456789ABCDEF";
+ size_t bufferSize = length * 3 - 1;
+ StringBuffer buffer(bufferSize);
+ size_t index = 0;
+ for (size_t i = 0; i < length; ++i) {
+ if (i > 0)
+ buffer[index++] = ':';
+ buffer[index++] = hexDigits[value[i] >> 4];
+ buffer[index++] = hexDigits[value[i] & 0xF];
+ }
+ ASSERT(index == bufferSize);
+ return String::adopt(buffer);
+}
+#endif
+
InspectorResource::InspectorResource(unsigned long identifier, DocumentLoader* loader, const KURL& requestURL)
: m_identifier(identifier)
, m_loader(loader)
- , m_frame(loader->frame())
+ , m_frame(loader ? loader->frame() : 0)
, m_requestURL(requestURL)
, m_expectedContentLength(0)
, m_cached(false)
@@ -66,6 +91,9 @@ InspectorResource::InspectorResource(unsigned long identifier, DocumentLoader* l
, m_connectionID(0)
, m_connectionReused(false)
, m_isMainResource(false)
+#if ENABLE(WEB_SOCKETS)
+ , m_isWebSocket(false)
+#endif
{
}
@@ -88,6 +116,12 @@ PassRefPtr<InspectorResource> InspectorResource::appendRedirect(unsigned long id
return redirect;
}
+PassRefPtr<InspectorResource> InspectorResource::create(unsigned long identifier, DocumentLoader* loader, const KURL& requestURL)
+{
+ ASSERT(loader);
+ return adoptRef(new InspectorResource(identifier, loader, requestURL));
+}
+
PassRefPtr<InspectorResource> InspectorResource::createCached(unsigned long identifier, DocumentLoader* loader, const CachedResource* cachedResource)
{
PassRefPtr<InspectorResource> resource = create(identifier, loader, KURL(ParsedURLString, cachedResource->url()));
@@ -107,6 +141,16 @@ PassRefPtr<InspectorResource> InspectorResource::createCached(unsigned long iden
return resource;
}
+#if ENABLE(WEB_SOCKETS)
+PassRefPtr<InspectorResource> InspectorResource::createWebSocket(unsigned long identifier, const KURL& requestURL, const KURL& documentURL)
+{
+ RefPtr<InspectorResource> resource = adoptRef(new InspectorResource(identifier, 0, requestURL));
+ resource->markWebSocket();
+ resource->m_documentURL = documentURL;
+ return resource.release();
+}
+#endif
+
void InspectorResource::updateRequest(const ResourceRequest& request)
{
m_requestHeaderFields = request.httpHeaderFields();
@@ -117,6 +161,11 @@ void InspectorResource::updateRequest(const ResourceRequest& request)
m_changes.set(RequestChange);
}
+void InspectorResource::markAsCached()
+{
+ m_cached = true;
+}
+
void InspectorResource::updateResponse(const ResourceResponse& response)
{
m_expectedContentLength = response.expectedContentLength();
@@ -134,7 +183,7 @@ void InspectorResource::updateResponse(const ResourceResponse& response)
m_connectionID = response.connectionID();
m_connectionReused = response.connectionReused();
m_loadTiming = response.resourceLoadTiming();
- m_cached = response.wasCached();
+ m_cached = m_cached || response.wasCached();
if (!m_cached && m_loadTiming && m_loadTiming->requestTime)
m_responseReceivedTime = m_loadTiming->requestTime + m_loadTiming->receiveHeadersEnd / 1000.0;
@@ -146,6 +195,27 @@ void InspectorResource::updateResponse(const ResourceResponse& response)
m_changes.set(TypeChange);
}
+#if ENABLE(WEB_SOCKETS)
+void InspectorResource::updateWebSocketRequest(const WebSocketHandshakeRequest& request)
+{
+ m_requestHeaderFields = request.headerFields();
+ m_requestMethod = "GET"; // Currently we always use "GET" to request handshake.
+ m_webSocketRequestKey3.set(new WebSocketHandshakeRequest::Key3(request.key3()));
+ m_changes.set(RequestChange);
+ m_changes.set(TypeChange);
+}
+
+void InspectorResource::updateWebSocketResponse(const WebSocketHandshakeResponse& response)
+{
+ m_responseStatusCode = response.statusCode();
+ m_responseStatusText = response.statusText();
+ m_responseHeaderFields = response.headerFields();
+ m_webSocketChallengeResponse.set(new WebSocketHandshakeResponse::ChallengeResponse(response.challengeResponse()));
+ m_changes.set(ResponseChange);
+ m_changes.set(TypeChange);
+}
+#endif // ENABLE(WEB_SOCKETS)
+
static PassRefPtr<InspectorObject> buildHeadersObject(const HTTPHeaderMap& headers)
{
RefPtr<InspectorObject> object = InspectorObject::create();
@@ -183,8 +253,10 @@ void InspectorResource::updateScriptObject(InspectorFrontend* frontend)
RefPtr<InspectorObject> jsonObject = InspectorObject::create();
jsonObject->setNumber("id", m_identifier);
if (m_changes.hasChange(RequestChange)) {
+ if (m_frame)
+ m_documentURL = m_frame->document()->url();
jsonObject->setString("url", m_requestURL.string());
- jsonObject->setString("documentURL", m_frame->document()->url().string());
+ jsonObject->setString("documentURL", m_documentURL.string());
jsonObject->setString("host", m_requestURL.host());
jsonObject->setString("path", m_requestURL.path());
jsonObject->setString("lastPathComponent", m_requestURL.lastPathComponent());
@@ -194,6 +266,10 @@ void InspectorResource::updateScriptObject(InspectorFrontend* frontend)
jsonObject->setString("requestMethod", m_requestMethod);
jsonObject->setString("requestFormData", m_requestFormData);
jsonObject->setBoolean("didRequestChange", true);
+#if ENABLE(WEB_SOCKETS)
+ if (m_webSocketRequestKey3)
+ jsonObject->setString("webSocketRequestKey3", createReadableStringFromBinary(m_webSocketRequestKey3->value, sizeof(m_webSocketRequestKey3->value)));
+#endif
}
if (m_changes.hasChange(ResponseChange)) {
@@ -209,6 +285,10 @@ void InspectorResource::updateScriptObject(InspectorFrontend* frontend)
jsonObject->setBoolean("cached", m_cached);
if (m_loadTiming && !m_cached)
jsonObject->setObject("timing", buildObjectForTiming(m_loadTiming.get()));
+#if ENABLE(WEB_SOCKETS)
+ if (m_webSocketChallengeResponse)
+ jsonObject->setString("webSocketChallengeResponse", createReadableStringFromBinary(m_webSocketChallengeResponse->value, sizeof(m_webSocketChallengeResponse->value)));
+#endif
jsonObject->setBoolean("didResponseChange", true);
}
@@ -267,6 +347,8 @@ CachedResource* InspectorResource::cachedResource() const
// Try hard to find a corresponding CachedResource. During preloading, CachedResourceLoader may not have the resource in document resources set yet,
// but Inspector will already try to fetch data that is only available via CachedResource (and it won't update once the resource is added,
// because m_changes will not have the appropriate bits set).
+ if (!m_frame)
+ return 0;
const String& url = m_requestURL.string();
CachedResource* cachedResource = m_frame->document()->cachedResourceLoader()->cachedResource(url);
if (!cachedResource)
@@ -303,6 +385,12 @@ InspectorResource::Type InspectorResource::type() const
if (!m_overrideContent.isNull())
return m_overrideContentType;
+#if ENABLE(WEB_SOCKETS)
+ if (m_isWebSocket)
+ return WebSocket;
+#endif
+
+ ASSERT(m_loader);
if (equalIgnoringFragmentIdentifier(m_requestURL, m_loader->requestURL())) {
InspectorResource::Type resourceType = cachedResourceType();
if (resourceType == Other)
@@ -342,7 +430,7 @@ String InspectorResource::sourceString() const
PassRefPtr<SharedBuffer> InspectorResource::resourceData(String* textEncodingName) const
{
- if (equalIgnoringFragmentIdentifier(m_requestURL, m_loader->requestURL())) {
+ if (m_loader && equalIgnoringFragmentIdentifier(m_requestURL, m_loader->requestURL())) {
*textEncodingName = m_frame->document()->inputEncoding();
return m_loader->mainResourceData();
}
@@ -372,9 +460,18 @@ void InspectorResource::startTiming()
m_changes.set(TimingChange);
}
-void InspectorResource::endTiming()
+void InspectorResource::endTiming(double actualEndTime)
{
- m_endTime = currentTime();
+ if (actualEndTime) {
+ m_endTime = actualEndTime;
+ // In case of fast load (or in case of cached resources), endTime on network stack
+ // can be less then m_responseReceivedTime measured in WebCore. Normalize it here,
+ // prefer actualEndTime to m_responseReceivedTime.
+ if (m_endTime < m_responseReceivedTime)
+ m_responseReceivedTime = m_endTime;
+ } else
+ m_endTime = currentTime();
+
m_finished = true;
m_changes.set(TimingChange);
m_changes.set(CompletionChange);
diff --git a/WebCore/inspector/InspectorResource.h b/WebCore/inspector/InspectorResource.h
index 4004142..914232e 100644
--- a/WebCore/inspector/InspectorResource.h
+++ b/WebCore/inspector/InspectorResource.h
@@ -34,6 +34,8 @@
#include "HTTPHeaderMap.h"
#include "KURL.h"
#include "ScriptString.h"
+#include "WebSocketHandshakeRequest.h"
+#include "WebSocketHandshakeResponse.h"
#include <wtf/CurrentTime.h>
#include <wtf/OwnPtr.h>
@@ -51,6 +53,11 @@ namespace WebCore {
class ResourceRequest;
class ResourceResponse;
+#if ENABLE(WEB_SOCKETS)
+ class WebSocketHandshakeRequest;
+ class WebSocketHandshakeResponse;
+#endif
+
class InspectorResource : public RefCounted<InspectorResource> {
public:
@@ -63,16 +70,19 @@ namespace WebCore {
Script,
XHR,
Media,
+ WebSocket,
Other
};
- static PassRefPtr<InspectorResource> create(unsigned long identifier, DocumentLoader* loader, const KURL& requestURL)
- {
- return adoptRef(new InspectorResource(identifier, loader, requestURL));
- }
+ static PassRefPtr<InspectorResource> create(unsigned long identifier, DocumentLoader* loader, const KURL& requestURL);
static PassRefPtr<InspectorResource> createCached(unsigned long identifier, DocumentLoader*, const CachedResource*);
+#if ENABLE(WEB_SOCKETS)
+ // WebSocket resource doesn't have its loader. For WebSocket resources, m_loader and m_frame will become null.
+ static PassRefPtr<InspectorResource> createWebSocket(unsigned long identifier, const KURL& requestURL, const KURL& documentURL);
+#endif
+
~InspectorResource();
PassRefPtr<InspectorResource> appendRedirect(unsigned long identifier, const KURL& redirectURL);
@@ -80,8 +90,14 @@ namespace WebCore {
void releaseScriptObject(InspectorFrontend* frontend);
void updateRequest(const ResourceRequest&);
+ void markAsCached();
void updateResponse(const ResourceResponse&);
+#if ENABLE(WEB_SOCKETS)
+ void updateWebSocketRequest(const WebSocketHandshakeRequest&);
+ void updateWebSocketResponse(const WebSocketHandshakeResponse&);
+#endif
+
void setOverrideContent(const ScriptString& data, Type);
String sourceString() const;
@@ -102,7 +118,7 @@ namespace WebCore {
void startTiming();
void markLoadEventTime();
void markDOMContentEventTime();
- void endTiming();
+ void endTiming(double actualEndTime);
void markFailed();
void addLength(int lengthReceived);
@@ -149,10 +165,15 @@ namespace WebCore {
Type cachedResourceType() const;
CachedResource* cachedResource() const;
+#if ENABLE(WEB_SOCKETS)
+ void markWebSocket() { m_isWebSocket = true; }
+#endif
+
unsigned long m_identifier;
RefPtr<DocumentLoader> m_loader;
RefPtr<Frame> m_frame;
KURL m_requestURL;
+ KURL m_documentURL;
HTTPHeaderMap m_requestHeaderFields;
HTTPHeaderMap m_responseHeaderFields;
String m_mimeType;
@@ -179,6 +200,15 @@ namespace WebCore {
String m_requestMethod;
String m_requestFormData;
Vector<RefPtr<InspectorResource> > m_redirects;
+
+#if ENABLE(WEB_SOCKETS)
+ bool m_isWebSocket;
+
+ // The following fields are not used for resources other than WebSocket.
+ // We allocate them dynamically to reduce memory consumption for regular resources.
+ OwnPtr<WebSocketHandshakeRequest::Key3> m_webSocketRequestKey3;
+ OwnPtr<WebSocketHandshakeResponse::ChallengeResponse> m_webSocketChallengeResponse;
+#endif
};
} // namespace WebCore
diff --git a/WebCore/inspector/front-end/AuditFormatters.js b/WebCore/inspector/front-end/AuditFormatters.js
index de277ad..1bc1803 100755..100644
--- a/WebCore/inspector/front-end/AuditFormatters.js
+++ b/WebCore/inspector/front-end/AuditFormatters.js
@@ -79,8 +79,14 @@ WebInspector.AuditFormatters = {
return parent;
},
- url: function(url, displayText)
+ url: function(url, displayText, allowExternalNavigation)
{
- return WebInspector.linkifyURLAsNode(url, displayText || url, null, (url in WebInspector.resourceURLMap));
+ var a = document.createElement("a");
+ a.href = url;
+ a.title = url;
+ a.textContent = displayText || url;
+ if (allowExternalNavigation)
+ a.target = "_blank";
+ return a;
}
};
diff --git a/WebCore/inspector/front-end/BreakpointsSidebarPane.js b/WebCore/inspector/front-end/BreakpointsSidebarPane.js
index cda72fb..9688f3e 100644
--- a/WebCore/inspector/front-end/BreakpointsSidebarPane.js
+++ b/WebCore/inspector/front-end/BreakpointsSidebarPane.js
@@ -97,6 +97,7 @@ WebInspector.BreakpointItem = function(breakpoint)
this._breakpoint = breakpoint;
this._element = document.createElement("li");
+ this._element.addEventListener("click", this._breakpointClicked.bind(this), false);
var checkboxElement = document.createElement("input");
checkboxElement.className = "checkbox-elem";
@@ -141,8 +142,6 @@ WebInspector.JSBreakpointItem = function(breakpoint)
{
WebInspector.BreakpointItem.call(this, breakpoint);
- this._element.addEventListener("click", this._breakpointClicked.bind(this), false);
-
var displayName = this._breakpoint.url ? WebInspector.displayNameForURL(this._breakpoint.url) : WebInspector.UIString("(program)");
var labelElement = document.createTextNode(displayName + ":" + this._breakpoint.line);
this._element.appendChild(labelElement);
@@ -183,8 +182,7 @@ WebInspector.DOMBreakpointItem = function(breakpoint)
{
WebInspector.BreakpointItem.call(this, breakpoint);
- var node = WebInspector.domAgent.nodeForId(this._breakpoint.nodeId);
- var link = WebInspector.panels.elements.linkifyNodeReference(node);
+ var link = WebInspector.panels.elements.linkifyNodeById(this._breakpoint.nodeId);
this._element.appendChild(link);
var type = WebInspector.DOMBreakpoint.labelForType(this._breakpoint.type);
@@ -198,6 +196,11 @@ WebInspector.DOMBreakpointItem.prototype = {
if (this._breakpoint.type != other._breakpoint.type)
return this._breakpoint.type < other._breakpoint.type ? -1 : 1;
return 0;
+ },
+
+ _breakpointClicked: function()
+ {
+ WebInspector.updateFocusedNode(this._breakpoint.nodeId);
}
}
diff --git a/WebCore/inspector/front-end/CallStackSidebarPane.js b/WebCore/inspector/front-end/CallStackSidebarPane.js
index 60eee34..91f35a6 100644
--- a/WebCore/inspector/front-end/CallStackSidebarPane.js
+++ b/WebCore/inspector/front-end/CallStackSidebarPane.js
@@ -26,7 +26,6 @@
WebInspector.CallStackSidebarPane = function()
{
WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack"));
-
}
WebInspector.CallStackSidebarPane.prototype = {
@@ -83,6 +82,39 @@ WebInspector.CallStackSidebarPane.prototype = {
}
},
+ updateStatus: function(status)
+ {
+ var statusElement = document.createElement("div");
+ statusElement.className = "info";
+
+ var breakpointType = status.breakpoint.type;
+ var substitutions = [WebInspector.DOMBreakpoint.labelForType(breakpointType), WebInspector.panels.elements.linkifyNodeById(status.breakpoint.nodeId)];
+ var formatters = {
+ s: function(substitution)
+ {
+ return substitution;
+ }
+ };
+ function append(a, b)
+ {
+ if (typeof b === "string")
+ b = document.createTextNode(b);
+ statusElement.appendChild(b);
+ }
+ if (breakpointType === WebInspector.DOMBreakpoint.Types.SubtreeModified) {
+ var targetNode = WebInspector.panels.elements.linkifyNodeById(status.targetNodeId);
+ if (status.insertion) {
+ if (status.targetNodeId !== status.breakpoint.nodeId)
+ WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s.", substitutions.concat(targetNode), formatters, "", append);
+ else
+ WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node.", substitutions, formatters, "", append);
+ } else
+ WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed.", substitutions.concat(targetNode), formatters, "", append);
+ } else
+ WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s.", substitutions, formatters, "", append);
+ this.bodyElement.appendChild(statusElement);
+ },
+
get selectedCallFrame()
{
return this._selectedCallFrame;
diff --git a/WebCore/inspector/front-end/ConsoleView.js b/WebCore/inspector/front-end/ConsoleView.js
index 9785cd0..6f8bd8b 100644
--- a/WebCore/inspector/front-end/ConsoleView.js
+++ b/WebCore/inspector/front-end/ConsoleView.js
@@ -400,10 +400,13 @@ WebInspector.ConsoleView.prototype = {
}
var contextMenu = new WebInspector.ContextMenu();
- if (!WebInspector.monitoringXHREnabled)
- contextMenu.appendCheckboxItem(WebInspector.UIString("XMLHttpRequest logging"), InspectorBackend.enableMonitoringXHR.bind(InspectorBackend), false);
- else
- contextMenu.appendCheckboxItem(WebInspector.UIString("XMLHttpRequest logging"), InspectorBackend.disableMonitoringXHR.bind(InspectorBackend), true);
+
+ function monitoringXHRWasChanged(newState)
+ {
+ WebInspector.monitoringXHREnabled = newState;
+ }
+ var itemAction = InspectorBackend.setMonitoringXHREnabled.bind(InspectorBackend, !WebInspector.monitoringXHREnabled, monitoringXHRWasChanged);
+ contextMenu.appendCheckboxItem(WebInspector.UIString("XMLHttpRequest logging"), itemAction, WebInspector.monitoringXHREnabled);
contextMenu.appendItem(WebInspector.UIString("Clear Console"), this.requestClearMessages.bind(this));
contextMenu.show(event);
},
@@ -518,7 +521,7 @@ WebInspector.ConsoleView.prototype = {
_enterKeyPressed: function(event)
{
- if (event.altKey)
+ if (event.altKey || event.ctrlKey)
return;
event.preventDefault();
@@ -1091,7 +1094,7 @@ WebInspector.ConsoleGroup.prototype = {
if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup || msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
this.messagesElement.parentNode.insertBefore(element, this.messagesElement);
- element.addEventListener("click", this._titleClicked.bind(this), true);
+ element.addEventListener("click", this._titleClicked.bind(this), false);
var groupElement = element.enclosingNodeOrSelfWithClass("console-group");
if (groupElement && msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
groupElement.addStyleClass("collapsed");
diff --git a/WebCore/inspector/front-end/ElementsPanel.js b/WebCore/inspector/front-end/ElementsPanel.js
index c60d4b1..72b23e1 100644
--- a/WebCore/inspector/front-end/ElementsPanel.js
+++ b/WebCore/inspector/front-end/ElementsPanel.js
@@ -147,7 +147,7 @@ WebInspector.ElementsPanel.prototype = {
{
WebInspector.Panel.prototype.hide.call(this);
- WebInspector.hoveredDOMNode = null;
+ WebInspector.highlightDOMNode(0);
InspectorBackend.disableSearchingForNode();
},
@@ -165,7 +165,7 @@ WebInspector.ElementsPanel.prototype = {
this.rootDOMNode = null;
this.focusedDOMNode = null;
- WebInspector.hoveredDOMNode = null;
+ WebInspector.highlightDOMNode(0);
this.recentlyModifiedNodes = [];
@@ -187,9 +187,7 @@ WebInspector.ElementsPanel.prototype = {
inspectedRootDocument.addEventListener("DOMNodeRemoved", this._nodeRemoved.bind(this));
inspectedRootDocument.addEventListener("DOMAttrModified", this._attributesUpdated.bind(this));
- this.treeOutline.suppressSelectHighlight = true;
this.rootDOMNode = inspectedRootDocument;
- this.treeOutline.suppressSelectHighlight = false;
function selectNode(candidateFocusNode)
{
@@ -199,11 +197,9 @@ WebInspector.ElementsPanel.prototype = {
if (!candidateFocusNode)
return;
- this.treeOutline.suppressSelectHighlight = true;
this.focusedDOMNode = candidateFocusNode;
if (this.treeOutline.selectedTreeElement)
this.treeOutline.selectedTreeElement.expand();
- this.treeOutline.suppressSelectHighlight = false;
}
function selectLastSelectedNode(nodeId)
@@ -261,6 +257,23 @@ WebInspector.ElementsPanel.prototype = {
this._nodeSearchButton.toggled = false;
},
+ populateHrefContextMenu: function(contextMenu, event, anchorElement)
+ {
+ if (!anchorElement.href)
+ return false;
+
+ var resourceURL = WebInspector.resourceURLForRelatedNode(this.focusedDOMNode, anchorElement.href);
+ if (!resourceURL)
+ return false;
+
+ // Add resource-related actions.
+ // Keep these consistent with those added in WebInspector.StylesSidebarPane.prototype._populateHrefContextMenu().
+ contextMenu.appendItem(WebInspector.UIString("Open Link in New Window"), WebInspector.openResource.bind(null, resourceURL, false));
+ if (WebInspector.resourceForURL(resourceURL))
+ contextMenu.appendItem(WebInspector.UIString("Open Link in Resources Panel"), WebInspector.openResource.bind(null, resourceURL, true));
+ return true;
+ },
+
_updateMatchesCount: function()
{
WebInspector.updateSearchMatchesCount(this._searchResults.length, this);
@@ -561,7 +574,7 @@ WebInspector.ElementsPanel.prototype = {
var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
var crumbElement = nodeUnderMouse.enclosingNodeOrSelfWithClass("crumb");
- WebInspector.hoveredDOMNode = (crumbElement ? crumbElement.representedObject : null);
+ WebInspector.highlightDOMNode(crumbElement ? crumbElement.representedObject.id : 0);
if ("_mouseOutOfCrumbsTimeout" in this) {
clearTimeout(this._mouseOutOfCrumbsTimeout);
@@ -575,7 +588,7 @@ WebInspector.ElementsPanel.prototype = {
if (nodeUnderMouse && nodeUnderMouse.isDescendant(this.crumbsElement))
return;
- WebInspector.hoveredDOMNode = null;
+ WebInspector.highlightDOMNode(0);
this._mouseOutOfCrumbsTimeout = setTimeout(this.updateBreadcrumbSizes.bind(this), 1000);
},
@@ -761,11 +774,19 @@ WebInspector.ElementsPanel.prototype = {
{
var link = document.createElement("span");
link.className = "node-link";
- link.addEventListener("click", WebInspector.updateFocusedNode.bind(WebInspector, node.id), false);
this.decorateNodeLabel(node, link);
+ WebInspector.wireElementWithDOMNode(link, node.id);
return link;
},
+ linkifyNodeById: function(nodeId)
+ {
+ var node = WebInspector.domAgent.nodeForId(nodeId);
+ if (!node)
+ return document.createTextNode(WebInspector.UIString("<node>"));
+ return this.linkifyNodeReference(node);
+ },
+
updateBreadcrumbSizes: function(focusedCrumb)
{
if (!this.visible)
diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js
index 10131f4..e261234 100644
--- a/WebCore/inspector/front-end/ElementsTreeOutline.js
+++ b/WebCore/inspector/front-end/ElementsTreeOutline.js
@@ -93,27 +93,8 @@ WebInspector.ElementsTreeOutline.prototype = {
// and the select() call would change the focusedDOMNode and reenter this setter. So to
// avoid calling focusedNodeChanged() twice, first check if _focusedDOMNode is the same
// node as the one passed in.
- if (this._focusedDOMNode === x) {
+ if (this._focusedDOMNode === x)
this.focusedNodeChanged();
-
- if (x && !this.suppressSelectHighlight) {
- InspectorBackend.highlightDOMNode(x.id);
-
- if ("_restorePreviousHighlightNodeTimeout" in this)
- clearTimeout(this._restorePreviousHighlightNodeTimeout);
-
- function restoreHighlightToHoveredNode()
- {
- var hoveredNode = WebInspector.hoveredDOMNode;
- if (hoveredNode)
- InspectorBackend.highlightDOMNode(hoveredNode.id);
- else
- InspectorBackend.hideDOMNodeHighlight();
- }
-
- this._restorePreviousHighlightNodeTimeout = setTimeout(restoreHighlightToHoveredNode, 2000);
- }
- }
},
get editing()
@@ -260,7 +241,7 @@ WebInspector.ElementsTreeOutline.prototype = {
element._createTooltipForNode();
}
- WebInspector.hoveredDOMNode = (element ? element.representedObject : null);
+ WebInspector.highlightDOMNode(element ? element.representedObject.id : 0);
},
_onmouseout: function(event)
@@ -274,7 +255,7 @@ WebInspector.ElementsTreeOutline.prototype = {
delete this._previousHoveredElement;
}
- WebInspector.hoveredDOMNode = null;
+ WebInspector.highlightDOMNode(0);
},
_contextMenuEventFired: function(event)
@@ -285,12 +266,21 @@ WebInspector.ElementsTreeOutline.prototype = {
var contextMenu = new WebInspector.ContextMenu();
+ var href = event.target.enclosingNodeOrSelfWithClass("webkit-html-resource-link") || event.target.enclosingNodeOrSelfWithClass("webkit-html-external-link");
var tag = event.target.enclosingNodeOrSelfWithClass("webkit-html-tag");
var textNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-text-node");
- if (tag && listItem.treeElement._populateTagContextMenu)
+ var needSeparator;
+ if (href)
+ needSeparator = WebInspector.panels.elements.populateHrefContextMenu(contextMenu, event, href);
+ if (tag && listItem.treeElement._populateTagContextMenu) {
+ if (needSeparator)
+ contextMenu.appendSeparator();
listItem.treeElement._populateTagContextMenu(contextMenu, event);
- else if (textNode && listItem.treeElement._populateTextContextMenu)
+ } else if (textNode && listItem.treeElement._populateTextContextMenu) {
+ if (needSeparator)
+ contextMenu.appendSeparator();
listItem.treeElement._populateTextContextMenu(contextMenu, textNode);
+ }
contextMenu.show(event);
}
}
@@ -1189,29 +1179,6 @@ WebInspector.ElementsTreeElement.prototype = {
this._highlightSearchResults();
},
- _rewriteAttrHref: function(node, hrefValue)
- {
- if (!hrefValue || hrefValue.indexOf("://") > 0)
- return hrefValue;
-
- for (var frameOwnerCandidate = node; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) {
- if (frameOwnerCandidate.documentURL) {
- var result = WebInspector.completeURL(frameOwnerCandidate.documentURL, hrefValue);
- if (result)
- return result;
- break;
- }
- }
-
- // documentURL not found or has bad value
- for (var url in WebInspector.resourceURLMap) {
- var match = url.match(WebInspector.URLRegExp);
- if (match && match[4] === hrefValue)
- return url;
- }
- return hrefValue;
- },
-
_attributeHTML: function(name, value, node, linkify)
{
var hasText = (value.length > 0);
@@ -1221,7 +1188,7 @@ WebInspector.ElementsTreeElement.prototype = {
html += "=&#8203;\"";
if (linkify && (name === "src" || name === "href")) {
- var rewrittenHref = this._rewriteAttrHref(node, value);
+ var rewrittenHref = WebInspector.resourceURLForRelatedNode(node, value);
value = value.replace(/([\/;:\)\]\}])/g, "$1\u200B");
html += linkify(rewrittenHref, value, "webkit-html-attribute-value", node.nodeName.toLowerCase() === "a");
} else {
diff --git a/WebCore/inspector/front-end/HAREntry.js b/WebCore/inspector/front-end/HAREntry.js
index 9f188ed..85e4f59 100644
--- a/WebCore/inspector/front-end/HAREntry.js
+++ b/WebCore/inspector/front-end/HAREntry.js
@@ -42,7 +42,7 @@ WebInspector.HAREntry.prototype = {
return {
pageref: this._resource.documentURL,
startedDateTime: new Date(this._resource.startTime * 1000),
- time: this._toMilliseconds(this._resource.duration),
+ time: WebInspector.HAREntry._toMilliseconds(this._resource.duration),
request: this._buildRequest(),
response: this._buildResponse(),
// cache: {...}, -- Not supproted yet.
@@ -95,14 +95,34 @@ WebInspector.HAREntry.prototype = {
_buildTimings: function()
{
+ var waitForConnection = this._interval("connectStart", "connectEnd");
+ var blocked;
+ var connect;
+ var dns = this._interval("dnsStart", "dnsEnd");
+ var send = this._interval("sendStart", "sendEnd");
+ var ssl = this._interval("sslStart", "sslEnd");
+
+ if (ssl !== -1 && send !== -1)
+ send -= ssl;
+
+ if (this._resource.connectionReused) {
+ connect = -1;
+ blocked = waitForConnection;
+ } else {
+ blocked = 0;
+ connect = waitForConnection;
+ if (dns !== -1)
+ connect -= dns;
+ }
+
return {
- blocked: -1, // Not available.
- dns: -1, // Not available.
- connect: -1, // Not available.
- send: -1, // Not available.
- wait: this._toMilliseconds(this._resource.latency),
- receive: this._toMilliseconds(this._resource.receiveDuration),
- ssl: -1 // Not available.
+ blocked: blocked,
+ dns: dns,
+ connect: connect,
+ send: send,
+ wait: this._interval("sendEnd", "receiveHeadersEnd"),
+ receive: WebInspector.HAREntry._toMilliseconds(this._resource.receiveDuration),
+ ssl: ssl
};
},
@@ -130,8 +150,65 @@ WebInspector.HAREntry.prototype = {
return parameters.slice();
},
- _toMilliseconds: function(time)
+ _interval: function(start, end)
+ {
+ var timing = this._resource.timing;
+ if (!timing)
+ return -1;
+ var startTime = timing[start];
+ return typeof startTime !== "number" || startTime === -1 ? -1 : Math.round(timing[end] - startTime);
+ }
+};
+
+WebInspector.HAREntry._toMilliseconds = function(time)
+{
+ return time === -1 ? -1 : Math.round(time * 1000);
+}
+
+WebInspector.HARLog = function()
+{
+}
+
+WebInspector.HARLog.prototype = {
+ build: function()
+ {
+ var webKitVersion = /AppleWebKit\/([^ ]+)/.exec(window.navigator.userAgent);
+
+ return {
+ version: "1.2",
+ creator: {
+ name: "WebInspector",
+ version: webKitVersion ? webKitVersion[1] : "n/a"
+ },
+ pages: this._buildPages(),
+ entries: Object.properties(WebInspector.resources).map(this._convertResource)
+ }
+ },
+
+ _buildPages: function()
+ {
+ return [
+ {
+ startedDateTime: new Date(WebInspector.mainResource.startTime * 1000),
+ id: WebInspector.mainResource.documentURL,
+ title: "",
+ pageTimings: this._buildMainResourceTimings()
+ }
+ ];
+ },
+
+ _buildMainResourceTimings: function()
+ {
+ var resourcesPanel = WebInspector.panels.resources;
+ var startTime = WebInspector.mainResource.startTime;
+ return {
+ onContentLoad: WebInspector.HAREntry._toMilliseconds(resourcesPanel.mainResourceDOMContentTime - startTime),
+ onLoad: WebInspector.HAREntry._toMilliseconds(resourcesPanel.mainResourceLoadTime - startTime),
+ }
+ },
+
+ _convertResource: function(id)
{
- return time === -1 ? -1 : Math.round(time * 1000);
+ return (new WebInspector.HAREntry(WebInspector.resources[id])).build();
}
};
diff --git a/WebCore/inspector/front-end/InjectedScript.js b/WebCore/inspector/front-end/InjectedScript.js
index d4e3d80..5544ed5 100644
--- a/WebCore/inspector/front-end/InjectedScript.js
+++ b/WebCore/inspector/front-end/InjectedScript.js
@@ -464,6 +464,10 @@ InjectedScript.prototype = {
return str.replace(/^\[object (.*)\]$/i, "$1");
} else {
// V8
+ if (isFinite(obj.length) && typeof obj.callee === "function") {
+ // Arguments.constructor === Object in V8
+ return "Arguments";
+ }
return obj.constructor && obj.constructor.name || "Object";
}
},
diff --git a/WebCore/inspector/front-end/ProfileDataGridTree.js b/WebCore/inspector/front-end/ProfileDataGridTree.js
index b10f392..adf34f1 100644
--- a/WebCore/inspector/front-end/ProfileDataGridTree.js
+++ b/WebCore/inspector/front-end/ProfileDataGridTree.js
@@ -96,19 +96,10 @@ WebInspector.ProfileDataGridNode.prototype = {
cell.addStyleClass("highlight");
if (this.profileNode.url) {
- var fileName = WebInspector.displayNameForURL(this.profileNode.url);
-
- var urlElement = document.createElement("a");
- urlElement.className = "profile-node-file webkit-html-resource-link";
- urlElement.href = this.profileNode.url;
- urlElement.lineNumber = this.profileNode.lineNumber;
- urlElement.preferredPanel = "scripts";
-
+ var lineNumber;
if (this.profileNode.lineNumber > 0)
- urlElement.textContent = fileName + ":" + this.profileNode.lineNumber;
- else
- urlElement.textContent = fileName;
-
+ lineNumber = this.profileNode.lineNumber;
+ var urlElement = WebInspector.linkifyResourceAsNode(this.profileNode.url, "scripts", lineNumber, "profile-node-file");
cell.insertBefore(urlElement, cell.firstChild);
}
diff --git a/WebCore/inspector/front-end/Resource.js b/WebCore/inspector/front-end/Resource.js
index de87047..ea9052d 100644
--- a/WebCore/inspector/front-end/Resource.js
+++ b/WebCore/inspector/front-end/Resource.js
@@ -45,7 +45,8 @@ WebInspector.Resource.Type = {
Script: 4,
XHR: 5,
Media: 6,
- Other: 7,
+ WebSocket: 7,
+ Other: 8,
isTextType: function(type)
{
@@ -76,6 +77,8 @@ WebInspector.Resource.Type = {
return "XHR";
case this.Media:
return "media";
+ case this.WebSocket:
+ return "WebSocket";
case this.Other:
default:
return "other";
@@ -372,6 +375,9 @@ WebInspector.Resource.prototype = {
case WebInspector.Resource.Type.XHR:
this.category = WebInspector.resourceCategories.xhr;
break;
+ case WebInspector.Resource.Type.WebSocket:
+ this.category = WebInspector.resourceCategories.websocket;
+ break;
case WebInspector.Resource.Type.Other:
default:
this.category = WebInspector.resourceCategories.other;
@@ -584,7 +590,8 @@ WebInspector.Resource.prototype = {
if (typeof this.type === "undefined"
|| this.type === WebInspector.Resource.Type.Other
- || this.type === WebInspector.Resource.Type.XHR)
+ || this.type === WebInspector.Resource.Type.XHR
+ || this.type === WebInspector.Resource.Type.WebSocket)
return true;
if (this.mimeType in WebInspector.MIMETypes)
diff --git a/WebCore/inspector/front-end/ResourceView.js b/WebCore/inspector/front-end/ResourceView.js
index 7ce09b6..1c2574f 100644
--- a/WebCore/inspector/front-end/ResourceView.js
+++ b/WebCore/inspector/front-end/ResourceView.js
@@ -279,13 +279,19 @@ WebInspector.ResourceView.prototype = {
_refreshRequestHeaders: function()
{
- this._refreshHeaders(WebInspector.UIString("Request Headers"), this.resource.sortedRequestHeaders, this.requestHeadersTreeElement);
+ var additionalRow = null;
+ if (typeof this.resource.webSocketRequestKey3 !== "undefined")
+ additionalRow = {header: "(Key3)", value: this.resource.webSocketRequestKey3};
+ this._refreshHeaders(WebInspector.UIString("Request Headers"), this.resource.sortedRequestHeaders, additionalRow, this.requestHeadersTreeElement);
this._refreshFormData();
},
_refreshResponseHeaders: function()
{
- this._refreshHeaders(WebInspector.UIString("Response Headers"), this.resource.sortedResponseHeaders, this.responseHeadersTreeElement);
+ var additionalRow = null;
+ if (typeof this.resource.webSocketChallengeResponse !== "undefined")
+ additionalRow = {header: "(Challenge Response)", value: this.resource.webSocketChallengeResponse};
+ this._refreshHeaders(WebInspector.UIString("Response Headers"), this.resource.sortedResponseHeaders, additionalRow, this.responseHeadersTreeElement);
},
_refreshHTTPInformation: function()
@@ -316,7 +322,7 @@ WebInspector.ResourceView.prototype = {
}
},
- _refreshHeaders: function(title, headers, headersTreeElement)
+ _refreshHeaders: function(title, headers, additionalRow, headersTreeElement)
{
headersTreeElement.removeChildren();
@@ -333,6 +339,15 @@ WebInspector.ResourceView.prototype = {
headerTreeElement.selectable = false;
headersTreeElement.appendChild(headerTreeElement);
}
+
+ if (additionalRow) {
+ var title = "<div class=\"header-name\">" + additionalRow.header.escapeHTML() + ":</div>";
+ title += "<div class=\"header-value source-code\">" + additionalRow.value.escapeHTML() + "</div>"
+
+ var headerTreeElement = new TreeElement(title, null, false);
+ headerTreeElement.selectable = false;
+ headersTreeElement.appendChild(headerTreeElement);
+ }
}
}
diff --git a/WebCore/inspector/front-end/ResourcesPanel.js b/WebCore/inspector/front-end/ResourcesPanel.js
index 27df5cf..f329b1a 100644
--- a/WebCore/inspector/front-end/ResourcesPanel.js
+++ b/WebCore/inspector/front-end/ResourcesPanel.js
@@ -47,6 +47,8 @@ WebInspector.ResourcesPanel = function()
this.filter(this.filterAllElement, false);
this.graphsTreeElement.children[0].select();
this._resourceTrackingEnabled = false;
+
+ this.sidebarElement.addEventListener("contextmenu", this._contextMenu.bind(this), true);
}
WebInspector.ResourcesPanel.prototype = {
@@ -751,16 +753,23 @@ WebInspector.ResourcesPanel.prototype = {
_toggleResourceTracking: function(optionalAlways)
{
+ function callback(newState) {
+ if (newState)
+ WebInspector.panels.resources.resourceTrackingWasEnabled();
+ else
+ WebInspector.panels.resources.resourceTrackingWasDisabled();
+ }
+
if (this._resourceTrackingEnabled) {
this.largerResourcesButton.visible = false;
this.sortingSelectElement.visible = false;
WebInspector.resources = {};
WebInspector.resourceURLMap = {};
- InspectorBackend.disableResourceTracking(true);
+ InspectorBackend.setResourceTrackingEnabled(false, true, callback);
} else {
this.largerResourcesButton.visible = true;
this.sortingSelectElement.visible = true;
- InspectorBackend.enableResourceTracking(!!optionalAlways);
+ InspectorBackend.setResourceTrackingEnabled(true, !!optionalAlways, callback);
}
},
@@ -857,7 +866,7 @@ WebInspector.ResourcesPanel.prototype = {
var title = document.createElement("span");
title.className = "resource-timing-bar-title";
- if (i >= rows.length - 2)
+ if (total - rows[i].end < rows[i].start)
title.style.right = (scale * (total - rows[i].end) + 3) + "px";
else
title.style.left = (scale * rows[i].start + 3) + "px";
@@ -876,6 +885,36 @@ WebInspector.ResourcesPanel.prototype = {
{
WebInspector.Panel.prototype.hide.call(this);
this._popoverHelper.hidePopup();
+ },
+
+ _contextMenu: function(event)
+ {
+ // createBlobURL is enabled conditionally, do not expose resource export if it's not available.
+ if (typeof window.createBlobURL !== "function" || !Preferences.resourceExportEnabled)
+ return;
+
+ var contextMenu = new WebInspector.ContextMenu();
+ var resourceTreeItem = event.target.enclosingNodeOrSelfWithClass("resource-sidebar-tree-item");
+ if (resourceTreeItem && resourceTreeItem.treeElement) {
+ var resource = resourceTreeItem.treeElement.representedObject;
+ contextMenu.appendItem(WebInspector.UIString("Export to HAR"), this._exportResource.bind(this, resource));
+ }
+ contextMenu.appendItem(WebInspector.UIString("Export all to HAR"), this._exportAll.bind(this));
+ contextMenu.show(event);
+ },
+
+ _exportAll: function()
+ {
+ var harArchive = {
+ log: (new WebInspector.HARLog()).build()
+ }
+ offerFileForDownload(JSON.stringify(harArchive));
+ },
+
+ _exportResource: function(resource)
+ {
+ var har = (new WebInspector.HAREntry(resource)).build();
+ offerFileForDownload(JSON.stringify(har));
}
}
diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js
index c5267f7..715339d 100644
--- a/WebCore/inspector/front-end/ScriptsPanel.js
+++ b/WebCore/inspector/front-end/ScriptsPanel.js
@@ -375,7 +375,7 @@ WebInspector.ScriptsPanel.prototype = {
InjectedScriptAccess.get(callFrame.worldId).evaluateInCallFrame(callFrame.id, code, objectGroup, evalCallback);
},
- debuggerPaused: function(callFrames)
+ debuggerPaused: function(details)
{
WebInspector.breakpointManager.removeOneTimeBreakpoint();
this._paused = true;
@@ -384,8 +384,11 @@ WebInspector.ScriptsPanel.prototype = {
this._updateDebuggerButtons();
- this.sidebarPanes.callstack.update(callFrames, this._sourceIDMap);
- this.sidebarPanes.callstack.selectedCallFrame = callFrames[0];
+ this.sidebarPanes.callstack.update(details.callFrames, this._sourceIDMap);
+ this.sidebarPanes.callstack.selectedCallFrame = details.callFrames[0];
+
+ if (details.status)
+ this.sidebarPanes.callstack.updateStatus(details.status);
WebInspector.currentPanel = this;
window.focus();
diff --git a/WebCore/inspector/front-end/Settings.js b/WebCore/inspector/front-end/Settings.js
index 41d82f9..63f2641 100644
--- a/WebCore/inspector/front-end/Settings.js
+++ b/WebCore/inspector/front-end/Settings.js
@@ -44,7 +44,8 @@ var Preferences = {
profilerAlwaysEnabled: false,
auditsPanelEnabled: true,
onlineDetectionEnabled: true,
- domBreakpointsEnabled: false
+ domBreakpointsEnabled: false,
+ resourceExportEnabled: false
}
WebInspector.Settings = function(sessionScope)
diff --git a/WebCore/inspector/front-end/StylesSidebarPane.js b/WebCore/inspector/front-end/StylesSidebarPane.js
index 1dddde7..6aff37d 100644
--- a/WebCore/inspector/front-end/StylesSidebarPane.js
+++ b/WebCore/inspector/front-end/StylesSidebarPane.js
@@ -64,6 +64,7 @@ WebInspector.StylesSidebarPane = function(computedStylePane)
this.titleElement.appendChild(this.settingsSelectElement);
this._computedStylePane = computedStylePane;
+ this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true);
}
// Taken from http://www.w3.org/TR/CSS21/propidx.html.
@@ -105,6 +106,17 @@ WebInspector.StylesSidebarPane.prototype = {
this.settingsSelectElement[2].selected = true;
},
+ _contextMenuEventFired: function(event)
+ {
+ var href = event.target.enclosingNodeOrSelfWithClass("webkit-html-resource-link") || event.target.enclosingNodeOrSelfWithClass("webkit-html-external-link");
+ if (href) {
+ var contextMenu = new WebInspector.ContextMenu();
+ var filled = WebInspector.panels.elements.populateHrefContextMenu(contextMenu, event, href);
+ if (filled)
+ contextMenu.show(event);
+ }
+ },
+
update: function(node, editedSection, forceUpdate)
{
var refresh = false;
diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc
index f90a9fe..c222f0e 100644
--- a/WebCore/inspector/front-end/WebKit.qrc
+++ b/WebCore/inspector/front-end/WebKit.qrc
@@ -266,5 +266,6 @@
<file>Images/warningOrangeDot.png</file>
<file>Images/warningsErrors.png</file>
<file>Images/whiteConnectorPoint.png</file>
+ <file alias="DebuggerScript.js">../../bindings/v8/DebuggerScript.js</file>
</qresource>
</RCC>
diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css
index 4319816..6d8571c 100644
--- a/WebCore/inspector/front-end/inspector.css
+++ b/WebCore/inspector/front-end/inspector.css
@@ -1693,6 +1693,10 @@ li.editing .swatch, li.editing .enabled-button, li.editing-sub-part .delete-but
color: gray;
}
+.pane > .body .placard + .info {
+ border-top: 1px solid gray
+}
+
.pane.expanded > .body, .pane.expanded > .growbar {
display: block;
}
@@ -2835,7 +2839,8 @@ button.enable-toggle-status-bar-item.toggled-on .glyph {
}
.resources-category-documents, .resources-category-stylesheets, .resources-category-images,
-.resources-category-scripts, .resources-category-xhr, .resources-category-fonts, .resources-category-other {
+.resources-category-scripts, .resources-category-xhr, .resources-category-fonts,
+.resources-category-websockets, .resources-category-other {
display: none;
}
@@ -2845,6 +2850,7 @@ button.enable-toggle-status-bar-item.toggled-on .glyph {
.filter-all .resources-category-scripts, .filter-scripts .resources-category-scripts,
.filter-all .resources-category-xhr, .filter-xhr .resources-category-xhr,
.filter-all .resources-category-fonts, .filter-fonts .resources-category-fonts,
+.filter-all .resources-category-websockets, .filter-websockets .resources-category-websockets,
.filter-all .resources-category-other, .filter-other .resources-category-other,
.resource-sidebar-tree-item.selected {
display: list-item;
@@ -2920,6 +2926,15 @@ button.enable-toggle-status-bar-item.toggled-on .glyph {
-webkit-border-image: url(Images/timelineHollowPillYellow.png) 6 7 6 7;
}
+/* FIXME: Create bar images for WebSocket. */
+.resources-category-websockets .resources-graph-bar {
+ -webkit-border-image: url(Images/timelinePillGray.png) 6 7 6 7;
+}
+
+.resources-category-websockets.resource-cached .resources-graph-bar {
+ -webkit-border-image: url(Images/timelineHollowPillGray.png) 6 7 6 7;
+}
+
#resource-views {
position: absolute;
top: 23px;
diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js
index 840745f..f6fa06b 100644
--- a/WebCore/inspector/front-end/inspector.js
+++ b/WebCore/inspector/front-end/inspector.js
@@ -403,45 +403,44 @@ var WebInspector = {
}
},
- get hoveredDOMNode()
+ highlightDOMNode: function(nodeId)
{
- return this._hoveredDOMNode;
- },
+ if ("_hideDOMNodeHighlightTimeout" in this) {
+ clearTimeout(this._hideDOMNodeHighlightTimeout);
+ delete this._hideDOMNodeHighlightTimeout;
+ }
- set hoveredDOMNode(x)
- {
- if (this._hoveredDOMNode === x)
+ if (this._highlightedDOMNodeId === nodeId)
return;
- this._hoveredDOMNode = x;
-
- if (this._hoveredDOMNode)
- this._updateHoverHighlightSoon(this.showingDOMNodeHighlight ? 50 : 500);
+ this._highlightedDOMNodeId = nodeId;
+ if (nodeId)
+ InspectorBackend.highlightDOMNode(nodeId);
else
- this._updateHoverHighlight();
+ InspectorBackend.hideDOMNodeHighlight();
},
- _updateHoverHighlightSoon: function(delay)
+ highlightDOMNodeForTwoSeconds: function(nodeId)
{
- if ("_updateHoverHighlightTimeout" in this)
- clearTimeout(this._updateHoverHighlightTimeout);
- this._updateHoverHighlightTimeout = setTimeout(this._updateHoverHighlight.bind(this), delay);
+ this.highlightDOMNode(nodeId);
+ this._hideDOMNodeHighlightTimeout = setTimeout(this.highlightDOMNode.bind(this, 0), 2000);
},
- _updateHoverHighlight: function()
+ wireElementWithDOMNode: function(element, nodeId)
{
- if ("_updateHoverHighlightTimeout" in this) {
- clearTimeout(this._updateHoverHighlightTimeout);
- delete this._updateHoverHighlightTimeout;
- }
+ element.addEventListener("click", this._updateFocusedNode.bind(this, nodeId), false);
+ element.addEventListener("mouseover", this.highlightDOMNode.bind(this, nodeId), false);
+ element.addEventListener("mouseout", this.highlightDOMNode.bind(this, 0), false);
+ },
- if (this._hoveredDOMNode) {
- InspectorBackend.highlightDOMNode(this._hoveredDOMNode.id);
- this.showingDOMNodeHighlight = true;
- } else {
- InspectorBackend.hideDOMNodeHighlight();
- this.showingDOMNodeHighlight = false;
- }
+ _updateFocusedNode: function(nodeId)
+ {
+ var node = WebInspector.domAgent.nodeForId(nodeId);
+ if (!node)
+ return;
+
+ this.currentPanel = this.panels.elements;
+ this.panels.elements.focusedDOMNode = node;
}
}
@@ -517,6 +516,7 @@ WebInspector.doLoadedDone = function()
scripts: new WebInspector.ResourceCategory("scripts", WebInspector.UIString("Scripts"), "rgb(255,121,0)"),
xhr: new WebInspector.ResourceCategory("xhr", WebInspector.UIString("XHR"), "rgb(231,231,10)"),
fonts: new WebInspector.ResourceCategory("fonts", WebInspector.UIString("Fonts"), "rgb(255,82,62)"),
+ websocket: new WebInspector.ResourceCategory("websockets", WebInspector.UIString("WebSocket"), "rgb(186,186,186)"), // FIXME: Decide the color.
other: new WebInspector.ResourceCategory("other", WebInspector.UIString("Other"), "rgb(186,186,186)")
};
@@ -582,6 +582,16 @@ WebInspector.doLoadedDone = function()
this.extensionServer.initExtensions();
+ function populateInspectorState(inspectorState)
+ {
+ WebInspector.monitoringXHREnabled = inspectorState.monitoringXHREnabled;
+ if (inspectorState.resourceTrackingEnabled)
+ WebInspector.panels.resources.resourceTrackingWasEnabled();
+ else
+ WebInspector.panels.resources.resourceTrackingWasDisabled();
+ }
+ InspectorBackend.getInspectorState(populateInspectorState);
+
InspectorBackend.populateScriptObjects();
// As a DOMAgent method, this needs to happen after the frontend has loaded and the agent is available.
@@ -720,22 +730,10 @@ WebInspector.disconnectFromBackend = function()
InspectorFrontendHost.disconnectFromBackend();
}
-WebInspector.documentMouseOver = function(event)
-{
- if (event.target.tagName !== "A")
- return;
-
- const anchor = event.target;
- if (!anchor.hasStyleClass("webkit-html-resource-link"))
- return;
- if (anchor.href && anchor.href.indexOf("/data:") != -1)
- return;
-}
-
WebInspector.documentClick = function(event)
{
var anchor = event.target.enclosingNodeOrSelfWithNodeName("a");
- if (!anchor)
+ if (!anchor || anchor.target === "_blank")
return;
// Prevent the link from navigating, since we don't do any navigation by following links normally.
@@ -788,6 +786,16 @@ WebInspector.documentClick = function(event)
followLink();
}
+WebInspector.openResource = function(resourceURL, inResourcesPanel)
+{
+ var resource = WebInspector.resourceForURL(resourceURL);
+ if (inResourcesPanel && resource) {
+ WebInspector.panels.resources.showResource(resource);
+ WebInspector.showPanel("resources");
+ } else
+ InspectorBackend.openInInspectedWindow(resource ? resource.url : resourceURL);
+}
+
WebInspector._registerShortcuts = function()
{
var shortcut = WebInspector.KeyboardShortcut;
@@ -1223,6 +1231,8 @@ WebInspector.updateResource = function(payload)
resource.requestMethod = payload.requestMethod;
resource.requestFormData = payload.requestFormData;
resource.documentURL = payload.documentURL;
+ if (typeof payload.webSocketRequestKey3 !== "undefined")
+ resource.webSocketRequestKey3 = payload.webSocketRequestKey3;
if (resource.mainResource)
this.mainResource = resource;
@@ -1247,6 +1257,8 @@ WebInspector.updateResource = function(payload)
resource.connectionReused = payload.connectionReused;
resource.timing = payload.timing;
resource.cached = payload.cached;
+ if (typeof payload.webSocketChallengeResponse !== "undefined")
+ resource.webSocketChallengeResponse = payload.webSocketChallengeResponse;
}
if (payload.didTypeChange) {
@@ -1370,16 +1382,6 @@ WebInspector.updateNetworkState = function(isNowOnline)
this.panels.storage.updateNetworkState(isNowOnline);
}
-WebInspector.resourceTrackingWasEnabled = function()
-{
- this.panels.resources.resourceTrackingWasEnabled();
-}
-
-WebInspector.resourceTrackingWasDisabled = function()
-{
- this.panels.resources.resourceTrackingWasDisabled();
-}
-
WebInspector.searchingForNodeWasEnabled = function()
{
this.panels.elements.searchingForNodeWasEnabled();
@@ -1390,16 +1392,6 @@ WebInspector.searchingForNodeWasDisabled = function()
this.panels.elements.searchingForNodeWasDisabled();
}
-WebInspector.monitoringXHRWasEnabled = function()
-{
- this.monitoringXHREnabled = true;
-}
-
-WebInspector.monitoringXHRWasDisabled = function()
-{
- this.monitoringXHREnabled = false;
-}
-
WebInspector.attachDebuggerWhenShown = function()
{
this.panels.scripts.attachDebuggerWhenShown();
@@ -1447,7 +1439,7 @@ WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLin
WebInspector.pausedScript = function(details)
{
- this.panels.scripts.debuggerPaused(details.callFrames);
+ this.panels.scripts.debuggerPaused(details);
InspectorFrontendHost.bringToFront();
}
@@ -1474,7 +1466,7 @@ WebInspector.reset = function()
this.resourceURLMap = {};
this.cookieDomains = {};
this.applicationCacheDomains = {};
- this.hoveredDOMNode = null;
+ this.highlightDOMNode(0);
delete this.mainResource;
@@ -1683,13 +1675,8 @@ WebInspector.drawLoadingPieChart = function(canvas, percent) {
WebInspector.updateFocusedNode = function(nodeId)
{
- var node = WebInspector.domAgent.nodeForId(nodeId);
- if (!node)
- // FIXME: Should we deselect if null is passed in?
- return;
-
- this.currentPanel = this.panels.elements;
- this.panels.elements.focusedDOMNode = node;
+ this._updateFocusedNode(nodeId);
+ this.highlightDOMNodeForTwoSeconds(nodeId);
}
WebInspector.displayNameForURL = function(url)
@@ -1804,7 +1791,6 @@ WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal, too
a.title = url;
else if (typeof tooltipText !== "string" || tooltipText.length)
a.title = tooltipText;
- a.target = "_blank";
a.textContent = linkText;
return a;
@@ -1828,6 +1814,29 @@ WebInspector.linkifyResourceAsNode = function(url, preferredPanel, lineNumber, c
return node;
}
+WebInspector.resourceURLForRelatedNode = function(node, url)
+{
+ if (!url || url.indexOf("://") > 0)
+ return url;
+
+ for (var frameOwnerCandidate = node; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) {
+ if (frameOwnerCandidate.documentURL) {
+ var result = WebInspector.completeURL(frameOwnerCandidate.documentURL, url);
+ if (result)
+ return result;
+ break;
+ }
+ }
+
+ // documentURL not found or has bad value
+ for (var resourceURL in WebInspector.resourceURLMap) {
+ var match = resourceURL.match(WebInspector.URLRegExp);
+ if (match && match[4] === url)
+ return resourceURL;
+ }
+ return url;
+},
+
WebInspector.completeURL = function(baseURL, href)
{
var match = baseURL.match(WebInspector.URLRegExp);
@@ -1850,7 +1859,6 @@ WebInspector.addMainEventListeners = function(doc)
doc.defaultView.addEventListener("focus", this.windowFocused.bind(this), false);
doc.defaultView.addEventListener("blur", this.windowBlurred.bind(this), false);
doc.addEventListener("click", this.documentClick.bind(this), true);
- doc.addEventListener("mouseover", this.documentMouseOver.bind(this), true);
}
WebInspector._searchFieldManualFocus = function(event)
@@ -2008,6 +2016,11 @@ WebInspector.UIString = function(string)
return String.vsprintf(string, Array.prototype.slice.call(arguments, 1));
}
+WebInspector.formatLocalized = function(format, substitutions, formatters, initialValue, append)
+{
+ return String.format(WebInspector.UIString(format), substitutions, formatters, initialValue, append);
+}
+
WebInspector.isMac = function()
{
if (!("_isMac" in this))
diff --git a/WebCore/inspector/front-end/treeoutline.js b/WebCore/inspector/front-end/treeoutline.js
index 5891401..c2a3fe7 100644
--- a/WebCore/inspector/front-end/treeoutline.js
+++ b/WebCore/inspector/front-end/treeoutline.js
@@ -651,6 +651,7 @@ TreeElement.treeElementToggled = function(event)
else
element.treeElement.expand();
}
+ event.stopPropagation();
}
TreeElement.treeElementDoubleClicked = function(event)
diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js
index e8adff6..5e41da6 100644
--- a/WebCore/inspector/front-end/utilities.js
+++ b/WebCore/inspector/front-end/utilities.js
@@ -984,3 +984,12 @@ function createSearchRegex(query)
}
return new RegExp(regex, "i");
}
+
+function offerFileForDownload(contents)
+{
+ var builder = new BlobBuilder();
+ builder.append(contents);
+ var blob = builder.getBlob("application/octet-stream");
+ var url = window.createBlobURL(blob);
+ window.open(url);
+}