diff options
Diffstat (limited to 'WebCore/inspector')
46 files changed, 1512 insertions, 571 deletions
diff --git a/WebCore/inspector/InspectorBackend.cpp b/WebCore/inspector/InspectorBackend.cpp index aed8f2b..36f41b8 100644 --- a/WebCore/inspector/InspectorBackend.cpp +++ b/WebCore/inspector/InspectorBackend.cpp @@ -254,6 +254,18 @@ void InspectorBackend::getProfile(long callId, unsigned uid) if (m_inspectorController) m_inspectorController->getProfile(callId, uid); } + +void InspectorBackend::removeProfile(unsigned uid) +{ + if (m_inspectorController) + m_inspectorController->removeProfile(uid); +} + +void InspectorBackend::clearProfiles() +{ + if (m_inspectorController) + m_inspectorController->clearProfiles(); +} #endif void InspectorBackend::setInjectedScriptSource(const String& source) @@ -363,6 +375,18 @@ void InspectorBackend::getComputedStyle(long callId, long nodeId) domAgent->getComputedStyle(callId, nodeId); } +void InspectorBackend::getStyleSheet(long callId, long styleSheetId) +{ + if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) + domAgent->getStyleSheet(callId, styleSheetId); +} + +void InspectorBackend::getRuleRangesForStyleSheetId(long callId, long styleSheetId) +{ + if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) + domAgent->getRuleRangesForStyleSheetId(callId, styleSheetId); +} + void InspectorBackend::applyStyleText(long callId, long styleId, const String& styleText, const String& propertyName) { if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) diff --git a/WebCore/inspector/InspectorBackend.h b/WebCore/inspector/InspectorBackend.h index 7331843..0eb8e4c 100644 --- a/WebCore/inspector/InspectorBackend.h +++ b/WebCore/inspector/InspectorBackend.h @@ -98,6 +98,9 @@ public: void getProfileHeaders(long callId); void getProfile(long callId, unsigned uid); + + void removeProfile(unsigned uid); + void clearProfiles(); #endif void setInjectedScriptSource(const String& source); @@ -118,6 +121,8 @@ public: void getAllStyles(long callId); void getInlineStyle(long callId, long nodeId); void getComputedStyle(long callId, long nodeId); + void getStyleSheet(long callId, long styleSheetId); + void getRuleRangesForStyleSheetId(long callId, long styleSheetId); void applyStyleText(long callId, long styleId, const String& styleText, const String& propertyName); void setStyleText(long callId, long styleId, const String& cssText); void setStyleProperty(long callId, long styleId, const String& name, const String& value); diff --git a/WebCore/inspector/InspectorBackend.idl b/WebCore/inspector/InspectorBackend.idl index cf0fe01..e8cfdb9 100644 --- a/WebCore/inspector/InspectorBackend.idl +++ b/WebCore/inspector/InspectorBackend.idl @@ -73,6 +73,9 @@ module core { void getProfileHeaders(in long callId); void getProfile(in long callId, in unsigned long uid); + + void removeProfile(in unsigned long uid); + void clearProfiles(); #endif void setInjectedScriptSource(in DOMString scriptSource); void dispatchOnInjectedScript(in long callId, in long injectedScriptId, in DOMString methodName, in DOMString arguments, in boolean async); @@ -95,6 +98,8 @@ module core { void getAllStyles(in long callId); void getInlineStyle(in long callId, in long nodeId); void getComputedStyle(in long callId, in long nodeId); + void getStyleSheet(in long callId, in long styleSheetId); + void getRuleRangesForStyleSheetId(in long callId, in long styleSheetId); void applyStyleText(in long callId, in long styleId, in DOMString styleText, in DOMString propertyName); void setStyleText(in long callId, in long styleId, in DOMString styleText); void setStyleProperty(in long callId, in long styleId, in DOMString name, in DOMString value); diff --git a/WebCore/inspector/InspectorCSSStore.cpp b/WebCore/inspector/InspectorCSSStore.cpp index e53688b..a080eda 100644 --- a/WebCore/inspector/InspectorCSSStore.cpp +++ b/WebCore/inspector/InspectorCSSStore.cpp @@ -29,14 +29,27 @@ #include "config.h" #include "InspectorCSSStore.h" +#include "CSSMutableStyleDeclaration.h" +#include "CSSParser.h" +#include "CSSRuleList.h" #include "CSSStyleDeclaration.h" #include "CSSStyleRule.h" #include "CSSStyleSheet.h" +#include "HTMLHeadElement.h" +#include "InspectorController.h" +#include "InspectorFrontend.h" +#include "InspectorResource.h" #include "PlatformString.h" +#include "ScriptObject.h" +#include "StyleSheetList.h" namespace WebCore { -InspectorCSSStore::InspectorCSSStore() +InspectorCSSStore::InspectorCSSStore(InspectorController* inspectorController) + : m_inspectorController(inspectorController) + , m_lastStyleId(1) + , m_lastStyleSheetId(1) + , m_lastRuleId(1) { } @@ -46,12 +59,164 @@ InspectorCSSStore::~InspectorCSSStore() void InspectorCSSStore::reset() { - styleToId.clear(); - idToStyle.clear(); - ruleToId.clear(); - idToRule.clear(); - idToDisabledStyle.clear(); - inspectorStyleSheet = 0; + m_styleToId.clear(); + m_idToStyle.clear(); + m_ruleToId.clear(); + m_idToRule.clear(); + deleteAllValues(m_styleSheetToOffsets); + m_styleSheetToOffsets.clear(); + m_styleSheetToId.clear(); + m_idToStyleSheet.clear(); + m_idToDisabledStyle.clear(); + m_documentNodeToInspectorStyleSheetMap.clear(); + + m_lastStyleId = 1; + m_lastStyleSheetId = 1; + m_lastRuleId = 1; +} + +void InspectorCSSStore::removeDocument(Document* doc) +{ + m_documentNodeToInspectorStyleSheetMap.remove(doc); +} + +CSSStyleSheet* InspectorCSSStore::inspectorStyleSheet(Document* ownerDocument, bool createIfAbsent, long callId) +{ + DocumentToStyleSheetMap::iterator it = m_documentNodeToInspectorStyleSheetMap.find(ownerDocument); + if (it != m_documentNodeToInspectorStyleSheetMap.end()) + return it->second.get(); + if (!createIfAbsent) + return 0; + ExceptionCode ec = 0; + RefPtr<Element> styleElement = ownerDocument->createElement("style", ec); + if (!ec) + styleElement->setAttribute("type", "text/css", ec); + if (!ec) + ownerDocument->head()->appendChild(styleElement, ec); + if (ec) { + m_inspectorController->inspectorFrontend()->didAddRule(callId, ScriptValue::undefined(), false); + return 0; + } + StyleSheetList* styleSheets = ownerDocument->styleSheets(); + StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1); + if (!styleSheet->isCSSStyleSheet()) { + m_inspectorController->inspectorFrontend()->didAddRule(callId, ScriptValue::undefined(), false); + return 0; + } + CSSStyleSheet* inspectorStyleSheet = static_cast<CSSStyleSheet*>(styleSheet); + m_documentNodeToInspectorStyleSheetMap.set(ownerDocument, inspectorStyleSheet); + return inspectorStyleSheet; +} + +HashMap<long, SourceRange> InspectorCSSStore::getRuleRangesForStyleSheet(CSSStyleSheet* styleSheet) +{ + if (!styleSheet) + return HashMap<long, SourceRange>(); + RefPtr<CSSRuleList> originalRuleList = CSSRuleList::create(styleSheet, false); + StyleSheetToOffsetsMap::iterator it = m_styleSheetToOffsets.find(styleSheet); + HashMap<long, SourceRange> result; + Vector<SourceRange>* offsetVector = 0; + if (it == m_styleSheetToOffsets.end()) { + InspectorResource* resource = m_inspectorController->resourceForURL(styleSheet->finalURL().string()); + if (resource) { + offsetVector = new Vector<SourceRange>; + RefPtr<CSSStyleSheet> newStyleSheet = CSSStyleSheet::create(styleSheet->ownerNode()); + CSSParser p; + CSSParser::StyleRuleRanges ruleRangeMap; + p.parseSheet(newStyleSheet.get(), resource->sourceString(), &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); + } + } else + offsetVector = it->second; + if (!offsetVector) + return HashMap<long, SourceRange>(); + unsigned ruleIndex = 0; + for (unsigned i = 0, length = styleSheet->length(); i < length; ++i) { + ASSERT(ruleIndex < offsetVector->size()); + CSSStyleRule* rule = asCSSStyleRule(styleSheet->item(i)); + if (!rule) + continue; + result.set(bindRule(rule), offsetVector->at(ruleIndex)); + ruleIndex++; + } + return result; +} + +CSSStyleRule* InspectorCSSStore::asCSSStyleRule(StyleBase* styleBase) +{ + if (!styleBase->isStyleRule()) + return 0; + CSSRule* rule = static_cast<CSSRule*>(styleBase); + if (rule->type() != CSSRule::STYLE_RULE) + return 0; + return static_cast<CSSStyleRule*>(rule); +} + +DisabledStyleDeclaration* InspectorCSSStore::disabledStyleForId(long styleId, bool createIfAbsent) +{ + IdToDisabledStyleMap::iterator it = m_idToDisabledStyle.find(styleId); + if (it == m_idToDisabledStyle.end() && createIfAbsent) + it = m_idToDisabledStyle.set(styleId, DisabledStyleDeclaration()).first; + return it == m_idToDisabledStyle.end() ? 0 : &(it->second); +} + +CSSStyleDeclaration* InspectorCSSStore::styleForId(long styleId) +{ + IdToStyleMap::iterator it = m_idToStyle.find(styleId); + return it == m_idToStyle.end() ? 0 : it->second.get(); +} + +CSSStyleSheet* InspectorCSSStore::styleSheetForId(long styleSheetId) +{ + IdToStyleSheetMap::iterator it = m_idToStyleSheet.find(styleSheetId); + return it == m_idToStyleSheet.end() ? 0 : it->second.get(); +} + +CSSStyleRule* InspectorCSSStore::ruleForId(long ruleId) +{ + IdToRuleMap::iterator it = m_idToRule.find(ruleId); + return it == m_idToRule.end() ? 0 : it->second.get(); +} + +long InspectorCSSStore::bindStyle(CSSStyleDeclaration* style) +{ + long id = m_styleToId.get(style); + if (!id) { + id = m_lastStyleId++; + m_idToStyle.set(id, style); + m_styleToId.set(style, id); + } + return id; +} + +long InspectorCSSStore::bindStyleSheet(CSSStyleSheet* styleSheet) +{ + long id = m_styleSheetToId.get(styleSheet); + if (!id) { + id = m_lastStyleSheetId++; + m_idToStyleSheet.set(id, styleSheet); + m_styleSheetToId.set(styleSheet, id); + } + return id; +} + +long InspectorCSSStore::bindRule(CSSStyleRule* rule) +{ + long id = m_ruleToId.get(rule); + if (!id) { + id = m_lastRuleId++; + m_idToRule.set(id, rule); + m_ruleToId.set(rule, id); + } + return id; } } // namespace WebCore diff --git a/WebCore/inspector/InspectorCSSStore.h b/WebCore/inspector/InspectorCSSStore.h index d290fad..4b7ef51 100644 --- a/WebCore/inspector/InspectorCSSStore.h +++ b/WebCore/inspector/InspectorCSSStore.h @@ -36,30 +36,65 @@ namespace WebCore { +class Document; +class InspectorController; +class InspectorFrontend; +class CSSMutableStyleDeclaration; class CSSStyleDeclaration; +class CSSRuleList; class CSSStyleRule; class CSSStyleSheet; class String; +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*, long> StyleSheetToIdMap; +typedef HashMap<long, RefPtr<CSSStyleSheet> > IdToStyleSheetMap; typedef HashMap<long, DisabledStyleDeclaration> IdToDisabledStyleMap; +typedef HashMap<RefPtr<Document>, RefPtr<CSSStyleSheet> > DocumentToStyleSheetMap; -struct InspectorCSSStore { - InspectorCSSStore(); +class InspectorCSSStore { + +public: + InspectorCSSStore(InspectorController* inspectorController); ~InspectorCSSStore(); void reset(); + HashMap<long, SourceRange> getRuleRangesForStyleSheet(CSSStyleSheet*); + CSSStyleDeclaration* styleForId(long styleId); + CSSStyleSheet* styleSheetForId(long styleSheetId); + CSSStyleRule* ruleForId(long styleRuleId); + DisabledStyleDeclaration* disabledStyleForId(long styleId, bool createIfAbsent); + CSSStyleSheet* inspectorStyleSheet(Document* ownerDocument, bool createIfAbsent, long callId); + void removeDocument(Document*); + + long bindRule(CSSStyleRule* rule); + long bindStyle(CSSStyleDeclaration* style); + long bindStyleSheet(CSSStyleSheet* styleSheet); + +private: + static CSSStyleRule* asCSSStyleRule(StyleBase*); + + StyleToIdMap m_styleToId; + IdToStyleMap m_idToStyle; + RuleToIdMap m_ruleToId; + IdToRuleMap m_idToRule; + StyleSheetToOffsetsMap m_styleSheetToOffsets; + StyleSheetToIdMap m_styleSheetToId; + IdToStyleSheetMap m_idToStyleSheet; + IdToDisabledStyleMap m_idToDisabledStyle; + DocumentToStyleSheetMap m_documentNodeToInspectorStyleSheetMap; - StyleToIdMap styleToId; - IdToStyleMap idToStyle; - RuleToIdMap ruleToId; - IdToRuleMap idToRule; - IdToDisabledStyleMap idToDisabledStyle; - RefPtr<CSSStyleSheet> inspectorStyleSheet; + InspectorController* m_inspectorController; + long m_lastStyleId; + long m_lastStyleSheetId; + long m_lastRuleId; }; } // namespace WebCore diff --git a/WebCore/inspector/InspectorController.cpp b/WebCore/inspector/InspectorController.cpp index 3b36a4a..f38f8d0 100644 --- a/WebCore/inspector/InspectorController.cpp +++ b/WebCore/inspector/InspectorController.cpp @@ -145,7 +145,7 @@ InspectorController::InspectorController(Page* page, InspectorClient* client) : m_inspectedPage(page) , m_client(client) , m_openingFrontend(false) - , m_cssStore(new InspectorCSSStore()) + , m_cssStore(new InspectorCSSStore(this)) , m_expiredConsoleMessageCount(0) , m_showAfterVisible(CurrentPanel) , m_groupLevel(0) @@ -177,6 +177,7 @@ InspectorController::~InspectorController() // These should have been cleared in inspectedPageDestroyed(). ASSERT(!m_client); ASSERT(!m_inspectedPage); + ASSERT(!m_highlightedNode); deleteAllValues(m_frameResources); deleteAllValues(m_consoleMessages); @@ -195,6 +196,8 @@ void InspectorController::inspectedPageDestroyed() if (m_frontend) m_frontend->inspectedPageDestroyed(); + hideHighlight(); + ASSERT(m_inspectedPage); m_inspectedPage = 0; @@ -336,11 +339,11 @@ void InspectorController::clearConsoleMessages() m_frontend->clearConsoleMessages(); } -void InspectorController::startGroup(MessageSource source, ScriptCallStack* callStack) +void InspectorController::startGroup(MessageSource source, ScriptCallStack* callStack, bool collapsed) { ++m_groupLevel; - addConsoleMessage(callStack->state(), new ConsoleMessage(source, StartGroupMessageType, LogMessageLevel, callStack, m_groupLevel)); + addConsoleMessage(callStack->state(), new ConsoleMessage(source, collapsed ? StartGroupCollapsedMessageType : StartGroupMessageType, LogMessageLevel, callStack, m_groupLevel)); } void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL) @@ -776,6 +779,15 @@ InspectorResource* InspectorController::getTrackedResource(unsigned long identif return 0; } +InspectorResource* InspectorController::resourceForURL(const String& url) +{ + for (InspectorController::ResourcesMap::iterator resIt = m_resources.begin(); resIt != m_resources.end(); ++resIt) { + if (resIt->second->requestURL().string() == url) + return resIt->second.get(); + } + return 0; +} + void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const CachedResource* cachedResource) { if (!enabled()) @@ -1376,6 +1388,25 @@ void InspectorController::addStartProfilingMessageToConsole(const String& title, addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL); } +void InspectorController::removeProfile(unsigned uid) +{ + if (!enabled()) + return; + + if (m_profiles.contains(uid)) + m_profiles.remove(uid); +} + +void InspectorController::clearProfiles() +{ + if (!enabled()) + return; + + m_profiles.clear(); + m_currentUserInitiatedProfileNumber = 1; + m_nextUserInitiatedProfileNumber = 1; +} + void InspectorController::getProfileHeaders(long callId) { if (!m_frontend) @@ -1628,9 +1659,8 @@ void InspectorController::failedToParseSource(const String& url, const String& d m_frontend->failedToParseScriptSource(url, data, firstLine, errorLine, errorMessage); } -void InspectorController::didPause() +void InspectorController::didPause(ScriptState* scriptState) { - ScriptState* scriptState = ScriptDebugServer::shared().currentCallFrameState(); ASSERT(scriptState); InjectedScript injectedScript = m_injectedScriptHost->injectedScriptFor(scriptState); RefPtr<SerializedScriptValue> callFrames = injectedScript.callFrames(); diff --git a/WebCore/inspector/InspectorController.h b/WebCore/inspector/InspectorController.h index a90b299..a2c8a77 100644 --- a/WebCore/inspector/InspectorController.h +++ b/WebCore/inspector/InspectorController.h @@ -6,13 +6,13 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. + * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -65,7 +65,7 @@ class InjectedScript; class InjectedScriptHost; class InspectorBackend; class InspectorClient; -struct InspectorCSSStore; +class InspectorCSSStore; class InspectorFrontend; class InspectorFrontendClient; class InspectorTimelineAgent; @@ -147,7 +147,7 @@ public: void setInspectorFrontendClient(PassOwnPtr<InspectorFrontendClient> client); bool hasInspectorFrontendClient() const { return m_inspectorFrontendClient; } - + void inspectedWindowScriptObjectCleared(Frame*); bool windowVisible(); @@ -203,6 +203,8 @@ public: #endif const ResourcesMap& resources() const { return m_resources; } + InspectorResource* resourceForURL(const String& url); + InspectorFrontend* inspectorFrontend() { return m_frontend.get(); } void drawNodeHighlight(GraphicsContext&) const; @@ -211,7 +213,7 @@ public: void startTiming(const String& title); bool stopTiming(const String& title, double& elapsed); - void startGroup(MessageSource source, ScriptCallStack* callFrame); + void startGroup(MessageSource source, ScriptCallStack* callFrame, bool collapsed = false); void endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL); void markTimeline(const String& message); @@ -220,6 +222,8 @@ public: void addProfile(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL); void addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL); void addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL); + void removeProfile(unsigned); + void clearProfiles(); bool isRecordingUserInitiatedProfile() const { return m_recordingUserInitiatedProfile; } @@ -241,7 +245,7 @@ public: virtual void didParseSource(const String& sourceID, const String& url, const String& data, int firstLine); virtual void failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage); - virtual void didPause(); + virtual void didPause(ScriptState*); virtual void didContinue(); #endif @@ -258,14 +262,12 @@ private: friend class InspectorBackend; friend class InjectedScriptHost; - + void populateScriptObjects(); void unbindAllResources(); - - // Following are used from InspectorBackend and internally. - void setSearchingForNode(bool enabled); // Following are used from InspectorBackend and internally. + void setSearchingForNode(bool enabled); void storeLastActivePanel(const String& panelName); InspectorDOMAgent* domAgent() { return m_domAgent.get(); } void releaseDOMAgent(); @@ -292,7 +294,7 @@ private: #if ENABLE(DOM_STORAGE) InspectorDOMStorageResource* getDOMStorageResourceForId(long storageId); #endif - + ScriptObject buildObjectForCookie(const Cookie&); ScriptArray buildArrayForCookies(ListHashSet<Cookie>&); diff --git a/WebCore/inspector/InspectorDOMAgent.cpp b/WebCore/inspector/InspectorDOMAgent.cpp index 0833e15..338dc33 100644 --- a/WebCore/inspector/InspectorDOMAgent.cpp +++ b/WebCore/inspector/InspectorDOMAgent.cpp @@ -52,7 +52,6 @@ #include "EventNames.h" #include "EventTarget.h" #include "HTMLFrameOwnerElement.h" -#include "HTMLHeadElement.h" #include "InspectorFrontend.h" #include "markup.h" #include "MutationEvent.h" @@ -78,8 +77,6 @@ InspectorDOMAgent::InspectorDOMAgent(InspectorCSSStore* cssStore, InspectorFront , m_cssStore(cssStore) , m_frontend(frontend) , m_lastNodeId(1) - , m_lastStyleId(1) - , m_lastRuleId(1) { } @@ -188,6 +185,7 @@ void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap) if (node->isFrameOwnerElement()) { const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node); stopListening(frameOwner->contentDocument()); + cssStore()->removeDocument(frameOwner->contentDocument()); } long id = nodesMap->get(node); @@ -785,7 +783,7 @@ void InspectorDOMAgent::getStyles(long callId, long nodeId, bool authorOnly) CSSStyleSelector* selector = element->ownerDocument()->styleSelector(); RefPtr<CSSRuleList> matchedRules = selector->styleRulesForElement(element, authorOnly); - result.set("matchedCSSRules", buildArrayForCSSRules(matchedRules.get())); + result.set("matchedCSSRules", buildArrayForCSSRules(node->ownerDocument(), matchedRules.get())); result.set("styleAttributes", buildObjectForAttributeStyles(element)); result.set("pseudoElements", buildArrayForPseudoElements(element, authorOnly)); @@ -800,7 +798,7 @@ void InspectorDOMAgent::getStyles(long callId, long nodeId, bool authorOnly) CSSStyleSelector* parentSelector = parentElement->ownerDocument()->styleSelector(); RefPtr<CSSRuleList> parentMatchedRules = parentSelector->styleRulesForElement(parentElement, authorOnly); - parentStyle.set("matchedCSSRules", buildArrayForCSSRules(parentMatchedRules.get())); + parentStyle.set("matchedCSSRules", buildArrayForCSSRules(parentElement->ownerDocument(), parentMatchedRules.get())); parentElement = parentElement->parentElement(); currentStyle = parentStyle; @@ -817,12 +815,46 @@ void InspectorDOMAgent::getAllStyles(long callId) for (unsigned i = 0; i < list->length(); ++i) { StyleSheet* styleSheet = list->item(i); if (styleSheet->isCSSStyleSheet()) - result.set(counter++, buildObjectForStyleSheet(static_cast<CSSStyleSheet*>(styleSheet))); + result.set(counter++, buildObjectForStyleSheet((*it).get(), static_cast<CSSStyleSheet*>(styleSheet))); } } m_frontend->didGetAllStyles(callId, result); } +void InspectorDOMAgent::getStyleSheet(long callId, long styleSheetId) +{ + CSSStyleSheet* styleSheet = cssStore()->styleSheetForId(styleSheetId); + if (styleSheet && styleSheet->doc()) + m_frontend->didGetStyleSheet(callId, buildObjectForStyleSheet(styleSheet->doc(), styleSheet)); + else + m_frontend->didGetStyleSheet(callId, ScriptObject::undefined()); +} + +void InspectorDOMAgent::getRuleRangesForStyleSheetId(long callId, long styleSheetId) +{ + CSSStyleSheet* styleSheet = cssStore()->styleSheetForId(styleSheetId); + if (styleSheet && styleSheet->doc()) { + HashMap<long, SourceRange> ruleRanges = cssStore()->getRuleRangesForStyleSheet(styleSheet); + if (!ruleRanges.size()) { + m_frontend->didGetStyleSheet(callId, ScriptObject::undefined()); + return; + } + ScriptObject result = m_frontend->newScriptObject(); + for (HashMap<long, SourceRange>::iterator it = ruleRanges.begin(); it != ruleRanges.end(); ++it) { + if (it->second.second) { + ScriptObject ruleRange = m_frontend->newScriptObject(); + result.set(String::number(it->first).utf8().data(), ruleRange); + ScriptObject bodyRange = m_frontend->newScriptObject(); + ruleRange.set("bodyRange", bodyRange); + bodyRange.set("start", it->second.first); + bodyRange.set("end", it->second.second); + } + } + m_frontend->didGetStyleSheet(callId, result); + } else + m_frontend->didGetStyleSheet(callId, ScriptObject::undefined()); +} + void InspectorDOMAgent::getInlineStyle(long callId, long nodeId) { Node* node = nodeForId(nodeId); @@ -867,14 +899,14 @@ ScriptObject InspectorDOMAgent::buildObjectForAttributeStyles(Element* element) return styleAttributes; } -ScriptArray InspectorDOMAgent::buildArrayForCSSRules(CSSRuleList* matchedRules) +ScriptArray InspectorDOMAgent::buildArrayForCSSRules(Document* ownerDocument, CSSRuleList* matchedRules) { ScriptArray matchedCSSRules = m_frontend->newScriptArray(); unsigned counter = 0; for (unsigned i = 0; matchedRules && i < matchedRules->length(); ++i) { CSSRule* rule = matchedRules->item(i); if (rule->type() == CSSRule::STYLE_RULE) - matchedCSSRules.set(counter++, buildObjectForRule(static_cast<CSSStyleRule*>(rule))); + matchedCSSRules.set(counter++, buildObjectForRule(ownerDocument, static_cast<CSSStyleRule*>(rule))); } return matchedCSSRules; } @@ -891,7 +923,7 @@ ScriptArray InspectorDOMAgent::buildArrayForPseudoElements(Element* element, boo if (matchedRules && matchedRules->length()) { ScriptObject pseudoStyles = m_frontend->newScriptObject(); pseudoStyles.set("pseudoId", static_cast<int>(pseudoId)); - pseudoStyles.set("rules", buildArrayForCSSRules(matchedRules.get())); + pseudoStyles.set("rules", buildArrayForCSSRules(element->ownerDocument(), matchedRules.get())); result.set(counter++, pseudoStyles); } } @@ -900,18 +932,17 @@ ScriptArray InspectorDOMAgent::buildArrayForPseudoElements(Element* element, boo void InspectorDOMAgent::applyStyleText(long callId, long styleId, const String& styleText, const String& propertyName) { - IdToStyleMap::iterator it = cssStore()->idToStyle.find(styleId); - if (it == cssStore()->idToStyle.end()) { + CSSStyleDeclaration* style = cssStore()->styleForId(styleId); + if (!style) { m_frontend->didApplyStyleText(callId, false, ScriptValue::undefined(), m_frontend->newScriptArray()); return; } // Remove disabled property entry for property with given name. - IdToDisabledStyleMap::iterator disabledIt = cssStore()->idToDisabledStyle.find(styleId); - if (disabledIt != cssStore()->idToDisabledStyle.end()) - disabledIt->second.remove(propertyName); + DisabledStyleDeclaration* disabledStyle = cssStore()->disabledStyleForId(styleId, false); + if (disabledStyle) + disabledStyle->remove(propertyName); - CSSStyleDeclaration* style = it->second.get(); int styleTextLength = styleText.length(); RefPtr<CSSMutableStyleDeclaration> tempMutableStyle = CSSMutableStyleDeclaration::create(); @@ -979,8 +1010,8 @@ void InspectorDOMAgent::applyStyleText(long callId, long styleId, const String& ExceptionCode ec = 0; style->setProperty(name, value, priority, ec); // Remove disabled property entry for property with this name. - if (disabledIt != cssStore()->idToDisabledStyle.end()) - disabledIt->second.remove(name); + if (disabledStyle) + disabledStyle->remove(name); changedProperties.append(name); } m_frontend->didApplyStyleText(callId, true, buildObjectForStyle(style, true), toArray(changedProperties)); @@ -988,12 +1019,11 @@ void InspectorDOMAgent::applyStyleText(long callId, long styleId, const String& void InspectorDOMAgent::setStyleText(long callId, long styleId, const String& cssText) { - IdToStyleMap::iterator it = cssStore()->idToStyle.find(styleId); - if (it == cssStore()->idToStyle.end()) { + CSSStyleDeclaration* style = cssStore()->styleForId(styleId); + if (!style) { m_frontend->didSetStyleText(callId, false); return; } - CSSStyleDeclaration* style = it->second.get(); ExceptionCode ec = 0; style->setCssText(cssText, ec); m_frontend->didSetStyleText(callId, !ec); @@ -1001,13 +1031,12 @@ void InspectorDOMAgent::setStyleText(long callId, long styleId, const String& cs void InspectorDOMAgent::setStyleProperty(long callId, long styleId, const String& name, const String& value) { - IdToStyleMap::iterator it = cssStore()->idToStyle.find(styleId); - if (it == cssStore()->idToStyle.end()) { + CSSStyleDeclaration* style = cssStore()->styleForId(styleId); + if (!style) { m_frontend->didSetStyleProperty(callId, false); return; } - CSSStyleDeclaration* style = it->second.get(); ExceptionCode ec = 0; style->setProperty(name, value, ec); m_frontend->didSetStyleProperty(callId, !ec); @@ -1015,28 +1044,25 @@ void InspectorDOMAgent::setStyleProperty(long callId, long styleId, const String void InspectorDOMAgent::toggleStyleEnabled(long callId, long styleId, const String& propertyName, bool disabled) { - IdToStyleMap::iterator it = cssStore()->idToStyle.find(styleId); - if (it == cssStore()->idToStyle.end()) { + CSSStyleDeclaration* style = cssStore()->styleForId(styleId); + if (!style) { m_frontend->didToggleStyleEnabled(callId, ScriptValue::undefined()); return; } - CSSStyleDeclaration* style = it->second.get(); - IdToDisabledStyleMap::iterator disabledIt = cssStore()->idToDisabledStyle.find(styleId); - if (disabledIt == cssStore()->idToDisabledStyle.end()) - disabledIt = cssStore()->idToDisabledStyle.set(styleId, DisabledStyleDeclaration()).first; + DisabledStyleDeclaration* disabledStyle = cssStore()->disabledStyleForId(styleId, true); // TODO: make sure this works with shorthands right. ExceptionCode ec = 0; if (disabled) { - disabledIt->second.set(propertyName, std::make_pair(style->getPropertyValue(propertyName), style->getPropertyPriority(propertyName))); + disabledStyle->set(propertyName, std::make_pair(style->getPropertyValue(propertyName), style->getPropertyPriority(propertyName))); if (!ec) style->removeProperty(propertyName, ec); - } else if (disabledIt->second.contains(propertyName)) { - PropertyValueAndPriority valueAndPriority = disabledIt->second.get(propertyName); + } else if (disabledStyle->contains(propertyName)) { + PropertyValueAndPriority valueAndPriority = disabledStyle->get(propertyName); style->setProperty(propertyName, valueAndPriority.first, valueAndPriority.second, ec); if (!ec) - disabledIt->second.remove(propertyName); + disabledStyle->remove(propertyName); } if (ec) { m_frontend->didToggleStyleEnabled(callId, ScriptValue::undefined()); @@ -1047,13 +1073,12 @@ void InspectorDOMAgent::toggleStyleEnabled(long callId, long styleId, const Stri void InspectorDOMAgent::setRuleSelector(long callId, long ruleId, const String& selector, long selectedNodeId) { - IdToRuleMap::iterator it = cssStore()->idToRule.find(ruleId); - if (it == cssStore()->idToRule.end()) { + CSSStyleRule* rule = cssStore()->ruleForId(ruleId); + if (!rule) { m_frontend->didSetRuleSelector(callId, ScriptValue::undefined(), false); return; } - CSSStyleRule* rule = it->second.get(); Node* node = nodeForId(selectedNodeId); CSSStyleSheet* styleSheet = rule->parentStyleSheet(); @@ -1077,7 +1102,7 @@ void InspectorDOMAgent::setRuleSelector(long callId, long ruleId, const String& return; } - m_frontend->didSetRuleSelector(callId, buildObjectForRule(newRule), ruleAffectsNode(newRule, node)); + m_frontend->didSetRuleSelector(callId, buildObjectForRule(node->ownerDocument(), newRule), ruleAffectsNode(newRule, node)); } void InspectorDOMAgent::addRule(long callId, const String& selector, long selectedNodeId) @@ -1088,70 +1113,34 @@ void InspectorDOMAgent::addRule(long callId, const String& selector, long select return; } - if (!cssStore()->inspectorStyleSheet.get()) { - Document* ownerDocument = node->ownerDocument(); - ExceptionCode ec = 0; - RefPtr<Element> styleElement = ownerDocument->createElement("style", ec); - if (!ec) - styleElement->setAttribute("type", "text/css", ec); - if (!ec) - ownerDocument->head()->appendChild(styleElement, ec); - if (ec) { - m_frontend->didAddRule(callId, ScriptValue::undefined(), false); - return; - } - StyleSheetList* styleSheets = ownerDocument->styleSheets(); - StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1); - if (!styleSheet->isCSSStyleSheet()) { - m_frontend->didAddRule(callId, ScriptValue::undefined(), false); - return; - } - cssStore()->inspectorStyleSheet = static_cast<CSSStyleSheet*>(styleSheet); - } + CSSStyleSheet* styleSheet = cssStore()->inspectorStyleSheet(node->ownerDocument(), true, callId); + if (!styleSheet) + return; // could not add a stylesheet to the ownerDocument ExceptionCode ec = 0; - cssStore()->inspectorStyleSheet->addRule(selector, "", ec); + styleSheet->addRule(selector, "", ec); if (ec) { m_frontend->didAddRule(callId, ScriptValue::undefined(), false); return; } - CSSStyleRule* newRule = static_cast<CSSStyleRule*>(cssStore()->inspectorStyleSheet->item(cssStore()->inspectorStyleSheet->length() - 1)); - m_frontend->didAddRule(callId, buildObjectForRule(newRule), ruleAffectsNode(newRule, node)); -} - -long InspectorDOMAgent::bindStyle(CSSStyleDeclaration* style) -{ - long id = cssStore()->styleToId.get(style); - if (!id) { - id = m_lastStyleId++; - cssStore()->idToStyle.set(id, style); - cssStore()->styleToId.set(style, id); - } - return id; -} - -long InspectorDOMAgent::bindRule(CSSStyleRule* rule) -{ - long id = cssStore()->ruleToId.get(rule); - if (!id) { - id = m_lastRuleId++; - cssStore()->idToRule.set(id, rule); - cssStore()->ruleToId.set(rule, id); - } - return id; + CSSStyleRule* newRule = static_cast<CSSStyleRule*>(styleSheet->item(styleSheet->length() - 1)); + m_frontend->didAddRule(callId, buildObjectForRule(node->ownerDocument(), newRule), ruleAffectsNode(newRule, node)); } ScriptObject InspectorDOMAgent::buildObjectForStyle(CSSStyleDeclaration* style, bool bind) { ScriptObject result = m_frontend->newScriptObject(); if (bind) { - long styleId = bindStyle(style); + long styleId = cssStore()->bindStyle(style); result.set("id", styleId); + CSSStyleSheet* parentStyleSheet = getParentStyleSheet(style); + if (parentStyleSheet) + result.set("parentStyleSheetId", cssStore()->bindStyleSheet(parentStyleSheet)); - IdToDisabledStyleMap::iterator disabledIt = cssStore()->idToDisabledStyle.find(styleId); - if (disabledIt != cssStore()->idToDisabledStyle.end()) - result.set("disabled", buildArrayForDisabledStyleProperties(disabledIt->second)); + DisabledStyleDeclaration* disabledStyle = cssStore()->disabledStyleForId(styleId, false); + if (disabledStyle) + result.set("disabled", buildArrayForDisabledStyleProperties(disabledStyle)); } result.set("width", style->getPropertyValue("width")); result.set("height", style->getPropertyValue("height")); @@ -1173,7 +1162,7 @@ void InspectorDOMAgent::populateObjectWithStyleProperties(CSSStyleDeclaration* s property.set("name", name); property.set("priority", style->getPropertyPriority(name)); property.set("implicit", style->isPropertyImplicit(name)); - String shorthand = style->getPropertyShorthand(name); + String shorthand = style->getPropertyShorthand(name); property.set("shorthand", shorthand); if (!shorthand.isEmpty() && !foundShorthands.contains(shorthand)) { foundShorthands.add(shorthand); @@ -1184,11 +1173,11 @@ void InspectorDOMAgent::populateObjectWithStyleProperties(CSSStyleDeclaration* s } } -ScriptArray InspectorDOMAgent::buildArrayForDisabledStyleProperties(DisabledStyleDeclaration& declaration) +ScriptArray InspectorDOMAgent::buildArrayForDisabledStyleProperties(DisabledStyleDeclaration* declaration) { int counter = 0; ScriptArray properties = m_frontend->newScriptArray(); - for (DisabledStyleDeclaration::iterator it = declaration.begin(); it != declaration.end(); ++it) { + for (DisabledStyleDeclaration::iterator it = declaration->begin(); it != declaration->end(); ++it) { ScriptObject property = m_frontend->newScriptObject(); property.set("name", it->first); property.set("value", it->second.first); @@ -1198,9 +1187,11 @@ ScriptArray InspectorDOMAgent::buildArrayForDisabledStyleProperties(DisabledStyl return properties; } -ScriptObject InspectorDOMAgent::buildObjectForStyleSheet(CSSStyleSheet* styleSheet) +ScriptObject InspectorDOMAgent::buildObjectForStyleSheet(Document* ownerDocument, CSSStyleSheet* styleSheet) { ScriptObject result = m_frontend->newScriptObject(); + long id = cssStore()->bindStyleSheet(styleSheet); + result.set("id", id); result.set("disabled", styleSheet->disabled()); result.set("href", styleSheet->href()); result.set("title", styleSheet->title()); @@ -1214,12 +1205,12 @@ ScriptObject InspectorDOMAgent::buildObjectForStyleSheet(CSSStyleSheet* styleShe for (unsigned i = 0; i < cssRuleList->length(); ++i) { CSSRule* rule = cssRuleList->item(i); if (rule->isStyleRule()) - cssRules.set(counter++, buildObjectForRule(static_cast<CSSStyleRule*>(rule))); + cssRules.set(counter++, buildObjectForRule(ownerDocument, static_cast<CSSStyleRule*>(rule))); } return result; } -ScriptObject InspectorDOMAgent::buildObjectForRule(CSSStyleRule* rule) +ScriptObject InspectorDOMAgent::buildObjectForRule(Document* ownerDocument, CSSStyleRule* rule) { CSSStyleSheet* parentStyleSheet = rule->parentStyleSheet(); @@ -1231,19 +1222,20 @@ ScriptObject InspectorDOMAgent::buildObjectForRule(CSSStyleRule* rule) ScriptObject parentStyleSheetValue = m_frontend->newScriptObject(); result.set("parentStyleSheet", parentStyleSheetValue); parentStyleSheetValue.set("href", parentStyleSheet->href()); + parentStyleSheetValue.set("id", cssStore()->bindStyleSheet(parentStyleSheet)); } bool isUserAgent = parentStyleSheet && !parentStyleSheet->ownerNode() && parentStyleSheet->href().isEmpty(); bool isUser = parentStyleSheet && parentStyleSheet->ownerNode() && parentStyleSheet->ownerNode()->nodeName() == "#document"; result.set("isUserAgent", isUserAgent); result.set("isUser", isUser); - result.set("isViaInspector", rule->parentStyleSheet() == cssStore()->inspectorStyleSheet.get()); + result.set("isViaInspector", rule->parentStyleSheet() == cssStore()->inspectorStyleSheet(ownerDocument, false, -1)); // Bind editable scripts only. bool bind = !isUserAgent && !isUser; result.set("style", buildObjectForStyle(rule->style(), bind)); if (bind) - result.set("id", bindRule(rule)); + result.set("id", cssStore()->bindRule(rule)); return result; } @@ -1324,6 +1316,20 @@ ScriptArray InspectorDOMAgent::toArray(const Vector<String>& data) return result; } +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; +} + } // namespace WebCore #endif // ENABLE(INSPECTOR) diff --git a/WebCore/inspector/InspectorDOMAgent.h b/WebCore/inspector/InspectorDOMAgent.h index c8a4e1a..f8925b5 100644 --- a/WebCore/inspector/InspectorDOMAgent.h +++ b/WebCore/inspector/InspectorDOMAgent.h @@ -107,6 +107,8 @@ namespace WebCore { void getAllStyles(long callId); void getInlineStyle(long callId, long nodeId); void getComputedStyle(long callId, long nodeId); + void getStyleSheet(long callId, long styleSheetId); + void getRuleRangesForStyleSheetId(long callId, long styleSheetId); void applyStyleText(long callId, long styleId, const String& styleText, const String& propertyName); void setStyleText(long callId, long styleId, const String& cssText); void setStyleProperty(long callId, long styleId, const String& name, const String& value); @@ -128,6 +130,7 @@ namespace WebCore { void pushChildNodesToFrontend(long nodeId); private: + static CSSStyleSheet* getParentStyleSheet(CSSStyleDeclaration*); void startListening(Document* document); void stopListening(Document* document); @@ -141,7 +144,7 @@ namespace WebCore { bool pushDocumentToFrontend(); ScriptObject buildObjectForAttributeStyles(Element* element); - ScriptArray buildArrayForCSSRules(CSSRuleList*); + ScriptArray buildArrayForCSSRules(Document* ownerDocument, CSSRuleList*); ScriptArray buildArrayForPseudoElements(Element* element, bool authorOnly); ScriptObject buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap); @@ -162,13 +165,11 @@ namespace WebCore { String documentURLString(Document* document) const; InspectorCSSStore* cssStore() { return m_cssStore; } - long bindStyle(CSSStyleDeclaration*); - long bindRule(CSSStyleRule*); ScriptObject buildObjectForStyle(CSSStyleDeclaration*, bool bind); void populateObjectWithStyleProperties(CSSStyleDeclaration*, ScriptObject& result); - ScriptArray buildArrayForDisabledStyleProperties(DisabledStyleDeclaration&); - ScriptObject buildObjectForRule(CSSStyleRule*); - ScriptObject buildObjectForStyleSheet(CSSStyleSheet*); + ScriptArray buildArrayForDisabledStyleProperties(DisabledStyleDeclaration*); + ScriptObject buildObjectForRule(Document* ownerDocument, CSSStyleRule*); + ScriptObject buildObjectForStyleSheet(Document* ownerDocument, CSSStyleSheet*); Vector<String> longhandProperties(CSSStyleDeclaration*, const String& shorthandProperty); String shorthandValue(CSSStyleDeclaration*, const String& shorthandProperty); String shorthandPriority(CSSStyleDeclaration*, const String& shorthandProperty); @@ -186,8 +187,6 @@ namespace WebCore { HashMap<long, NodeToIdMap*> m_idToNodesMap; HashSet<long> m_childrenRequested; long m_lastNodeId; - long m_lastStyleId; - long m_lastRuleId; ListHashSet<RefPtr<Document> > m_documents; }; diff --git a/WebCore/inspector/InspectorFrontend.cpp b/WebCore/inspector/InspectorFrontend.cpp index d89ae71..fb66cad 100644 --- a/WebCore/inspector/InspectorFrontend.cpp +++ b/WebCore/inspector/InspectorFrontend.cpp @@ -524,6 +524,15 @@ void InspectorFrontend::didGetAllStyles(long callId, const ScriptArray& styles) function.call(); } +void InspectorFrontend::didGetStyleSheet(long callId, const ScriptValue& styleSheet) +{ + ScriptFunctionCall function(m_webInspector, "dispatch"); + function.appendArgument("didGetStyleSheet"); + function.appendArgument(callId); + function.appendArgument(styleSheet); + function.call(); +} + void InspectorFrontend::didGetComputedStyle(long callId, const ScriptValue& style) { ScriptFunctionCall function(m_webInspector, "dispatch"); diff --git a/WebCore/inspector/InspectorFrontend.h b/WebCore/inspector/InspectorFrontend.h index 0e7d7b3..fa752aa 100644 --- a/WebCore/inspector/InspectorFrontend.h +++ b/WebCore/inspector/InspectorFrontend.h @@ -7,13 +7,13 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. + * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -50,7 +50,7 @@ namespace WebCore { public: InspectorFrontend(ScriptObject webInspector); ~InspectorFrontend(); - + void close(); void inspectedPageDestroyed(); @@ -75,7 +75,7 @@ namespace WebCore { void showPanel(int panel); void populateInterface(); void reset(); - + void bringToFront(); void inspectedURLChanged(const String&); @@ -111,7 +111,7 @@ namespace WebCore { void selectDatabase(int databaseId); void didGetDatabaseTableNames(long callId, const ScriptArray& tableNames); #endif - + #if ENABLE(DOM_STORAGE) bool addDOMStorage(const ScriptObject& domStorageObj); void selectDOMStorage(long storageId); @@ -137,6 +137,7 @@ namespace WebCore { void didGetStyles(long callId, const ScriptValue& styles); void didGetAllStyles(long callId, const ScriptArray& styles); void didGetInlineStyle(long callId, const ScriptValue& style); + void didGetStyleSheet(long callId, const ScriptValue& styleSheet); void didGetComputedStyle(long callId, const ScriptValue& style); void didApplyStyleText(long callId, bool success, const ScriptValue& style, const ScriptArray& changedProperties); void didSetStyleText(long callId, bool success); diff --git a/WebCore/inspector/InspectorResource.cpp b/WebCore/inspector/InspectorResource.cpp index 51ed290..999b8d6 100644 --- a/WebCore/inspector/InspectorResource.cpp +++ b/WebCore/inspector/InspectorResource.cpp @@ -125,6 +125,7 @@ void InspectorResource::updateResponse(const ResourceResponse& response) } m_responseHeaderFields = response.httpHeaderFields(); m_responseStatusCode = response.httpStatusCode(); + m_responseStatusText = response.httpStatusText(); m_suggestedFilename = response.suggestedFilename(); m_changes.set(ResponseChange); @@ -167,6 +168,7 @@ void InspectorResource::updateScriptObject(InspectorFrontend* frontend) jsonObject.set("suggestedFilename", m_suggestedFilename); jsonObject.set("expectedContentLength", m_expectedContentLength); jsonObject.set("statusCode", m_responseStatusCode); + jsonObject.set("statusText", m_responseStatusText); jsonObject.set("suggestedFilename", m_suggestedFilename); ScriptObject responseHeaders = frontend->newScriptObject(); populateHeadersObject(&responseHeaders, m_responseHeaderFields); diff --git a/WebCore/inspector/InspectorResource.h b/WebCore/inspector/InspectorResource.h index 30b1280..9b91889 100644 --- a/WebCore/inspector/InspectorResource.h +++ b/WebCore/inspector/InspectorResource.h @@ -166,6 +166,7 @@ namespace WebCore { bool m_failed; int m_length; int m_responseStatusCode; + String m_responseStatusText; double m_startTime; double m_responseReceivedTime; double m_endTime; diff --git a/WebCore/inspector/InspectorValues.cpp b/WebCore/inspector/InspectorValues.cpp new file mode 100644 index 0000000..f59e900 --- /dev/null +++ b/WebCore/inspector/InspectorValues.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorValues.h" + +#if ENABLE(INSPECTOR) + +namespace WebCore { + +inline bool escapeChar(UChar c, Vector<UChar>* dst) +{ + switch (c) { + case '\b': dst->append("\\b", 2); break; + case '\f': dst->append("\\f", 2); break; + case '\n': dst->append("\\n", 2); break; + case '\r': dst->append("\\r", 2); break; + case '\t': dst->append("\\t", 2); break; + case '\\': dst->append("\\\\", 2); break; + case '"': dst->append("\\\"", 2); break; + default: + return false; + } + return true; +} + +inline void doubleQuoteString(const String& str, Vector<UChar>* dst) +{ + dst->append('"'); + for (unsigned i = 0; i < str.length(); ++i) { + UChar c = str[i]; + if (!escapeChar(c, dst)) { + if (c < 32 || c > 126 || c == '<' || c == '>') { + // 1. Escaping <, > to prevent script execution. + // 2. Technically, we could also pass through c > 126 as UTF8, but this + // is also optional. It would also be a pain to implement here. + unsigned int symbol = static_cast<unsigned int>(c); + String symbolCode = String::format("\\u%04X", symbol); + dst->append(symbolCode.characters(), symbolCode.length()); + } else + dst->append(c); + } + } + dst->append('"'); +} + +String InspectorValue::toJSONString() const +{ + Vector<UChar> result; + result.reserveCapacity(512); + writeJSON(&result); + return String(result.data(), result.size()); +} + +void InspectorValue::writeJSON(Vector<UChar>* output) const +{ + ASSERT(m_type == TypeNull); + output->append("null", 4); +} + +void InspectorBasicValue::writeJSON(Vector<UChar>* output) const +{ + ASSERT(type() == TypeBoolean || type() == TypeDouble); + if (type() == TypeBoolean) { + if (m_boolValue) + output->append("true", 4); + else + output->append("false", 5); + } else if (type() == TypeDouble) { + String value = String::format("%f", m_doubleValue); + output->append(value.characters(), value.length()); + } +} + +void InspectorString::writeJSON(Vector<UChar>* output) const +{ + ASSERT(type() == TypeString); + doubleQuoteString(m_stringValue, output); +} + +void InspectorObject::writeJSON(Vector<UChar>* output) const +{ + output->append('{'); + for (Dictionary::const_iterator it = m_data.begin(); it != m_data.end(); ++it) { + if (it != m_data.begin()) + output->append(','); + doubleQuoteString(it->first, output); + output->append(':'); + it->second->writeJSON(output); + } + output->append('}'); +} + +void InspectorArray::writeJSON(Vector<UChar>* output) const +{ + output->append('['); + for (Vector<RefPtr<InspectorValue> >::const_iterator it = m_data.begin(); it != m_data.end(); ++it) { + if (it != m_data.begin()) + output->append(','); + (*it)->writeJSON(output); + } + output->append(']'); +} + +} // namespace WebCore + +#endif // ENABLE(INSPECTOR) diff --git a/WebCore/inspector/InspectorValues.h b/WebCore/inspector/InspectorValues.h new file mode 100644 index 0000000..a60bb2c --- /dev/null +++ b/WebCore/inspector/InspectorValues.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef InspectorValues_h +#define InspectorValues_h + +#if ENABLE(INSPECTOR) + +#include "PlatformString.h" +#include "StringHash.h" + +#include <wtf/HashMap.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class String; + +class InspectorValue : public RefCounted<InspectorValue> { +public: + InspectorValue() : m_type(TypeNull) { } + virtual ~InspectorValue() { } + + static PassRefPtr<InspectorValue> null() + { + return adoptRef(new InspectorValue()); + } + + typedef enum { + TypeNull = 0, + TypeBoolean, + TypeDouble, + TypeString, + TypeObject, + TypeArray + } Type; + + Type type() const { return m_type; } + + String toJSONString() const; + virtual void writeJSON(Vector<UChar>* output) const; + +protected: + explicit InspectorValue(Type type) : m_type(type) { } + +private: + Type m_type; +}; + +class InspectorBasicValue : public InspectorValue { +public: + + static PassRefPtr<InspectorBasicValue> create(bool value) + { + return adoptRef(new InspectorBasicValue(value)); + } + + static PassRefPtr<InspectorBasicValue> create(int value) + { + return adoptRef(new InspectorBasicValue(value)); + } + + static PassRefPtr<InspectorBasicValue> create(double value) + { + return adoptRef(new InspectorBasicValue(value)); + } + + virtual void writeJSON(Vector<UChar>* output) const; + +private: + explicit InspectorBasicValue(bool value) : InspectorValue(TypeBoolean), m_boolValue(value) { } + explicit InspectorBasicValue(int value) : InspectorValue(TypeDouble), m_doubleValue((double)value) { } + explicit InspectorBasicValue(double value) : InspectorValue(TypeDouble), m_doubleValue(value) { } + + union { + bool m_boolValue; + double m_doubleValue; + }; +}; + +class InspectorString : public InspectorValue { +public: + static PassRefPtr<InspectorString> create(const String& value) + { + return adoptRef(new InspectorString(value)); + } + + static PassRefPtr<InspectorString> create(const char* value) + { + return adoptRef(new InspectorString(value)); + } + virtual void writeJSON(Vector<UChar>* output) const; + +private: + explicit InspectorString(const String& value) : InspectorValue(TypeString), m_stringValue(value) { } + explicit InspectorString(const char* value) : InspectorValue(TypeString), m_stringValue(value) { } + + String m_stringValue; +}; + +class InspectorObject : public InspectorValue { +public: + static PassRefPtr<InspectorObject> create() + { + return adoptRef(new InspectorObject()); + } + ~InspectorObject() { } + + void setBool(const String& name, bool); + void setNumber(const String& name, double); + void setString(const String& name, const String&); + void set(const String& name, PassRefPtr<InspectorValue>); + + virtual void writeJSON(Vector<UChar>* output) const; + +private: + InspectorObject() : InspectorValue(TypeObject) { } + typedef HashMap<String, RefPtr<InspectorValue> > Dictionary; + Dictionary m_data; +}; + +class InspectorArray : public InspectorValue { +public: + static PassRefPtr<InspectorArray> create() + { + return adoptRef(new InspectorArray()); + } + ~InspectorArray() { } + + void pushBool(bool); + void pushNumber(double); + void pushString(const String&); + void push(PassRefPtr<InspectorValue>); + unsigned length() { return m_data.size(); } + + virtual void writeJSON(Vector<UChar>* output) const; + +private: + InspectorArray() : InspectorValue(TypeArray) { } + Vector<RefPtr<InspectorValue> > m_data; +}; + +inline void InspectorObject::setBool(const String& name, bool value) +{ + m_data.set(name, InspectorBasicValue::create(value)); +} + +inline void InspectorObject::setNumber(const String& name, double value) +{ + m_data.set(name, InspectorBasicValue::create(value)); +} + +inline void InspectorObject::setString(const String& name, const String& value) +{ + m_data.set(name, InspectorString::create(value)); +} + +inline void InspectorObject::set(const String& name, PassRefPtr<InspectorValue> value) +{ + m_data.set(name, value); +} + +inline void InspectorArray::pushBool(bool value) +{ + m_data.append(InspectorBasicValue::create(value)); +} + +inline void InspectorArray::pushNumber(double value) +{ + m_data.append(InspectorBasicValue::create(value)); +} + +inline void InspectorArray::pushString(const String& value) +{ + m_data.append(InspectorString::create(value)); +} + +inline void InspectorArray::push(PassRefPtr<InspectorValue> value) +{ + m_data.append(value); +} + +} // namespace WebCore + +#endif // ENABLE(INSPECTOR) +#endif // !defined(InspectorValues_h) + diff --git a/WebCore/inspector/ScriptDebugListener.h b/WebCore/inspector/ScriptDebugListener.h index 5a85da1..c669f5e 100644 --- a/WebCore/inspector/ScriptDebugListener.h +++ b/WebCore/inspector/ScriptDebugListener.h @@ -32,6 +32,8 @@ #if ENABLE(JAVASCRIPT_DEBUGGER) +#include "ScriptState.h" + namespace WebCore { class String; @@ -42,7 +44,7 @@ public: virtual void didParseSource(const String& sourceID, const String& url, const String& data, int firstLine) = 0; virtual void failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage) = 0; - virtual void didPause() = 0; + virtual void didPause(ScriptState*) = 0; virtual void didContinue() = 0; }; diff --git a/WebCore/inspector/TimelineRecordFactory.cpp b/WebCore/inspector/TimelineRecordFactory.cpp index 0540dad..bdb5f3d 100644 --- a/WebCore/inspector/TimelineRecordFactory.cpp +++ b/WebCore/inspector/TimelineRecordFactory.cpp @@ -49,14 +49,9 @@ ScriptObject TimelineRecordFactory::createGenericRecord(InspectorFrontend* front ScriptObject record = frontend->newScriptObject(); record.set("startTime", startTime); - String sourceName; - int sourceLineNumber; - String functionName; - if (ScriptCallStack::callLocation(&sourceName, &sourceLineNumber, &functionName) && sourceName != "undefined") { - record.set("callerScriptName", sourceName); - record.set("callerScriptLine", sourceLineNumber); - record.set("callerFunctionName", functionName); - } + ScriptArray stackTrace; + if (ScriptCallStack::stackTrace(5, frontend->scriptState(), stackTrace)) + record.set("stackTrace", stackTrace); return record; } diff --git a/WebCore/inspector/front-end/AuditsPanel.js b/WebCore/inspector/front-end/AuditsPanel.js index c3318ce..481df80 100644 --- a/WebCore/inspector/front-end/AuditsPanel.js +++ b/WebCore/inspector/front-end/AuditsPanel.js @@ -49,7 +49,7 @@ WebInspector.AuditsPanel = function() this.element.addStyleClass("audits"); - this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear audit results."), "clear-audit-results-status-bar-item"); + this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear audit results."), "clear-status-bar-item"); this.clearResultsButton.addEventListener("click", this._clearButtonClicked.bind(this), false); this.viewsContainerElement = document.createElement("div"); diff --git a/WebCore/inspector/front-end/Breakpoint.js b/WebCore/inspector/front-end/Breakpoint.js index 7f3ef17..e69de29 100644 --- a/WebCore/inspector/front-end/Breakpoint.js +++ b/WebCore/inspector/front-end/Breakpoint.js @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -WebInspector.Breakpoint = function(url, line, sourceID, condition) -{ - this.url = url; - this.line = line; - this.sourceID = sourceID; - this._enabled = true; - this._sourceText = ""; - this._condition = condition || ""; -} - -WebInspector.Breakpoint.prototype = { - get enabled() - { - return this._enabled; - }, - - set enabled(x) - { - if (this._enabled === x) - return; - - this._enabled = x; - - if (this._enabled) - this.dispatchEventToListeners("enabled"); - else - this.dispatchEventToListeners("disabled"); - }, - - get sourceText() - { - return this._sourceText; - }, - - set sourceText(text) - { - this._sourceText = text; - this.dispatchEventToListeners("text-changed"); - }, - - get label() - { - var displayName = (this.url ? WebInspector.displayNameForURL(this.url) : WebInspector.UIString("(program)")); - return displayName + ":" + this.line; - }, - - get id() - { - return this.sourceID + ":" + this.line; - }, - - get condition() - { - return this._condition; - }, - - set condition(c) - { - c = c || ""; - if (this._condition === c) - return; - - this._condition = c; - this.dispatchEventToListeners("condition-changed"); - - if (this.enabled) - InspectorBackend.setBreakpoint(this.sourceID, this.line, this.enabled, this.condition); - } -} - -WebInspector.Breakpoint.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/WebCore/inspector/front-end/BreakpointManager.js b/WebCore/inspector/front-end/BreakpointManager.js new file mode 100644 index 0000000..c277fb1 --- /dev/null +++ b/WebCore/inspector/front-end/BreakpointManager.js @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.BreakpointManager = function() +{ + this._breakpoints = {}; +} + +WebInspector.BreakpointManager.prototype = { + addBreakpoint: function(sourceID, sourceURL, line, enabled, condition) + { + var breakpoint = new WebInspector.Breakpoint(this, sourceID, sourceURL, line, enabled, condition); + if (this._breakpoints[breakpoint.id]) + return; + this._breakpoints[breakpoint.id] = breakpoint; + this._saveBreakpointOnBackend(breakpoint); + this.dispatchEventToListeners("breakpoint-added", breakpoint); + }, + + removeBreakpoint: function(breakpoint) + { + if (!(breakpoint.id in this._breakpoints)) + return; + delete this._breakpoints[breakpoint.id]; + this._removeBreakpointFromBackend(breakpoint); + this.dispatchEventToListeners("breakpoint-removed", breakpoint); + }, + + breakpointsForSourceID: function(sourceID) + { + var breakpoints = []; + for (var id in this._breakpoints) { + if (this._breakpoints[id].sourceID === sourceID) + breakpoints.push(this._breakpoints[id]); + } + return breakpoints; + }, + + breakpointsForURL: function(url) + { + var breakpoints = []; + for (var id in this._breakpoints) { + if (this._breakpoints[id].url === url) + breakpoints.push(this._breakpoints[id]); + } + return breakpoints; + }, + + reset: function() + { + this._breakpoints = {}; + }, + + _saveBreakpointOnBackend: function(breakpoint) + { + InspectorBackend.setBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.enabled, breakpoint.condition); + }, + + _removeBreakpointFromBackend: function(breakpoint) + { + InspectorBackend.removeBreakpoint(breakpoint.sourceID, breakpoint.line); + } +} + +WebInspector.BreakpointManager.prototype.__proto__ = WebInspector.Object.prototype; + +WebInspector.Breakpoint = function(breakpointManager, sourceID, sourceURL, line, enabled, condition) +{ + this.url = sourceURL; + this.line = line; + this.sourceID = sourceID; + this._enabled = enabled; + this._condition = condition || ""; + this._sourceText = ""; + this._breakpointManager = breakpointManager; +} + +WebInspector.Breakpoint.prototype = { + get enabled() + { + return this._enabled; + }, + + set enabled(x) + { + if (this._enabled === x) + return; + + this._enabled = x; + this._breakpointManager._saveBreakpointOnBackend(this); + if (this._enabled) + this.dispatchEventToListeners("enabled"); + else + this.dispatchEventToListeners("disabled"); + }, + + get sourceText() + { + return this._sourceText; + }, + + set sourceText(text) + { + this._sourceText = text; + this.dispatchEventToListeners("text-changed"); + }, + + get label() + { + var displayName = (this.url ? WebInspector.displayNameForURL(this.url) : WebInspector.UIString("(program)")); + return displayName + ":" + this.line; + }, + + get id() + { + return this.sourceID + ":" + this.line; + }, + + get condition() + { + return this._condition; + }, + + set condition(c) + { + c = c || ""; + if (this._condition === c) + return; + + this._condition = c; + if (this.enabled) + this._breakpointManager._saveBreakpointOnBackend(this); + this.dispatchEventToListeners("condition-changed"); + } +} + +WebInspector.Breakpoint.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/WebCore/inspector/front-end/BreakpointsSidebarPane.js b/WebCore/inspector/front-end/BreakpointsSidebarPane.js index fcfd2ab..a4daa2d 100644 --- a/WebCore/inspector/front-end/BreakpointsSidebarPane.js +++ b/WebCore/inspector/front-end/BreakpointsSidebarPane.js @@ -27,8 +27,6 @@ WebInspector.BreakpointsSidebarPane = function() { WebInspector.SidebarPane.call(this, WebInspector.UIString("Breakpoints")); - this.breakpoints = {}; - this.listElement = document.createElement("ol"); this.listElement.className = "breakpoint-list"; @@ -37,12 +35,14 @@ WebInspector.BreakpointsSidebarPane = function() this.emptyElement.textContent = WebInspector.UIString("No Breakpoints"); this.bodyElement.appendChild(this.emptyElement); + + WebInspector.breakpointManager.addEventListener("breakpoint-added", this._breakpointAdded, this); + WebInspector.breakpointManager.addEventListener("breakpoint-removed", this._breakpointRemoved, this); } WebInspector.BreakpointsSidebarPane.prototype = { reset: function() { - this.breakpoints = {}; this.listElement.removeChildren(); if (this.listElement.parentElement) { this.bodyElement.removeChild(this.listElement); @@ -50,12 +50,9 @@ WebInspector.BreakpointsSidebarPane.prototype = { } }, - addBreakpoint: function(breakpoint) + _breakpointAdded: function(event) { - if (this.breakpoints[breakpoint.id]) - return; - - this.breakpoints[breakpoint.id] = breakpoint; + var breakpoint = event.data; breakpoint.addEventListener("enabled", this._breakpointEnableChanged, this); breakpoint.addEventListener("disabled", this._breakpointEnableChanged, this); @@ -67,8 +64,6 @@ WebInspector.BreakpointsSidebarPane.prototype = { this.bodyElement.removeChild(this.emptyElement); this.bodyElement.appendChild(this.listElement); } - - InspectorBackend.setBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.enabled, breakpoint.condition); }, _appendBreakpointElement: function(breakpoint) @@ -121,11 +116,9 @@ WebInspector.BreakpointsSidebarPane.prototype = { this.listElement.appendChild(breakpointElement); }, - removeBreakpoint: function(breakpoint) + _breakpointRemoved: function(event) { - if (!this.breakpoints[breakpoint.id]) - return; - delete this.breakpoints[breakpoint.id]; + var breakpoint = event.data; breakpoint.removeEventListener("enabled", null, this); breakpoint.removeEventListener("disabled", null, this); @@ -138,8 +131,6 @@ WebInspector.BreakpointsSidebarPane.prototype = { this.bodyElement.removeChild(this.listElement); this.bodyElement.appendChild(this.emptyElement); } - - InspectorBackend.removeBreakpoint(breakpoint.sourceID, breakpoint.line); }, _breakpointEnableChanged: function(event) @@ -148,7 +139,6 @@ WebInspector.BreakpointsSidebarPane.prototype = { var checkbox = breakpoint._breakpointListElement.firstChild; checkbox.checked = breakpoint.enabled; - InspectorBackend.setBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.enabled, breakpoint.condition); }, _breakpointTextChanged: function(event) diff --git a/WebCore/inspector/front-end/ChangesView.js b/WebCore/inspector/front-end/ChangesView.js index 802fdba..5ab6942 100644 --- a/WebCore/inspector/front-end/ChangesView.js +++ b/WebCore/inspector/front-end/ChangesView.js @@ -37,7 +37,7 @@ WebInspector.ChangesView = function(drawer) this.clearButton = document.createElement("button"); this.clearButton.id = "clear-changes-status-bar-item"; this.clearButton.title = WebInspector.UIString("Clear changes log."); - this.clearButton.className = "status-bar-item"; + this.clearButton.className = "status-bar-item clear-status-bar-item"; this.clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false); this.toggleChangesButton = document.getElementById("changes-status-bar-item"); diff --git a/WebCore/inspector/front-end/ConsoleView.js b/WebCore/inspector/front-end/ConsoleView.js index b9f6d0a..8521cb3 100644 --- a/WebCore/inspector/front-end/ConsoleView.js +++ b/WebCore/inspector/front-end/ConsoleView.js @@ -249,7 +249,7 @@ WebInspector.ConsoleView.prototype = { this.currentGroup = this.currentGroup.parentGroup; } else { - if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup) { + if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup || msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) { this.groupLevel++; var group = new WebInspector.ConsoleGroup(this.currentGroup, this.groupLevel); @@ -808,8 +808,8 @@ WebInspector.ConsoleMessage.prototype = { element.addStyleClass("console-error-level"); break; } - - if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup) + + if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup || this.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) element.addStyleClass("console-group-title"); if (this.elementsTreeOutline) { @@ -894,6 +894,7 @@ WebInspector.ConsoleMessage.prototype = { case WebInspector.ConsoleMessage.MessageType.Trace: typeString = "Trace"; break; + case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed: case WebInspector.ConsoleMessage.MessageType.StartGroup: typeString = "Start Group"; break; @@ -961,9 +962,10 @@ WebInspector.ConsoleMessage.MessageType = { Object: 1, Trace: 2, StartGroup: 3, - EndGroup: 4, - Assert: 5, - Result: 6 + StartGroupCollapsed: 4, + EndGroup: 5, + Assert: 6, + Result: 7 } WebInspector.ConsoleMessage.MessageLevel = { @@ -1051,10 +1053,13 @@ WebInspector.ConsoleGroup.prototype = { addMessage: function(msg) { var element = msg.toMessageElement(); - - if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup) { + + 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); + var groupElement = element.enclosingNodeOrSelfWithClass("console-group"); + if (groupElement && msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) + groupElement.addStyleClass("collapsed"); } else this.messagesElement.appendChild(element); diff --git a/WebCore/inspector/front-end/DOMAgent.js b/WebCore/inspector/front-end/DOMAgent.js index 3373c04..5bde12f 100644 --- a/WebCore/inspector/front-end/DOMAgent.js +++ b/WebCore/inspector/front-end/DOMAgent.js @@ -489,6 +489,7 @@ WebInspector.EventListeners.getEventListenersForNodeAsync = function(node, callb WebInspector.CSSStyleDeclaration = function(payload) { this.id = payload.id; + this.parentStyleSheetId = payload.parentStyleSheetId; this.width = payload.width; this.height = payload.height; this.__disabledProperties = {}; @@ -672,6 +673,7 @@ WebInspector.didGetEventListenersForNode = WebInspector.Callback.processCallback WebInspector.didGetStyles = WebInspector.Callback.processCallback; WebInspector.didGetAllStyles = WebInspector.Callback.processCallback; +WebInspector.didGetStyleSheet = WebInspector.Callback.processCallback; WebInspector.didGetInlineStyle = WebInspector.Callback.processCallback; WebInspector.didGetComputedStyle = WebInspector.Callback.processCallback; WebInspector.didApplyStyleText = WebInspector.Callback.processCallback; diff --git a/WebCore/inspector/front-end/Drawer.js b/WebCore/inspector/front-end/Drawer.js index 8bf707e..3f827fb 100644 --- a/WebCore/inspector/front-end/Drawer.js +++ b/WebCore/inspector/front-end/Drawer.js @@ -40,6 +40,8 @@ WebInspector.Drawer = function() this.mainStatusBar = document.getElementById("main-status-bar"); this.mainStatusBar.addEventListener("mousedown", this._startStatusBarDragging.bind(this), true); this.viewStatusBar = document.getElementById("other-drawer-status-bar-items"); + this._counters = document.getElementById("counters"); + this._drawerStatusBar = document.getElementById("drawer-status-bar"); } WebInspector.Drawer.prototype = { @@ -110,6 +112,15 @@ WebInspector.Drawer.prototype = { var drawerStatusBar = document.getElementById("drawer-status-bar"); drawerStatusBar.insertBefore(anchoredItems, drawerStatusBar.firstChild); + if (this._currentPanelCounters) { + var oldRight = this._drawerStatusBar.clientWidth - (this._counters.offsetLeft + this._currentPanelCounters.offsetWidth); + var newRight = WebInspector.Panel.counterRightMargin; + var rightPadding = (oldRight - newRight); + animations.push({element: this._currentPanelCounters, start: {"padding-right": rightPadding}, end: {"padding-right": 0}}); + this._currentPanelCounters.parentNode.removeChild(this._currentPanelCounters); + this.mainStatusBar.appendChild(this._currentPanelCounters); + } + function animationFinished() { if ("updateStatusBarItems" in WebInspector.currentPanel) @@ -119,6 +130,8 @@ WebInspector.Drawer.prototype = { delete this._animating; delete this._currentAnimationInterval; this.state = (this.fullPanel ? WebInspector.Drawer.State.Full : WebInspector.Drawer.State.Variable); + if (this._currentPanelCounters) + this._currentPanelCounters.removeAttribute("style"); } this._currentAnimationInterval = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this)); @@ -158,12 +171,26 @@ WebInspector.Drawer.prototype = { {element: document.getElementById("other-drawer-status-bar-items"), start: {opacity: 1}, end: {opacity: 0}} ]; + if (this._currentPanelCounters) { + var newRight = this._drawerStatusBar.clientWidth - this._counters.offsetLeft; + var oldRight = this.mainStatusBar.clientWidth - (this._currentPanelCounters.offsetLeft + this._currentPanelCounters.offsetWidth); + var rightPadding = (newRight - oldRight); + animations.push({element: this._currentPanelCounters, start: {"padding-right": 0}, end: {"padding-right": rightPadding}}); + } + function animationFinished() { WebInspector.currentPanel.resize(); var mainStatusBar = document.getElementById("main-status-bar"); mainStatusBar.insertBefore(anchoredItems, mainStatusBar.firstChild); mainStatusBar.style.removeProperty("padding-left"); + + if (this._currentPanelCounters) { + this._currentPanelCounters.setAttribute("style", null); + this._currentPanelCounters.parentNode.removeChild(this._currentPanelCounters); + this._counters.insertBefore(this._currentPanelCounters, this._counters.firstChild); + } + document.body.removeStyleClass("drawer-visible"); delete this._animating; delete this._currentAnimationInterval; @@ -222,6 +249,22 @@ WebInspector.Drawer.prototype = { this.fullPanel = false; }, + set currentPanelCounters(x) + { + if (!x) { + if (this._currentPanelCounters) + this._currentPanelCounters.parentElement.removeChild(this._currentPanelCounters); + delete this._currentPanelCounters; + return; + } + + this._currentPanelCounters = x; + if (this.visible) + this.mainStatusBar.appendChild(x); + else + this._counters.insertBefore(x, this._counters.firstChild); + }, + _cancelAnimationIfNeeded: function() { if (this._animating) { diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js index 0e943c0..e8fecb0 100644 --- a/WebCore/inspector/front-end/ElementsTreeOutline.js +++ b/WebCore/inspector/front-end/ElementsTreeOutline.js @@ -43,7 +43,6 @@ WebInspector.ElementsTreeOutline = function() { this.focusedDOMNode = null; this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true); - this.element.addEventListener("keydown", this._keyDown.bind(this), true); } WebInspector.ElementsTreeOutline.prototype = { @@ -117,6 +116,11 @@ WebInspector.ElementsTreeOutline.prototype = { } }, + get editing() + { + return this._editing; + }, + update: function() { var selectedNode = this.selectedTreeElement ? this.selectedTreeElement.representedObject : null; @@ -226,41 +230,6 @@ WebInspector.ElementsTreeOutline.prototype = { return element; }, - _keyDown: function(event) - { - if (event.target !== this.treeOutline.element) - return; - - var selectedElement = this.selectedTreeElement; - if (!selectedElement) - return; - - if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Backspace.code || - event.keyCode === WebInspector.KeyboardShortcut.Keys.Delete.code) { - var startTagTreeElement = this.findTreeElement(selectedElement.representedObject); - if (selectedElement !== startTagTreeElement) - selectedElement = startTagTreeElement; - selectedElement.remove(); - event.preventDefault(); - event.stopPropagation(); - return; - } - - // On Enter or Return start editing the first attribute - // or create a new attribute on the selected element. - if (isEnterKey(event)) { - if (this._editing) - return; - - selectedElement._startEditing(); - - // prevent a newline from being immediately inserted - event.preventDefault(); - event.stopPropagation(); - return; - } - }, - _onmousedown: function(event) { var element = this._treeElementFromEvent(event); @@ -686,6 +655,26 @@ WebInspector.ElementsTreeElement.prototype = { this.treeOutline.suppressRevealAndSelect = false; }, + ondelete: function() + { + var startTagTreeElement = this.treeOutline.findTreeElement(this.representedObject); + startTagTreeElement ? startTagTreeElement.remove() : this.remove(); + return true; + }, + + onenter: function() + { + // On Enter or Return start editing the first attribute + // or create a new attribute on the selected element. + if (this.treeOutline.editing) + return false; + + this._startEditing(); + + // prevent a newline from being immediately inserted + return true; + }, + selectOnMouseDown: function(event) { TreeElement.prototype.selectOnMouseDown.call(this, event); diff --git a/WebCore/inspector/front-end/Object.js b/WebCore/inspector/front-end/Object.js index 74fb56e..27e2144 100644 --- a/WebCore/inspector/front-end/Object.js +++ b/WebCore/inspector/front-end/Object.js @@ -50,7 +50,7 @@ WebInspector.Object.prototype = { delete this._listeners[eventType]; }, - dispatchEventToListeners: function(eventType) { + dispatchEventToListeners: function(eventType, eventData) { if (!("_listeners" in this) || !(eventType in this._listeners)) return; @@ -66,7 +66,7 @@ WebInspector.Object.prototype = { this.defaultPrevented = true; } - var event = {target: this, type: eventType, defaultPrevented: false}; + var event = {target: this, type: eventType, data: eventData, defaultPrevented: false}; event.stopPropagation = stopPropagation; event.preventDefault = preventDefault; diff --git a/WebCore/inspector/front-end/Panel.js b/WebCore/inspector/front-end/Panel.js index 6dbc60e..9fd0a60 100644 --- a/WebCore/inspector/front-end/Panel.js +++ b/WebCore/inspector/front-end/Panel.js @@ -33,6 +33,9 @@ WebInspector.Panel = function() this.element.addStyleClass("panel"); } +// Should by in sync with style declarations. +WebInspector.Panel.counterRightMargin = 25; + WebInspector.Panel.prototype = { get toolbarItem() { @@ -313,6 +316,7 @@ WebInspector.Panel.prototype = { this.sidebarElement.appendChild(this.sidebarTreeElement); this.sidebarTree = new TreeOutline(this.sidebarTreeElement); + this.sidebarTree.panel = this; }, _startSidebarDragging: function(event) diff --git a/WebCore/inspector/front-end/ProfilesPanel.js b/WebCore/inspector/front-end/ProfilesPanel.js index cca9e33..1980fa5 100644 --- a/WebCore/inspector/front-end/ProfilesPanel.js +++ b/WebCore/inspector/front-end/ProfilesPanel.js @@ -113,6 +113,9 @@ WebInspector.ProfilesPanel = function() this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item"); this.enableToggleButton.addEventListener("click", this._toggleProfiling.bind(this), false); + this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear CPU profiles."), "clear-status-bar-item"); + this.clearResultsButton.addEventListener("click", this._clearProfiles.bind(this), false); + this.profileViewStatusBarItemsContainer = document.createElement("div"); this.profileViewStatusBarItemsContainer.id = "profile-view-status-bar-items"; @@ -151,7 +154,7 @@ WebInspector.ProfilesPanel.prototype = { items.push(button.element); } } - items.push(this.profileViewStatusBarItemsContainer); + items.push(this.clearResultsButton.element, this.profileViewStatusBarItemsContainer); return items; }, @@ -216,6 +219,12 @@ WebInspector.ProfilesPanel.prototype = { this.welcomeView.show(); }, + _clearProfiles: function() + { + InspectorBackend.clearProfiles(); + this.reset(); + }, + registerProfileType: function(profileType) { this._profileTypesByIdMap[profileType.id] = profileType; @@ -337,6 +346,14 @@ WebInspector.ProfilesPanel.prototype = { delete this._profileGroups[profileTitleKey]; sidebarParent.removeChild(profile._profilesTreeElement); + + if (!profile.isTemporary) + InspectorBackend.removeProfile(profile.uid); + + // No other item will be selected if there aren't any other profiles, so + // make sure that view gets cleared when the last profile is removed. + if (!this._profiles.length) + this.closeVisibleView(); }, showProfile: function(profile) @@ -466,6 +483,7 @@ WebInspector.ProfilesPanel.prototype = { for (var typeId in this._profileTypeButtonsByIdMap) this._profileTypeButtonsByIdMap[typeId].removeStyleClass("hidden"); this.profileViewStatusBarItemsContainer.removeStyleClass("hidden"); + this.clearResultsButton.element.removeStyleClass("hidden"); this.panelEnablerView.visible = false; } else { this.enableToggleButton.title = WebInspector.UIString("Profiling disabled. Click to enable."); @@ -473,6 +491,7 @@ WebInspector.ProfilesPanel.prototype = { for (var typeId in this._profileTypeButtonsByIdMap) this._profileTypeButtonsByIdMap[typeId].addStyleClass("hidden"); this.profileViewStatusBarItemsContainer.addStyleClass("hidden"); + this.clearResultsButton.element.addStyleClass("hidden"); this.panelEnablerView.visible = true; } }, @@ -540,7 +559,13 @@ WebInspector.ProfileSidebarTreeElement = function(profile) WebInspector.ProfileSidebarTreeElement.prototype = { onselect: function() { - WebInspector.panels.profiles.showProfile(this.profile); + this.treeOutline.panel.showProfile(this.profile); + }, + + ondelete: function() + { + this.treeOutline.panel.removeProfileHeader(this.profile); + return true; }, get mainTitle() diff --git a/WebCore/inspector/front-end/Resource.js b/WebCore/inspector/front-end/Resource.js index 739dd73..279e3af 100644 --- a/WebCore/inspector/front-end/Resource.js +++ b/WebCore/inspector/front-end/Resource.js @@ -37,63 +37,6 @@ WebInspector.Resource = function(identifier, url) this._category = WebInspector.resourceCategories.other; } -WebInspector.Resource.StatusText = { - 100: "Continue", - 101: "Switching Protocols", - 102: "Processing (WebDav)", - 200: "OK", - 201: "Created", - 202: "Accepted", - 203: "Non-Authoritative Information", - 204: "No Content", - 205: "Reset Content", - 206: "Partial Content", - 207: "Multi-Status (WebDav)", - 300: "Multiple Choices", - 301: "Moved Permanently", - 302: "Found", - 303: "See Other", - 304: "Not Modified", - 305: "Use Proxy", - 306: "Switch Proxy", - 307: "Temporary", - 400: "Bad Request", - 401: "Unauthorized", - 402: "Payment Required", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 406: "Not Acceptable", - 407: "Proxy Authentication Required", - 408: "Request Timeout", - 409: "Conflict", - 410: "Gone", - 411: "Length Required", - 412: "Precondition Failed", - 413: "Request Entity Too Large", - 414: "Request-URI Too Long", - 415: "Unsupported Media Type", - 416: "Requested Range Not Satisfiable", - 417: "Expectation Failed", - 418: "I'm a teapot", - 422: "Unprocessable Entity (WebDav)", - 423: "Locked (WebDav)", - 424: "Failed Dependency (WebDav)", - 425: "Unordered Collection", - 426: "Upgrade Required", - 449: "Retry With", - 500: "Internal Server Error", - 501: "Not Implemented", - 502: "Bad Gateway", - 503: "Service Unavailable", - 504: "Gateway Timeout", - 505: "HTTP Version Not Supported", - 506: "Variant Also Negotiates", - 507: "Insufficient Storage (WebDav)", - 509: "Bandwidth Limit Exceeded", - 510: "Not Extended" -}; - // Keep these in sync with WebCore::InspectorResource::Type WebInspector.Resource.Type = { Document: 0, @@ -622,9 +565,3 @@ WebInspector.Resource.CompareByTransferSize = function(a, b) { return a.transferSize - b.transferSize; } - - -WebInspector.Resource.StatusTextForCode = function(code) -{ - return code ? code + " " + WebInspector.Resource.StatusText[code] : ""; -} diff --git a/WebCore/inspector/front-end/ResourceView.js b/WebCore/inspector/front-end/ResourceView.js index fac57b4..ffcb9b9 100644 --- a/WebCore/inspector/front-end/ResourceView.js +++ b/WebCore/inspector/front-end/ResourceView.js @@ -35,28 +35,17 @@ WebInspector.ResourceView = function(resource) this.resource = resource; - this.tabsElement = document.createElement("div"); - this.tabsElement.className = "scope-bar"; - this.element.appendChild(this.tabsElement); - - this.headersTabElement = document.createElement("li"); - this.headersTabElement.textContent = WebInspector.UIString("Headers"); - this.contentTabElement = document.createElement("li"); - this.contentTabElement.textContent = WebInspector.UIString("Content"); - - this.tabsElement.appendChild(this.headersTabElement); - this.tabsElement.appendChild(this.contentTabElement); - - this.headersTabElement.addEventListener("click", this._selectHeadersTab.bind(this, true), false); - this.contentTabElement.addEventListener("click", this.selectContentTab.bind(this, true), false); + this.tabbedPane = new WebInspector.TabbedPane(this.element); this.headersElement = document.createElement("div"); this.headersElement.className = "resource-view-headers"; - this.element.appendChild(this.headersElement); + this.tabbedPane.appendTab("headers", WebInspector.UIString("Headers"), this.headersElement, this._selectHeadersTab.bind(this, true)); - this.contentElement = document.createElement("div"); - this.contentElement.className = "resource-view-content"; - this.element.appendChild(this.contentElement); + if (this.hasContentTab()) { + this.contentElement = document.createElement("div"); + this.contentElement.className = "resource-view-content"; + this.tabbedPane.appendTab("content", WebInspector.UIString("Content"), this.contentElement, this.selectContentTab.bind(this, true)); + } this.headersListElement = document.createElement("ol"); this.headersListElement.className = "outline-disclosure"; @@ -116,11 +105,10 @@ WebInspector.ResourceView = function(resource) resource.addEventListener("finished", this._refreshHTTPInformation, this); this._refreshURL(); + this._refreshQueryString(); this._refreshRequestHeaders(); this._refreshResponseHeaders(); this._refreshHTTPInformation(); - if (!this.hasContentTab()) - this.contentTabElement.addStyleClass("hidden"); this._selectTab(); } @@ -167,10 +155,7 @@ WebInspector.ResourceView.prototype = { { if (updatePrefs) WebInspector.settings.resourceViewTab = "headers"; - this.headersTabElement.addStyleClass("selected"); - this.contentTabElement.removeStyleClass("selected"); - this.headersElement.removeStyleClass("hidden"); - this.contentElement.addStyleClass("hidden"); + this.tabbedPane.selectTabById("headers"); }, selectContentTab: function(updatePrefs) @@ -188,10 +173,7 @@ WebInspector.ResourceView.prototype = { _innerSelectContentTab: function() { - this.contentTabElement.addStyleClass("selected"); - this.headersTabElement.removeStyleClass("selected"); - this.contentElement.removeStyleClass("hidden"); - this.headersElement.addStyleClass("hidden"); + this.tabbedPane.selectTabById("content"); if ("resize" in this) this.resize(); this.contentTabSelected(); @@ -245,8 +227,7 @@ WebInspector.ResourceView.prototype = { { this.requestPayloadTreeElement.removeChildren(); - var title = "<div class=\"header-name\"> </div>"; - title += "<div class=\"raw-form-data header-value source-code\">" + formData.escapeHTML() + "</div>"; + var title = "<div class=\"raw-form-data header-value source-code\">" + formData.escapeHTML() + "</div>"; var parmTreeElement = new TreeElement(title, null, false); parmTreeElement.selectable = false; this.requestPayloadTreeElement.appendChild(parmTreeElement); @@ -342,13 +323,15 @@ WebInspector.ResourceView.prototype = { statusImageSource = "Images/warningOrangeDot.png"; else statusImageSource = "Images/errorRedDot.png"; - statusCodeImage = "<img class=\"resource-status-image\" src=\"" + statusImageSource + "\" title=\"" + WebInspector.Resource.StatusTextForCode(this.resource.statusCode) + "\">"; + + var statusTextEscaped = this.resource.statusCode + " " + this.resource.statusText.escapeHTML(); + statusCodeImage = "<img class=\"resource-status-image\" src=\"" + statusImageSource + "\" title=\"" + statusTextEscaped + "\">"; requestMethodElement.title = "<div class=\"header-name\">" + WebInspector.UIString("Request Method") + ":</div>" + "<div class=\"header-value source-code\">" + this.resource.requestMethod + "</div>"; statusCodeElement.title = "<div class=\"header-name\">" + WebInspector.UIString("Status Code") + ":</div>" + - statusCodeImage + "<div class=\"header-value source-code\">" + WebInspector.Resource.StatusTextForCode(this.resource.statusCode) + "</div>"; + statusCodeImage + "<div class=\"header-value source-code\">" + statusTextEscaped + "</div>"; } }, diff --git a/WebCore/inspector/front-end/ScriptView.js b/WebCore/inspector/front-end/ScriptView.js index cb10889..1a24211 100644 --- a/WebCore/inspector/front-end/ScriptView.js +++ b/WebCore/inspector/front-end/ScriptView.js @@ -73,8 +73,7 @@ WebInspector.ScriptView.prototype = { _addBreakpoint: function(line) { - var breakpoint = new WebInspector.Breakpoint(this.script.sourceURL, line, this.script.sourceID); - WebInspector.panels.scripts.addBreakpoint(breakpoint); + WebInspector.breakpointManager.addBreakpoint(this.script.sourceID, this.script.sourceURL, line, true, ""); }, _editLineComplete: function(newBody) diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js index 6c817ac..755daff 100644 --- a/WebCore/inspector/front-end/ScriptsPanel.js +++ b/WebCore/inspector/front-end/ScriptsPanel.js @@ -164,12 +164,17 @@ WebInspector.ScriptsPanel = function() this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item", 3); this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions.bind(this), false); this._pauseOnExceptionButton.state = WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions; + this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions."); this._registerShortcuts(); this._debuggerEnabled = Preferences.debuggerAlwaysEnabled; if (Preferences.debuggerAlwaysEnabled) this._attachDebuggerWhenShown = true; + + WebInspector.breakpointManager.addEventListener("breakpoint-added", this._breakpointAdded, this); + WebInspector.breakpointManager.addEventListener("breakpoint-removed", this._breakpointRemoved, this); + this.reset(); } @@ -284,13 +289,13 @@ WebInspector.ScriptsPanel.prototype = { delete resource._scriptsPendingResourceLoad; }, - addBreakpoint: function(breakpoint) + _breakpointAdded: function(event) { + var breakpoint = event.data; + if (!this.breakpointsActivated) this._toggleBreakpointsClicked(); - this.sidebarPanes.breakpoints.addBreakpoint(breakpoint); - var sourceFrame; if (breakpoint.url) { var resource = WebInspector.resourceURLMap[breakpoint.url]; @@ -307,9 +312,9 @@ WebInspector.ScriptsPanel.prototype = { sourceFrame.addBreakpoint(breakpoint); }, - removeBreakpoint: function(breakpoint) + _breakpointRemoved: function(event) { - this.sidebarPanes.breakpoints.removeBreakpoint(breakpoint); + var breakpoint = event.data; var sourceFrame; if (breakpoint.url) { @@ -338,22 +343,18 @@ WebInspector.ScriptsPanel.prototype = { return; // Need to clear breakpoints and re-create them later when editing source. - var breakpointsPanel = this.sidebarPanes.breakpoints; - var newBreakpoints = []; - for (var id in breakpointsPanel.breakpoints) { - var breakpoint = breakpointsPanel.breakpoints[id]; - breakpointsPanel.removeBreakpoint(breakpoint); - newBreakpoints.push(breakpoint); - } + var breakpoints = WebInspector.breakpointManager.breakpointsForSourceID(sourceID); + for (var i = 0; i < breakpoints.length; ++i) + WebInspector.breakpointManager.removeBreakpoint(breakpoints[i]); function mycallback(newBody) { callback(newBody); - for (var i = 0; i < newBreakpoints.length; ++i) { - var breakpoint = newBreakpoints[i]; + for (var i = 0; i < breakpoints.length; ++i) { + var breakpoint = breakpoints[i]; if (breakpoint.line >= line) breakpoint.line += linesCountToShift; - this.addBreakpoint(breakpoint); + WebInspector.breakpointManager.addBreakpoint(breakpoint); } }; var callbackId = WebInspector.Callback.wrap(mycallback.bind(this)) @@ -611,14 +612,10 @@ WebInspector.ScriptsPanel.prototype = { return null; view = WebInspector.panels.resources.resourceViewForResource(scriptOrResource); view.headersVisible = false; - var breakpoints = this.sidebarPanes.breakpoints.breakpoints; - for (var breakpointId in breakpoints) { - var breakpoint = breakpoints[breakpointId]; - if (breakpoint.url === scriptOrResource.url) { - var sourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource); - sourceFrame.addBreakpoint(breakpoint); - } - } + var sourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource); + var breakpoints = WebInspector.breakpointManager.breakpointsForURL(scriptOrResource.url); + for (var i = 0; i < breakpoints.length; ++i) + sourceFrame.addBreakpoint(breakpoints[i]); } else if (scriptOrResource instanceof WebInspector.Script) view = this.scriptViewForScript(scriptOrResource); diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js index 953da11..5e529ae 100644 --- a/WebCore/inspector/front-end/SourceFrame.js +++ b/WebCore/inspector/front-end/SourceFrame.js @@ -428,7 +428,7 @@ WebInspector.SourceFrame.prototype = { contextMenu.appendItem(WebInspector.UIString("Add Conditional Breakpoint…"), addConditionalBreakpoint.bind(this)); } else { // This row has a breakpoint, we want to show edit and remove breakpoint, and either disable or enable. - contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), WebInspector.panels.scripts.removeBreakpoint.bind(WebInspector.panels.scripts, breakpoint)); + contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), this._removeBreakpointDelegate.bind(this, breakpoint)); contextMenu.appendItem(WebInspector.UIString("Edit Breakpoint…"), this._editBreakpointCondition.bind(this, breakpoint)); if (breakpoint.enabled) contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), function() { breakpoint.enabled = false; }); diff --git a/WebCore/inspector/front-end/SourceView.js b/WebCore/inspector/front-end/SourceView.js index 3621187..f01c241 100644 --- a/WebCore/inspector/front-end/SourceView.js +++ b/WebCore/inspector/front-end/SourceView.js @@ -51,6 +51,8 @@ WebInspector.SourceView.prototype = { { WebInspector.ResourceView.prototype.show.call(this, parentElement); this.sourceFrame.visible = true; + if (this.localSourceFrame) + this.localSourceFrame.visible = true; this.resize(); }, @@ -58,6 +60,8 @@ WebInspector.SourceView.prototype = { { WebInspector.View.prototype.hide.call(this); this.sourceFrame.visible = false; + if (this.localSourceFrame) + this.localSourceFrame.visible = false; this._currentSearchResultIndex = -1; }, @@ -65,6 +69,8 @@ WebInspector.SourceView.prototype = { { if (this.sourceFrame) this.sourceFrame.resize(); + if (this.localSourceFrame) + this.localSourceFrame.resize(); }, setupSourceFrameIfNeeded: function() @@ -112,16 +118,12 @@ WebInspector.SourceView.prototype = { _addBreakpoint: function(line) { var sourceID = this._sourceIDForLine(line); - if (WebInspector.panels.scripts) { - var breakpoint = new WebInspector.Breakpoint(this.resource.url, line, sourceID); - WebInspector.panels.scripts.addBreakpoint(breakpoint); - } + WebInspector.breakpointManager.addBreakpoint(sourceID, this.resource.url, line, true, ""); }, _removeBreakpoint: function(breakpoint) { - if (WebInspector.panels.scripts) - WebInspector.panels.scripts.removeBreakpoint(breakpoint); + WebInspector.breakpointManager.removeBreakpoint(breakpoint); }, _editLine: function(line, newContent) @@ -194,6 +196,25 @@ WebInspector.SourceView.prototype = { findSearchMatches.call(this, query, finishedCallback); }, + updateLocalContent: function(content, mimeType) + { + if (!this.localContentElement) { + this.localContentElement = document.createElement("div"); + this.localContentElement.className = "resource-view-content"; + this.tabbedPane.appendTab("local", WebInspector.UIString("Local"), this.localContentElement, this.selectLocalContentTab.bind(this)); + this.localSourceFrame = new WebInspector.SourceFrame(this.localContentElement, this._addBreakpoint.bind(this), this._removeBreakpoint.bind(this)); + } + this.localSourceFrame.setContent(mimeType, content, ""); + }, + + selectLocalContentTab: function() + { + this.tabbedPane.selectTabById("local"); + this.localSourceFrame.visible = true; + if ("resize" in this) + this.resize(); + }, + jumpToFirstSearchResult: function() { if (!this._searchResults || !this._searchResults.length) diff --git a/WebCore/inspector/front-end/TabbedPane.js b/WebCore/inspector/front-end/TabbedPane.js new file mode 100644 index 0000000..6acd163 --- /dev/null +++ b/WebCore/inspector/front-end/TabbedPane.js @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.TabbedPane = function(element) +{ + this.element = element || document.createElement("div"); + + this.tabsElement = document.createElement("div"); + this.tabsElement.className = "scope-bar"; + this.element.appendChild(this.tabsElement); + + this._tabObjects = {}; +} + +WebInspector.TabbedPane.prototype = { + appendTab: function(id, tabTitle, contentElement, tabClickListener) + { + var tabElement = document.createElement("li"); + tabElement.textContent = tabTitle; + tabElement.addEventListener("click", tabClickListener, false); + this.tabsElement.appendChild(tabElement); + this.element.appendChild(contentElement); + this._tabObjects[id] = {tab: tabElement, content: contentElement}; + }, + + tabObjectForId: function(id) + { + return this._tabObjects[id]; + }, + + hideTab: function(id) + { + var tabObject = this._tabObjects[id]; + if (tabObject) + tabObject.tab.addStyleClass("hidden"); + }, + + selectTabById: function(selectId) + { + var selected = false; + for (var id in this._tabObjects) { + var tabObject = this._tabObjects[id]; + if (id === selectId) { + selected = true; + tabObject.tab.addStyleClass("selected"); + tabObject.content.removeStyleClass("hidden"); + } else { + tabObject.tab.removeStyleClass("selected"); + tabObject.content.addStyleClass("hidden"); + } + } + return selected; + } +} diff --git a/WebCore/inspector/front-end/TextViewer.js b/WebCore/inspector/front-end/TextViewer.js index 1de1c12..cd06072 100644 --- a/WebCore/inspector/front-end/TextViewer.js +++ b/WebCore/inspector/front-end/TextViewer.js @@ -483,6 +483,9 @@ WebInspector.TextViewer.prototype = { if (selection.isCollapsed) return null; var selectionRange = selection.getRangeAt(0); + // Selection may be outside of the viewer. + if (!this.element.isAncestor(selectionRange.startContainer) || !this.element.isAncestor(selectionRange.endContainer)) + return null; var start = this._selectionToPosition(selectionRange.startContainer, selectionRange.startOffset); var end = this._selectionToPosition(selectionRange.endContainer, selectionRange.endOffset); return new WebInspector.TextRange(start.line, start.column, end.line, end.column); diff --git a/WebCore/inspector/front-end/TimelineOverviewPane.js b/WebCore/inspector/front-end/TimelineOverviewPane.js index 09431dc..3e83f62 100644 --- a/WebCore/inspector/front-end/TimelineOverviewPane.js +++ b/WebCore/inspector/front-end/TimelineOverviewPane.js @@ -30,32 +30,26 @@ WebInspector.TimelineOverviewPane = function(categories) { - this.element = document.createElement("div"); - this.element.id = "timeline-overview-panel"; - this._categories = categories; - this._overviewSidebarElement = document.createElement("div"); - this._overviewSidebarElement.id = "timeline-overview-sidebar"; - this.element.appendChild(this._overviewSidebarElement); - - var overviewTreeElement = document.createElement("ol"); - overviewTreeElement.className = "sidebar-tree"; - this._overviewSidebarElement.appendChild(overviewTreeElement); - var sidebarTree = new TreeOutline(overviewTreeElement); - - var categoriesTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("TIMELINES"), {}, true); - categoriesTreeElement.expanded = true; - sidebarTree.appendChild(categoriesTreeElement); + + this.statusBarFilters = document.createElement("div"); + this.statusBarFilters.id = "timeline-view-status-bar-items"; + this.statusBarFilters.addStyleClass("status-bar-item"); for (var categoryName in this._categories) { var category = this._categories[categoryName]; - categoriesTreeElement.appendChild(new WebInspector.TimelineCategoryTreeElement(category, this._onCheckboxClicked.bind(this, category))); + this.statusBarFilters.appendChild(this._createTimelineCategoryStatusBarCheckbox(category, this._onCheckboxClicked.bind(this, category))); } this._overviewGrid = new WebInspector.TimelineGrid(); this._overviewGrid.element.id = "timeline-overview-grid"; - this._overviewGrid.itemsGraphsElement.id = "timeline-overview-graphs"; + this._overviewGrid.itemsGraphsElement.id = "timeline-overview-timelines"; this._overviewGrid.element.addEventListener("mousedown", this._dragWindow.bind(this), true); - this.element.appendChild(this._overviewGrid.element); + + this._heapGraph = new WebInspector.HeapGraph(); + this._heapGraph.element.id = "timeline-overview-memory"; + this._overviewGrid.element.insertBefore(this._heapGraph.element, this._overviewGrid.itemsGraphsElement); + + this.element = this._overviewGrid.element; this._categoryGraphs = {}; var i = 0; @@ -90,10 +84,6 @@ WebInspector.TimelineOverviewPane = function(categories) this._overviewCalculator = new WebInspector.TimelineOverviewCalculator(); - var separatorElement = document.createElement("div"); - separatorElement.id = "timeline-overview-separator"; - this.element.appendChild(separatorElement); - this.windowLeft = 0.0; this.windowRight = 1.0; } @@ -101,6 +91,17 @@ WebInspector.TimelineOverviewPane = function(categories) WebInspector.TimelineOverviewPane.minSelectableSize = 12; WebInspector.TimelineOverviewPane.prototype = { + showTimelines: function(event) { + this._heapGraph.hide(); + this._overviewGrid.itemsGraphsElement.removeStyleClass("hidden"); + }, + + showMemoryGraph: function(records) { + this._heapGraph.show(); + this._heapGraph.update(records); + this._overviewGrid.itemsGraphsElement.addStyleClass("hidden"); + }, + _onCheckboxClicked: function (category, event) { if (event.target.checked) category.hidden = false; @@ -110,6 +111,16 @@ WebInspector.TimelineOverviewPane.prototype = { this.dispatchEventToListeners("filter changed"); }, + _forAllRecords: function(recordsArray, callback) + { + if (!recordsArray) + return; + for (var i = 0; i < recordsArray.length; ++i) { + callback(recordsArray[i]); + this._forAllRecords(recordsArray[i].children, callback); + } + }, + update: function(records, showShortEvents) { this._showShortEvents = showShortEvents; @@ -120,19 +131,9 @@ WebInspector.TimelineOverviewPane.prototype = { this._categoryGraphs[category].clearChunks(); } - function forAllRecords(recordsArray, callback) - { - if (!recordsArray) - return; - for (var i = 0; i < recordsArray.length; ++i) { - callback(recordsArray[i]); - forAllRecords(recordsArray[i].children, callback); - } - } - // Create sparse arrays with 101 cells each to fill with chunks for a given category. this._overviewCalculator.reset(); - forAllRecords(records, this._overviewCalculator.updateBoundaries.bind(this._overviewCalculator)); + this._forAllRecords(records, this._overviewCalculator.updateBoundaries.bind(this._overviewCalculator)); function markTimeline(record) { @@ -145,7 +146,7 @@ WebInspector.TimelineOverviewPane.prototype = { for (var j = Math.round(percentages.start); j <= end; ++j) timelines[categoryName][j] = true; } - forAllRecords(records, markTimeline.bind(this)); + this._forAllRecords(records, markTimeline.bind(this)); // Convert sparse arrays to continuous segments, render graphs for each. for (var category in this._categories) { @@ -168,6 +169,11 @@ WebInspector.TimelineOverviewPane.prototype = { chunkStart = -1; } } + + this._heapGraph.setSize(this._overviewGrid.element.offsetWidth, 60); + if (this._heapGraph.visible) + this._heapGraph.update(records); + this._overviewGrid.updateDividers(true, this._overviewCalculator); }, @@ -188,12 +194,7 @@ WebInspector.TimelineOverviewPane.prototype = { this._overviewGrid.addEventDividers(dividers); }, - setSidebarWidth: function(width) - { - this._overviewSidebarElement.style.width = width + "px"; - }, - - updateMainViewWidth: function(width) + updateMainViewWidth: function(width, records) { this._overviewGrid.element.style.left = width + "px"; }, @@ -328,7 +329,32 @@ WebInspector.TimelineOverviewPane.prototype = { _endWindowDragging: function(event) { WebInspector.elementDragEnd(event); + }, + + _createTimelineCategoryStatusBarCheckbox: function(category, onCheckboxClicked) + { + var labelContainer = document.createElement("div"); + labelContainer.addStyleClass("timeline-category-statusbar-item"); + labelContainer.addStyleClass("timeline-category-" + category.name); + labelContainer.addStyleClass("status-bar-item"); + + var label = document.createElement("label"); + var checkElement = document.createElement("input"); + checkElement.type = "checkbox"; + checkElement.className = "timeline-category-checkbox"; + checkElement.checked = true; + checkElement.addEventListener("click", onCheckboxClicked); + label.appendChild(checkElement); + + var typeElement = document.createElement("span"); + typeElement.className = "type"; + typeElement.textContent = category.title; + label.appendChild(typeElement); + + labelContainer.appendChild(label); + return labelContainer; } + } WebInspector.TimelineOverviewPane.prototype.__proto__ = WebInspector.Object.prototype; @@ -377,41 +403,6 @@ WebInspector.TimelineOverviewCalculator.prototype = { } -WebInspector.TimelineCategoryTreeElement = function(category, onCheckboxClicked) -{ - this._category = category; - this._onCheckboxClicked = onCheckboxClicked; - // Pass an empty title, the title gets made later in onattach. - TreeElement.call(this, "", null, false); -} - -WebInspector.TimelineCategoryTreeElement.prototype = { - onattach: function() - { - this.listItemElement.removeChildren(); - this.listItemElement.addStyleClass("timeline-category-tree-item"); - this.listItemElement.addStyleClass("timeline-category-" + this._category.name); - - var label = document.createElement("label"); - - var checkElement = document.createElement("input"); - checkElement.type = "checkbox"; - checkElement.className = "timeline-category-checkbox"; - checkElement.checked = true; - checkElement.addEventListener("click", this._onCheckboxClicked); - label.appendChild(checkElement); - - var typeElement = document.createElement("span"); - typeElement.className = "type"; - typeElement.textContent = this._category.title; - label.appendChild(typeElement); - - this.listItemElement.appendChild(label); - } -} - -WebInspector.TimelineCategoryTreeElement.prototype.__proto__ = TreeElement.prototype; - WebInspector.TimelineCategoryGraph = function(category, isEven) { this._category = category; @@ -497,3 +488,113 @@ WebInspector.TimelinePanel.WindowSelector.prototype = { } } +WebInspector.HeapGraph = function() { + this._canvas = document.createElement("canvas"); + + this._maxHeapSizeLabel = document.createElement("div"); + this._maxHeapSizeLabel.addStyleClass("memory-graph-label"); + + this._element = document.createElement("div"); + this._element.addStyleClass("hidden"); + this._element.appendChild(this._canvas); + this._element.appendChild(this._maxHeapSizeLabel); +} + +WebInspector.HeapGraph.prototype = { + get element() { + // return this._canvas; + return this._element; + }, + + get visible() { + return !this.element.hasStyleClass("hidden"); + }, + + show: function() { + this.element.removeStyleClass("hidden"); + }, + + hide: function() { + this.element.addStyleClass("hidden"); + }, + + setSize: function(w, h) { + this._canvas.width = w; + this._canvas.height = h - 5; + }, + + update: function(records) + { + if (!records.length) + return; + + var maxTotalHeapSize = 0; + var minTime; + var maxTime; + this._forAllRecords(records, function(r) { + if (r.totalHeapSize && r.totalHeapSize > maxTotalHeapSize) + maxTotalHeapSize = r.totalHeapSize; + + if (typeof minTime === "undefined" || r.startTime < minTime) + minTime = r.startTime; + if (typeof maxTime === "undefined" || r.endTime > maxTime) + maxTime = r.endTime; + }); + + var width = this._canvas.width; + var height = this._canvas.height; + var xFactor = width / (maxTime - minTime); + var yFactor = height / maxTotalHeapSize; + + var histogram = new Array(width); + this._forAllRecords(records, function(r) { + if (!r.usedHeapSize) + return; + var x = Math.round((r.endTime - minTime) * xFactor); + var y = Math.round(r.usedHeapSize * yFactor); + histogram[x] = Math.max(histogram[x] || 0, y); + }); + + var ctx = this._canvas.getContext("2d"); + this._clear(ctx); + + // +1 so that the border always fit into the canvas area. + height = height + 1; + + ctx.beginPath(); + var initialY = 0; + for (var k = 0; k < histogram.length; k++) { + if (histogram[k]) { + initialY = histogram[k]; + break; + } + } + ctx.moveTo(0, height - initialY); + + for (var x = 0; x < histogram.length; x++) { + if (!histogram[x]) + continue; + ctx.lineTo(x, height - histogram[x]); + } + + ctx.lineWidth = 0.5; + ctx.strokeStyle = "rgba(20,0,0,0.8)"; + ctx.stroke(); + + ctx.fillStyle = "rgba(214,225,254, 0.8);"; + ctx.lineTo(width, 60); + ctx.lineTo(0, 60); + ctx.lineTo(0, height - initialY); + ctx.fill(); + ctx.closePath(); + + this._maxHeapSizeLabel.textContent = Number.bytesToString(maxTotalHeapSize); + }, + + _clear: function(ctx) { + ctx.fillStyle = "rgba(255,255,255,0.8)"; + ctx.fillRect(0, 0, this._canvas.width, this._canvas.height); + }, + + _forAllRecords: WebInspector.TimelineOverviewPane.prototype._forAllRecords +} diff --git a/WebCore/inspector/front-end/TimelinePanel.js b/WebCore/inspector/front-end/TimelinePanel.js index af49c25..b9f0814 100644 --- a/WebCore/inspector/front-end/TimelinePanel.js +++ b/WebCore/inspector/front-end/TimelinePanel.js @@ -33,10 +33,7 @@ WebInspector.TimelinePanel = function() WebInspector.Panel.call(this); this.element.addStyleClass("timeline"); - this._overviewPane = new WebInspector.TimelineOverviewPane(this.categories); - this._overviewPane.addEventListener("window changed", this._windowChanged, this); - this._overviewPane.addEventListener("filter changed", this._refresh, this); - this.element.appendChild(this._overviewPane.element); + this.element.appendChild(this._createTopPane()); this.element.tabIndex = 0; this._sidebarBackgroundElement = document.createElement("div"); @@ -111,6 +108,39 @@ WebInspector.TimelinePanel.shortRecordThreshold = 0.015; WebInspector.TimelinePanel.prototype = { toolbarItemClass: "timeline", + _createTopPane: function() { + var topPaneElement = document.createElement("div"); + topPaneElement.id = "timeline-overview-panel"; + + this._topPaneSidebarElement = document.createElement("div"); + this._topPaneSidebarElement.id = "timeline-overview-sidebar"; + + var overviewTreeElement = document.createElement("ol"); + overviewTreeElement.className = "sidebar-tree"; + this._topPaneSidebarElement.appendChild(overviewTreeElement); + topPaneElement.appendChild(this._topPaneSidebarElement); + + var topPaneSidebarTree = new TreeOutline(overviewTreeElement); + var timelinesOverviewItem = new WebInspector.SidebarTreeElement("resources-time-graph-sidebar-item", WebInspector.UIString("Timelines")); + topPaneSidebarTree.appendChild(timelinesOverviewItem); + timelinesOverviewItem.onselect = this._timelinesOverviewItemSelected.bind(this); + timelinesOverviewItem.select(true); + + var memoryOverviewItem = new WebInspector.SidebarTreeElement("resources-size-graph-sidebar-item", WebInspector.UIString("Memory")); + topPaneSidebarTree.appendChild(memoryOverviewItem); + memoryOverviewItem.onselect = this._memoryOverviewItemSelected.bind(this); + + this._overviewPane = new WebInspector.TimelineOverviewPane(this.categories); + this._overviewPane.addEventListener("window changed", this._windowChanged, this); + this._overviewPane.addEventListener("filter changed", this._refresh, this); + topPaneElement.appendChild(this._overviewPane.element); + + var separatorElement = document.createElement("div"); + separatorElement.id = "timeline-overview-separator"; + topPaneElement.appendChild(separatorElement); + return topPaneElement; + }, + get toolbarItemLabel() { return WebInspector.UIString("Timeline"); @@ -118,7 +148,7 @@ WebInspector.TimelinePanel.prototype = { get statusBarItems() { - return [this.toggleFilterButton.element, this.toggleTimelineButton.element, this.clearButton.element, this.recordsCounter]; + return [this.toggleFilterButton.element, this.toggleTimelineButton.element, this.clearButton.element, this._overviewPane.statusBarFilters]; }, get categories() @@ -174,7 +204,7 @@ WebInspector.TimelinePanel.prototype = { this.toggleTimelineButton = new WebInspector.StatusBarButton(WebInspector.UIString("Record"), "record-profile-status-bar-item"); this.toggleTimelineButton.addEventListener("click", this._toggleTimelineButtonClicked.bind(this), false); - this.clearButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear"), "timeline-clear-status-bar-item"); + this.clearButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear"), "clear-status-bar-item"); this.clearButton.addEventListener("click", this._clearPanel.bind(this), false); this.toggleFilterButton = new WebInspector.StatusBarButton(this._hideShortRecordsTitleText, "timeline-filter-status-bar-item"); @@ -230,6 +260,14 @@ WebInspector.TimelinePanel.prototype = { return eventDividerPadding; }, + _timelinesOverviewItemSelected: function(event) { + this._overviewPane.showTimelines(); + }, + + _memoryOverviewItemSelected: function(event) { + this._overviewPane.showMemoryGraph(this._rootRecord.children); + }, + _toggleTimelineButtonClicked: function() { if (this.toggleTimelineButton.toggled) @@ -352,7 +390,7 @@ WebInspector.TimelinePanel.prototype = { { WebInspector.Panel.prototype.setSidebarWidth.call(this, width); this._sidebarBackgroundElement.style.width = width + "px"; - this._overviewPane.setSidebarWidth(width); + this._topPaneSidebarElement.style.width = width + "px"; }, updateMainViewWidth: function(width) @@ -398,12 +436,14 @@ WebInspector.TimelinePanel.prototype = { if (typeof this._scrollTop === "number") this._containerElement.scrollTop = this._scrollTop; this._refresh(); + WebInspector.drawer.currentPanelCounters = this.recordsCounter; }, hide: function() { WebInspector.Panel.prototype.hide.call(this); this._closeRecordDetails(); + WebInspector.drawer.currentPanelCounters = null; }, _onScroll: function(event) @@ -804,8 +844,10 @@ WebInspector.TimelinePanel.FormattedRecord = function(record, parentRecord, pane this._selfTime = this.endTime - this.startTime; this._lastChildEndTime = this.endTime; this.originalRecordForTests = record; - this.callerScriptName = record.callerScriptName; - this.callerScriptLine = record.callerScriptLine; + if (record.stackTrace && record.stackTrace.length) { + this.callerScriptName = record.stackTrace[0].scriptName; + this.callerScriptLine = record.stackTrace[0].lineNumber; + } this.totalHeapSize = record.totalHeapSize; this.usedHeapSize = record.usedHeapSize; diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc index 0f8d1ac..e93bf2c 100644 --- a/WebCore/inspector/front-end/WebKit.qrc +++ b/WebCore/inspector/front-end/WebKit.qrc @@ -8,7 +8,7 @@ <file>AuditRules.js</file> <file>AuditsPanel.js</file> <file>BottomUpProfileDataGridTree.js</file> - <file>Breakpoint.js</file> + <file>BreakpointManager.js</file> <file>BreakpointsSidebarPane.js</file> <file>Callback.js</file> <file>CallStackSidebarPane.js</file> @@ -77,6 +77,7 @@ <file>StoragePanel.js</file> <file>StylesSidebarPane.js</file> <file>SummaryBar.js</file> + <file>TabbedPane.js</file> <file>TestController.js</file> <file>TextEditorHighlighter.js</file> <file>TextEditorModel.js</file> diff --git a/WebCore/inspector/front-end/audits.css b/WebCore/inspector/front-end/audits.css index ad12db3..d36efc6 100644 --- a/WebCore/inspector/front-end/audits.css +++ b/WebCore/inspector/front-end/audits.css @@ -46,10 +46,6 @@ overflow: auto; } -button.clear-audit-results-status-bar-item .glyph { - -webkit-mask-image: url(Images/clearConsoleButtonGlyph.png); -} - .audit-launcher-view { z-index: 1000; position: absolute; diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css index 8a78247..ef34f2c 100644 --- a/WebCore/inspector/front-end/inspector.css +++ b/WebCore/inspector/front-end/inspector.css @@ -420,7 +420,7 @@ body.port-qt #dock-status-bar-item { -webkit-mask-image: url(Images/consoleButtonGlyph.png); } -#clear-console-status-bar-item .glyph { +.clear-status-bar-item .glyph { -webkit-mask-image: url(Images/clearConsoleButtonGlyph.png); } @@ -428,16 +428,12 @@ body.port-qt #dock-status-bar-item { -webkit-mask-image: url(Images/consoleButtonGlyph.png); /* TODO: Needs Image for Changes Toggle Button */ } -#clear-changes-status-bar-item .glyph { - -webkit-mask-image: url(Images/clearConsoleButtonGlyph.png); -} - -#count-items { +#counters { position: absolute; right: 16px; top: 0; cursor: pointer; - padding: 6px 2px; + padding: 6px 2px 6px 0px; font-size: 10px; height: 19px; } @@ -2713,6 +2709,15 @@ button.enable-toggle-status-bar-item.toggled-on .glyph { white-space: nowrap; } +.memory-graph-label { + position: absolute; + top: 5px; + left: 5px; + font-size: 9px; + color: rgb(50%, 50%, 50%); + white-space: nowrap; +} + .resources-graph-label { position: absolute; top: 0; @@ -3338,7 +3343,7 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { top: 0px; bottom: 0px; left: 0px; - padding-top: 1px; + padding-top: 2px; background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgb(242, 242, 242)), to(rgb(209, 209, 209))); border-right: 1px solid rgb(163, 163, 163); } @@ -3422,13 +3427,9 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { overflow-x: hidden; } -.timeline-clear-status-bar-item .glyph { - -webkit-mask-image: url(Images/clearConsoleButtonGlyph.png); -} - -.timeline-category-tree-item { - height: 20px; - line-height: 20px; +.timeline-category-statusbar-item { + height: 24px; + line-height: 24px; padding-left: 6px; white-space: nowrap; text-overflow: ellipsis; @@ -3436,7 +3437,7 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { font-weight: bold; } -.timeline-category-tree-item .timeline-category-checkbox { +.timeline-category-statusbar-item .timeline-category-checkbox { width: 10px; height: 11px; margin: 0 3px 0 5px; @@ -3448,26 +3449,22 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { -webkit-appearance: none; } -.timeline-category-tree-item .timeline-category-checkbox:checked { +.timeline-category-statusbar-item .timeline-category-checkbox:checked { background-position-x: -10px; } -.timeline-category-tree-item.timeline-category-loading .timeline-category-checkbox { +.timeline-category-statusbar-item.timeline-category-loading .timeline-category-checkbox { background-position-y: 0; } -.timeline-category-tree-item.timeline-category-scripting .timeline-category-checkbox { +.timeline-category-statusbar-item.timeline-category-scripting .timeline-category-checkbox { background-position-y: -33px; } -.timeline-category-tree-item.timeline-category-rendering .timeline-category-checkbox { +.timeline-category-statusbar-item.timeline-category-rendering .timeline-category-checkbox { background-position-y: -11px; } -.timeline-category-tree-item:nth-of-type(2n) { - background-color: rgba(0, 0, 0, 0.05); -} - .timeline-tree-item { height: 18px; line-height: 15px; @@ -3533,14 +3530,25 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { color: rgba(0, 0, 0, 0.7); } -#timeline-overview-graphs { +#timeline-overview-timelines, +#timeline-overview-memory { position: absolute; left: 0; right: 0; bottom: 0; top: 20px; + z-index: 160; +} + +#timeline-overview-memory > canvas { + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 5px; } + #timeline-graphs { position: absolute; left: 0; @@ -3688,12 +3696,20 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { .timeline-records-counter { font-size: 11px; - position: relative; - top: 5px; - margin-left: 5px; text-shadow: white 0 1px 0; } +#main-status-bar > .timeline-records-counter { + float: right; + margin-top: 4px; + margin-right: 25px; +} + +#counters > .timeline-records-counter { + float: left; + margin-top: -2px; +} + /* Profiler Style */ #profile-views { @@ -3704,6 +3720,7 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { bottom: 0; } +#timeline-view-status-bar-items, #profile-view-status-bar-items { position: absolute; top: 0; diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html index 74bddaf..75b31eb 100644 --- a/WebCore/inspector/front-end/inspector.html +++ b/WebCore/inspector/front-end/inspector.html @@ -46,6 +46,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="KeyboardShortcut.js"></script> <script type="text/javascript" src="TextPrompt.js"></script> <script type="text/javascript" src="Popover.js"></script> + <script type="text/javascript" src="TabbedPane.js"></script> <script type="text/javascript" src="Placard.js"></script> <script type="text/javascript" src="View.js"></script> <script type="text/javascript" src="Callback.js"></script> @@ -63,7 +64,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="DataGrid.js"></script> <script type="text/javascript" src="CookieItemsView.js"></script> <script type="text/javascript" src="Script.js"></script> - <script type="text/javascript" src="Breakpoint.js"></script> + <script type="text/javascript" src="BreakpointManager.js"></script> <script type="text/javascript" src="SidebarPane.js"></script> <script type="text/javascript" src="ElementsTreeOutline.js"></script> <script type="text/javascript" src="SidebarTreeElement.js"></script> @@ -137,11 +138,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. </div> <div id="main"> <div id="main-panels" spellcheck="false"></div> - <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="changes-status-bar-item" class="status-bar-item hidden"></button><div id="count-items"><div id="changes-count" class="hidden"></div><div id="error-warning-count" class="hidden"></div></div></div></div> + <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="changes-status-bar-item" class="status-bar-item hidden"></button><div id="counters"><div id="changes-count" class="hidden"></div><div id="error-warning-count" class="hidden"></div></div></div></div> </div> <div id="drawer"> <div id="console-view"><div id="console-messages" class="monospace"><div id="console-prompt" spellcheck="false"><br></div></div></div> - <div id="drawer-status-bar" class="status-bar"><div id="other-drawer-status-bar-items"><button id="clear-console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><div id="console-filter" class="scope-bar status-bar-item"></div></div></div> + <div id="drawer-status-bar" class="status-bar"><div id="other-drawer-status-bar-items"><button id="clear-console-status-bar-item" class="status-bar-item clear-status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><div id="console-filter" class="scope-bar status-bar-item"></div></div></div> </div> </body> </html> diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js index 06ae503..8c25be5 100644 --- a/WebCore/inspector/front-end/inspector.js +++ b/WebCore/inspector/front-end/inspector.js @@ -465,6 +465,8 @@ WebInspector.loaded = function() other: new WebInspector.ResourceCategory("other", WebInspector.UIString("Other"), "rgb(186,186,186)") }; + this.breakpointManager = new WebInspector.BreakpointManager(); + this.panels = {}; this._createPanels(); this._panelHistory = new WebInspector.PanelHistory(); @@ -705,19 +707,20 @@ WebInspector._registerShortcuts = function() WebInspector.documentKeyDown = function(event) { + var isInEditMode = event.target.enclosingNodeOrSelfWithClass("text-prompt") || WebInspector.isEditingAnyField(); const helpKey = WebInspector.isMac() ? "U+003F" : "U+00BF"; // "?" for both platforms if (event.keyIdentifier === "F1" || - (event.keyIdentifier === helpKey && (!WebInspector.isEditingAnyField() || event.metaKey))) { - WebInspector.shortcutsHelp.show(); - event.stopPropagation(); - event.preventDefault(); + (event.keyIdentifier === helpKey && event.shiftKey && (!isInEditMode || event.metaKey))) { + WebInspector.shortcutsHelp.show(); + event.stopPropagation(); + event.preventDefault(); + return; } if (WebInspector.isEditingAnyField()) return; - var isInTextPrompt = event.target.enclosingNodeOrSelfWithClass("text-prompt"); if (this.currentFocusElement && this.currentFocusElement.handleKeyEvent) { this.currentFocusElement.handleKeyEvent(event); if (event.handled) { @@ -737,7 +740,7 @@ WebInspector.documentKeyDown = function(event) var isMac = WebInspector.isMac(); switch (event.keyIdentifier) { case "Left": - var isBackKey = !isInTextPrompt && (isMac ? event.metaKey : event.ctrlKey); + var isBackKey = !isInEditMode && (isMac ? event.metaKey : event.ctrlKey); if (isBackKey && this._panelHistory.canGoBack()) { this._panelHistory.goBack(); event.preventDefault(); @@ -745,7 +748,7 @@ WebInspector.documentKeyDown = function(event) break; case "Right": - var isForwardKey = !isInTextPrompt && (isMac ? event.metaKey : event.ctrlKey); + var isForwardKey = !isInEditMode && (isMac ? event.metaKey : event.ctrlKey); if (isForwardKey && this._panelHistory.canGoForward()) { this._panelHistory.goForward(); event.preventDefault(); @@ -1159,6 +1162,7 @@ WebInspector.updateResource = function(identifier, payload) resource.suggestedFilename = payload.suggestedFilename; resource.expectedContentLength = payload.expectedContentLength; resource.statusCode = payload.statusCode; + resource.statusText = payload.statusText; resource.suggestedFilename = payload.suggestedFilename; resource.responseHeaders = payload.responseHeaders; } @@ -1321,9 +1325,7 @@ WebInspector.parsedScriptSource = function(sourceID, sourceURL, source, starting WebInspector.restoredBreakpoint = function(sourceID, sourceURL, line, enabled, condition) { - var breakpoint = new WebInspector.Breakpoint(sourceURL, line, sourceID, condition); - breakpoint.enabled = enabled; - this.panels.scripts.addBreakpoint(breakpoint); + this.breakpointManager.addBreakpoint(sourceID, sourceURL, line, enabled, condition); } WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLine, errorLine, errorMessage) @@ -1358,6 +1360,8 @@ WebInspector.reset = function() panel.reset(); } + this.breakpointManager.reset(); + for (var category in this.resourceCategories) this.resourceCategories[category].removeAllResources(); diff --git a/WebCore/inspector/front-end/treeoutline.js b/WebCore/inspector/front-end/treeoutline.js index 7d58954..297bbab 100644 --- a/WebCore/inspector/front-end/treeoutline.js +++ b/WebCore/inspector/front-end/treeoutline.js @@ -389,6 +389,12 @@ TreeOutline.prototype._treeKeyDown = function(event) this.selectedTreeElement.expand(); } } + } else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Backspace.code || event.keyCode === WebInspector.KeyboardShortcut.Keys.Delete.code) { + if (this.selectedTreeElement.ondelete) + handled = this.selectedTreeElement.ondelete(); + } else if (isEnterKey(event)) { + if (this.selectedTreeElement.onenter) + handled = this.selectedTreeElement.onenter(); } if (nextSelectedElement) { diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js index f87b53d..9ad1c10 100644 --- a/WebCore/inspector/front-end/utilities.js +++ b/WebCore/inspector/front-end/utilities.js @@ -369,7 +369,7 @@ String.prototype.escapeForRegExp = function() String.prototype.escapeHTML = function() { - return this.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); + return this.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """); } String.prototype.collapseWhitespace = function() @@ -621,7 +621,7 @@ Number.bytesToString = function(bytes, formatterFunction, higherResolution) var megabytes = kilobytes / 1024; if (higherResolution) - return formatterFunction("%.3fMB", megabytes); + return formatterFunction("%.2fMB", megabytes); else return formatterFunction("%.0fMB", megabytes); } |