Changeset 178137 in webkit


Ignore:
Timestamp:
Jan 8, 2015 3:16:48 PM (9 years ago)
Author:
Joseph Pecoraro
Message:

Web Inspector: Pause Reason Improvements (Breakpoint, Debugger Statement, Pause on Next Statement)
https://bugs.webkit.org/show_bug.cgi?id=138991

Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

  • debugger/Debugger.cpp:

(JSC::Debugger::Debugger):
(JSC::Debugger::pauseIfNeeded):
(JSC::Debugger::didReachBreakpoint):
When actually pausing, if we hit a breakpoint ensure the reason
is PausedForBreakpoint, otherwise use the current reason.

  • debugger/Debugger.h:

Make pause reason and pausing breakpoint ID public.

  • inspector/agents/InspectorDebuggerAgent.h:
  • inspector/agents/InspectorDebuggerAgent.cpp:

(Inspector::buildAssertPauseReason):
(Inspector::buildCSPViolationPauseReason):
(Inspector::InspectorDebuggerAgent::buildBreakpointPauseReason):
(Inspector::InspectorDebuggerAgent::buildExceptionPauseReason):
(Inspector::InspectorDebuggerAgent::handleConsoleAssert):
(Inspector::buildObjectForBreakpointCookie):
(Inspector::InspectorDebuggerAgent::setBreakpointByUrl):
(Inspector::InspectorDebuggerAgent::removeBreakpoint):
(Inspector::InspectorDebuggerAgent::resolveBreakpoint):
(Inspector::InspectorDebuggerAgent::pause):
(Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP):
(Inspector::InspectorDebuggerAgent::currentCallFrames):
(Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
Clean up creation of pause reason objects and other cleanup
of PassRefPtr use and InjectedScript use.

(Inspector::InspectorDebuggerAgent::didPause):
Clean up so that we first check for an Exception, and then fall
back to including a Pause Reason derived from the Debugger.

  • inspector/protocol/Debugger.json:

Add new DebuggerStatement, Breakpoint, and PauseOnNextStatement reasons.

Source/WebInspectorUI:

  • Localizations/en.lproj/localizedStrings.js:

New UI strings for Pause Reasons.

  • UserInterface/Controllers/DebuggerManager.js:

(WebInspector.DebuggerManager.prototype.breakpointForIdentifier):
Provide a way to get the breakpoint with an identifier.

  • UserInterface/Images/PausedBreakpoint.svg: Added.
  • UserInterface/Images/gtk/PausedBreakpoint.svg: Added.

Copy PseudoElement.svg icon and give it a new name.

  • UserInterface/Views/BreakpointTreeElement.css:

(.breakpoint-paused-icon .icon):
New icon for a breakpoint causing a pause.

  • UserInterface/Views/BreakpointTreeElement.js:

(WebInspector.BreakpointTreeElement.prototype.removeStatusImage):
(WebInspector.BreakpointTreeElement.prototype._updateStatus):
Give API to remove the breakpoint status icon from a BreakpointTreeElement.

  • UserInterface/Views/DebuggerSidebarPanel.js:

(WebInspector.DebuggerSidebarPanel):
(WebInspector.DebuggerSidebarPanel.prototype.get hasSelectedElement):
(WebInspector.DebuggerSidebarPanel.prototype.deselectBreakpointContentTreeElements):
(WebInspector.DebuggerSidebarPanel.prototype.deselectPauseReasonContentTreeElements):
(WebInspector.DebuggerSidebarPanel.prototype._treeElementSelected):
Give DebuggerSidebarPanel an optional pause reason tree outline. When available
include it in the pattern of ensuring a single exclusive selection.

(WebInspector.DebuggerSidebarPanel.prototype._breakpointRemoved):
When a breakpoint is removed, check if we should update the pause reason tree outline.

(WebInspector.DebuggerSidebarPanel.prototype._updatePauseReason):
(WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
Update Pause Reason section contents depending on the reason.

(WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonGotoArrow):
Always try to include a goto arrow to jump to the original pause location
if it is available at the time of pausing.

LayoutTests:

Test that the frontend receives expected pause reasons for different kinds of pauses.

  • inspector/debugger/pause-reason-expected.txt: Added.
  • inspector/debugger/pause-reason.html: Added.
  • inspector/debugger/resources/pause-reasons.js: Added.

(triggerBreakpoint):
(triggerException):
(triggerDebuggerStatement):
(triggerAssert):

Location:
trunk
Files:
5 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r178128 r178137  
     12015-01-08  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Pause Reason Improvements (Breakpoint, Debugger Statement, Pause on Next Statement)
     4        https://bugs.webkit.org/show_bug.cgi?id=138991
     5
     6        Reviewed by Timothy Hatcher.
     7
     8        Test that the frontend receives expected pause reasons for different kinds of pauses.
     9
     10        * inspector/debugger/pause-reason-expected.txt: Added.
     11        * inspector/debugger/pause-reason.html: Added.
     12        * inspector/debugger/resources/pause-reasons.js: Added.
     13        (triggerBreakpoint):
     14        (triggerException):
     15        (triggerDebuggerStatement):
     16        (triggerAssert):
     17
    1182015-01-08  Darin Adler  <darin@apple.com>
    219
  • trunk/Source/JavaScriptCore/ChangeLog

    r178127 r178137  
     12015-01-08  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Pause Reason Improvements (Breakpoint, Debugger Statement, Pause on Next Statement)
     4        https://bugs.webkit.org/show_bug.cgi?id=138991
     5
     6        Reviewed by Timothy Hatcher.
     7
     8        * debugger/Debugger.cpp:
     9        (JSC::Debugger::Debugger):
     10        (JSC::Debugger::pauseIfNeeded):
     11        (JSC::Debugger::didReachBreakpoint):
     12        When actually pausing, if we hit a breakpoint ensure the reason
     13        is PausedForBreakpoint, otherwise use the current reason.
     14
     15        * debugger/Debugger.h:
     16        Make pause reason and pausing breakpoint ID public.
     17
     18        * inspector/agents/InspectorDebuggerAgent.h:
     19        * inspector/agents/InspectorDebuggerAgent.cpp:
     20        (Inspector::buildAssertPauseReason):
     21        (Inspector::buildCSPViolationPauseReason):
     22        (Inspector::InspectorDebuggerAgent::buildBreakpointPauseReason):
     23        (Inspector::InspectorDebuggerAgent::buildExceptionPauseReason):
     24        (Inspector::InspectorDebuggerAgent::handleConsoleAssert):
     25        (Inspector::buildObjectForBreakpointCookie):
     26        (Inspector::InspectorDebuggerAgent::setBreakpointByUrl):
     27        (Inspector::InspectorDebuggerAgent::removeBreakpoint):
     28        (Inspector::InspectorDebuggerAgent::resolveBreakpoint):
     29        (Inspector::InspectorDebuggerAgent::pause):
     30        (Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP):
     31        (Inspector::InspectorDebuggerAgent::currentCallFrames):
     32        (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
     33        Clean up creation of pause reason objects and other cleanup
     34        of PassRefPtr use and InjectedScript use.
     35
     36        (Inspector::InspectorDebuggerAgent::didPause):
     37        Clean up so that we first check for an Exception, and then fall
     38        back to including a Pause Reason derived from the Debugger.
     39
     40        * inspector/protocol/Debugger.json:
     41        Add new DebuggerStatement, Breakpoint, and PauseOnNextStatement reasons.
     42
    1432015-01-08  Joseph Pecoraro  <pecoraro@apple.com>
    244
  • trunk/Source/JavaScriptCore/debugger/Debugger.cpp

    r177585 r178137  
    161161    , m_lastExecutedSourceID(noSourceID)
    162162    , m_topBreakpointID(noBreakpointID)
     163    , m_pausingBreakpointID(noBreakpointID)
    163164{
    164165}
     
    671672        if (breakpoint.autoContinue || !m_currentCallFrame)
    672673            return;
    673     }
    674 
    675     handlePause(vmEntryGlobalObject, m_reasonForPause);
     674        m_pausingBreakpointID = breakpoint.id;
     675    }
     676
     677    {
     678        PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause);
     679        handlePause(vmEntryGlobalObject, m_reasonForPause);
     680    }
     681
     682    m_pausingBreakpointID = noBreakpointID;
    676683
    677684    if (!m_pauseOnNextStatement && !m_pauseOnCallFrame) {
     
    780787        return;
    781788
    782     PauseReasonDeclaration reason(*this, PausedForBreakpoint);
     789    PauseReasonDeclaration reason(*this, PausedForDebuggerStatement);
    783790    m_pauseOnNextStatement = true;
    784791    setSteppingMode(SteppingModeEnabled);
  • trunk/Source/JavaScriptCore/debugger/Debugger.h

    r177585 r178137  
    8484    void setPauseOnExceptionsState(PauseOnExceptionsState);
    8585
    86     void setPauseOnNextStatement(bool);
    87     void breakProgram();
    88     void continueProgram();
    89     void stepIntoStatement();
    90     void stepOverStatement();
    91     void stepOutOfFunction();
    92 
    93     bool isPaused() const { return m_isPaused; }
    94     bool isStepping() const { return m_steppingMode == SteppingModeEnabled; }
    95 
    96     virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0;
    97 
    98     void exception(CallFrame*, JSValue exceptionValue, bool hasHandler);
    99     void atStatement(CallFrame*);
    100     void callEvent(CallFrame*);
    101     void returnEvent(CallFrame*);
    102     void willExecuteProgram(CallFrame*);
    103     void didExecuteProgram(CallFrame*);
    104     void didReachBreakpoint(CallFrame*);
    105 
    106     void recompileAllJSFunctions(VM*);
    107 
    108     void registerCodeBlock(CodeBlock*);
    109 
    110 protected:
    111     virtual bool needPauseHandling(JSGlobalObject*) { return false; }
    112     virtual void handleBreakpointHit(JSGlobalObject*, const Breakpoint&) { }
    113     virtual void handleExceptionInBreakpointCondition(ExecState*, JSValue exception) const { UNUSED_PARAM(exception); }
    114 
    11586    enum ReasonForPause {
    11687        NotPaused,
     
    12192        PausedAtStartOfProgram,
    12293        PausedAtEndOfProgram,
    123         PausedForBreakpoint
    124     };
    125 
     94        PausedForBreakpoint,
     95        PausedForDebuggerStatement,
     96    };
    12697    ReasonForPause reasonForPause() const { return m_reasonForPause; }
    127 
     98    BreakpointID pausingBreakpointID() const { return m_pausingBreakpointID; }
     99
     100    void setPauseOnNextStatement(bool);
     101    void breakProgram();
     102    void continueProgram();
     103    void stepIntoStatement();
     104    void stepOverStatement();
     105    void stepOutOfFunction();
     106
     107    bool isPaused() const { return m_isPaused; }
     108    bool isStepping() const { return m_steppingMode == SteppingModeEnabled; }
     109
     110    virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0;
     111
     112    void exception(CallFrame*, JSValue exceptionValue, bool hasHandler);
     113    void atStatement(CallFrame*);
     114    void callEvent(CallFrame*);
     115    void returnEvent(CallFrame*);
     116    void willExecuteProgram(CallFrame*);
     117    void didExecuteProgram(CallFrame*);
     118    void didReachBreakpoint(CallFrame*);
     119
     120    void recompileAllJSFunctions(VM*);
     121
     122    void registerCodeBlock(CodeBlock*);
     123
     124protected:
     125    virtual bool needPauseHandling(JSGlobalObject*) { return false; }
     126    virtual void handleBreakpointHit(JSGlobalObject*, const Breakpoint&) { }
     127    virtual void handleExceptionInBreakpointCondition(ExecState*, JSValue exception) const { UNUSED_PARAM(exception); }
    128128    virtual void handlePause(JSGlobalObject*, ReasonForPause) { }
    129129    virtual void notifyDoneProcessingDebuggerEvents() { }
     
    206206
    207207    BreakpointID m_topBreakpointID;
     208    BreakpointID m_pausingBreakpointID;
    208209    BreakpointIDToBreakpointMap m_breakpointIDToBreakpoint;
    209210    SourceIDToBreakpointsMap m_sourceIDToBreakpoints;
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp

    r178060 r178137  
    139139}
    140140
     141static RefPtr<InspectorObject> buildAssertPauseReason(const String& message)
     142{
     143    auto reason = Inspector::Protocol::Debugger::AssertPauseReason::create().release();
     144    if (!message.isNull())
     145        reason->setMessage(message);
     146    return reason->openAccessors();
     147}
     148
     149static RefPtr<InspectorObject> buildCSPViolationPauseReason(const String& directiveText)
     150{
     151    auto reason = Inspector::Protocol::Debugger::CSPViolationPauseReason::create()
     152        .setDirective(directiveText)
     153        .release();
     154    return reason->openAccessors();
     155}
     156
     157RefPtr<InspectorObject> InspectorDebuggerAgent::buildBreakpointPauseReason(JSC::BreakpointID debuggerBreakpointIdentifier)
     158{
     159    ASSERT(debuggerBreakpointIdentifier != JSC::noBreakpointID);
     160    auto it = m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.find(debuggerBreakpointIdentifier);
     161    if (it == m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.end())
     162        return nullptr;
     163
     164    auto reason = Inspector::Protocol::Debugger::BreakpointPauseReason::create()
     165        .setBreakpointId(it->value)
     166        .release();
     167    return reason->openAccessors();
     168}
     169
     170RefPtr<InspectorObject> InspectorDebuggerAgent::buildExceptionPauseReason(const Deprecated::ScriptValue& exception, const InjectedScript& injectedScript)
     171{
     172    ASSERT(!exception.hasNoValue());
     173    if (exception.hasNoValue())
     174        return nullptr;
     175
     176    ASSERT(!injectedScript.hasNoValue());
     177    if (injectedScript.hasNoValue())
     178        return nullptr;
     179
     180    return injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors();
     181}
     182
    141183void InspectorDebuggerAgent::handleConsoleAssert(const String& message)
    142184{
    143     if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions) {
    144         Ref<Inspector::Protocol::Debugger::AssertPauseReason> reason = Inspector::Protocol::Debugger::AssertPauseReason::create().release();
    145         if (!message.isNull())
    146             reason->setMessage(message);
    147         breakProgram(InspectorDebuggerFrontendDispatcher::Reason::Assert, reason->openAccessors());
    148     }
     185    if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions)
     186        breakProgram(InspectorDebuggerFrontendDispatcher::Reason::Assert, buildAssertPauseReason(message));
    149187}
    150188
     
    343381
    344382    for (JSC::BreakpointID breakpointID : m_breakpointIdentifierToDebugServerBreakpointIDs.take(breakpointIdentifier)) {
     383        m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.remove(breakpointID);
     384
    345385        const BreakpointActions& breakpointActions = scriptDebugServer().getActionsForBreakpoint(breakpointID);
    346386        for (auto& action : breakpointActions)
     
    388428        debugServerBreakpointIDsIterator = m_breakpointIdentifierToDebugServerBreakpointIDs.set(breakpointIdentifier, Vector<JSC::BreakpointID>()).iterator;
    389429    debugServerBreakpointIDsIterator->value.append(debugServerBreakpointID);
     430   
     431    m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.set(debugServerBreakpointID, breakpointIdentifier);
    390432
    391433    auto location = Inspector::Protocol::Debugger::Location::create()
     
    453495void InspectorDebuggerAgent::pause(ErrorString&)
    454496{
    455     if (m_javaScriptPauseScheduled)
    456         return;
    457 
    458     clearBreakDetails();
    459     scriptDebugServer().setPauseOnNextStatement(true);
     497    schedulePauseOnNextStatement(InspectorDebuggerFrontendDispatcher::Reason::PauseOnNextStatement, nullptr);
     498
    460499    m_javaScriptPauseScheduled = true;
    461500}
     
    545584void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText)
    546585{
    547     if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions) {
    548         auto reason = Inspector::Protocol::Debugger::CSPViolationPauseReason::create()
    549             .setDirective(directiveText)
    550             .release();
    551         breakProgram(InspectorDebuggerFrontendDispatcher::Reason::CSPViolation, reason->openAccessors());
    552     }
    553 }
    554 
    555 Ref<Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>> InspectorDebuggerAgent::currentCallFrames()
    556 {
    557     if (!m_pausedScriptState)
     586    if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions)
     587        breakProgram(InspectorDebuggerFrontendDispatcher::Reason::CSPViolation, buildCSPViolationPauseReason(directiveText));
     588}
     589
     590Ref<Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>> InspectorDebuggerAgent::currentCallFrames(InjectedScript injectedScript)
     591{
     592    ASSERT(!injectedScript.hasNoValue());
     593    if (injectedScript.hasNoValue())
    558594        return Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>::create();
    559 
    560     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState);
    561     if (injectedScript.hasNoValue()) {
    562         ASSERT_NOT_REACHED();
    563         return Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>::create();
    564     }
    565595
    566596    return injectedScript.wrapCallFrames(m_currentCallStack);
     
    628658}
    629659
    630 void InspectorDebuggerAgent::didPause(JSC::ExecState* scriptState, const Deprecated::ScriptValue& callFrames, const Deprecated::ScriptValue& exception)
     660void InspectorDebuggerAgent::didPause(JSC::ExecState* scriptState, const Deprecated::ScriptValue& callFrames, const Deprecated::ScriptValue& exceptionOrCaughtValue)
    631661{
    632662    ASSERT(scriptState && !m_pausedScriptState);
     
    634664    m_currentCallStack = callFrames;
    635665
    636     if (!exception.hasNoValue()) {
    637         InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
    638         if (!injectedScript.hasNoValue()) {
     666    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
     667
     668    // If a high level pause pause reason is not already set, try to infer a reason from the debugger.
     669    if (m_breakReason == InspectorDebuggerFrontendDispatcher::Reason::Other) {
     670        switch (scriptDebugServer().reasonForPause()) {
     671        case JSC::Debugger::PausedForBreakpoint: {
     672            JSC::BreakpointID debuggerBreakpointId = scriptDebugServer().pausingBreakpointID();
     673            if (debuggerBreakpointId != m_continueToLocationBreakpointID) {
     674                m_breakReason = InspectorDebuggerFrontendDispatcher::Reason::Breakpoint;
     675                m_breakAuxData = buildBreakpointPauseReason(debuggerBreakpointId);
     676            }
     677            break;
     678        }
     679        case JSC::Debugger::PausedForDebuggerStatement:
     680            m_breakReason = InspectorDebuggerFrontendDispatcher::Reason::DebuggerStatement;
     681            m_breakAuxData = nullptr;
     682            break;
     683        case JSC::Debugger::PausedForException:
    639684            m_breakReason = InspectorDebuggerFrontendDispatcher::Reason::Exception;
    640             m_breakAuxData = injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors();
    641             // m_breakAuxData might be null after this.
    642             injectedScript.setExceptionValue(exception);
    643             m_hasExceptionValue = true;
     685            m_breakAuxData = buildExceptionPauseReason(exceptionOrCaughtValue, injectedScript);
     686            break;
     687        case JSC::Debugger::PausedAtStatement:
     688        case JSC::Debugger::PausedAfterCall:
     689        case JSC::Debugger::PausedBeforeReturn:
     690        case JSC::Debugger::PausedAtStartOfProgram:
     691        case JSC::Debugger::PausedAtEndOfProgram:
     692            // Pause was just stepping. Nothing to report.
     693            break;
     694        case JSC::Debugger::NotPaused:
     695            ASSERT_NOT_REACHED();
     696            break;
    644697        }
    645698    }
    646699
    647     m_frontendDispatcher->paused(currentCallFrames(), m_breakReason, m_breakAuxData);
     700    // Set $exception to the exception or caught value.
     701    if (!exceptionOrCaughtValue.hasNoValue() && !injectedScript.hasNoValue()) {
     702        injectedScript.setExceptionValue(exceptionOrCaughtValue);
     703        m_hasExceptionValue = true;
     704    }
     705
     706    m_frontendDispatcher->paused(currentCallFrames(injectedScript), m_breakReason, m_breakAuxData);
    648707    m_javaScriptPauseScheduled = false;
    649708
     
    721780    m_scripts.clear();
    722781    m_breakpointIdentifierToDebugServerBreakpointIDs.clear();
     782    m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.clear();
    723783    m_continueToLocationBreakpointID = JSC::noBreakpointID;
    724784    clearBreakDetails();
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h

    r178060 r178137  
    124124    virtual void enable();
    125125    virtual void disable(bool skipRecompile);
    126     virtual void didPause(JSC::ExecState*, const Deprecated::ScriptValue& callFrames, const Deprecated::ScriptValue& exception) override;
     126    virtual void didPause(JSC::ExecState*, const Deprecated::ScriptValue& callFrames, const Deprecated::ScriptValue& exceptionOrCaughtValue) override;
    127127    virtual void didContinue() override;
    128128
     
    132132
    133133private:
    134     Ref<Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>> currentCallFrames();
     134    Ref<Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>> currentCallFrames(InjectedScript);
    135135
    136136    virtual void didParseSource(JSC::SourceID, const Script&) override final;
     
    147147    void clearExceptionValue();
    148148
     149    RefPtr<InspectorObject> buildBreakpointPauseReason(JSC::BreakpointID);
     150    RefPtr<InspectorObject> buildExceptionPauseReason(const Deprecated::ScriptValue& exception, const InjectedScript&);
     151
    149152    bool breakpointActionsFromProtocol(ErrorString&, RefPtr<InspectorArray>& actions, BreakpointActions* result);
    150153
     
    152155    typedef HashMap<String, Vector<JSC::BreakpointID>> BreakpointIdentifierToDebugServerBreakpointIDsMap;
    153156    typedef HashMap<String, RefPtr<InspectorObject>> BreakpointIdentifierToBreakpointMap;
     157    typedef HashMap<JSC::BreakpointID, String> DebugServerBreakpointIDToBreakpointIdentifier;
    154158
    155159    InjectedScriptManager* m_injectedScriptManager;
     
    162166    BreakpointIdentifierToDebugServerBreakpointIDsMap m_breakpointIdentifierToDebugServerBreakpointIDs;
    163167    BreakpointIdentifierToBreakpointMap m_javaScriptBreakpoints;
     168    DebugServerBreakpointIDToBreakpointIdentifier m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier;
    164169    JSC::BreakpointID m_continueToLocationBreakpointID;
    165170    InspectorDebuggerFrontendDispatcher::Reason m_breakReason;
  • trunk/Source/JavaScriptCore/inspector/protocol/Debugger.json

    r176358 r178137  
    104104            "properties": [
    105105                { "name": "message", "type": "string", "optional": true, "description": "The console.assert message string if provided." }
     106            ]
     107        },
     108        {
     109            "id": "BreakpointPauseReason",
     110            "description": "The pause reason auxiliary data when paused because of hitting a breakpoint.",
     111            "type": "object",
     112            "properties": [
     113                { "name": "breakpointId", "type": "string", "description": "The identifier of the breakpoint causing the pause." }
    106114            ]
    107115        },
     
    300308            "parameters": [
    301309                { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." },
    302                 { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "CSPViolation", "other" ], "description": "Pause reason." },
     310                { "name": "reason", "type": "string", "enum": ["XHR", "DOM", "EventListener", "exception", "assert", "CSPViolation", "DebuggerStatement", "Breakpoint", "PauseOnNextStatement", "other"], "description": "Pause reason." },
    303311                { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }
    304312            ],
  • trunk/Source/WebInspectorUI/ChangeLog

    r178110 r178137  
     12015-01-08  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Pause Reason Improvements (Breakpoint, Debugger Statement, Pause on Next Statement)
     4        https://bugs.webkit.org/show_bug.cgi?id=138991
     5
     6        Reviewed by Timothy Hatcher.
     7
     8        * Localizations/en.lproj/localizedStrings.js:
     9        New UI strings for Pause Reasons.
     10
     11        * UserInterface/Controllers/DebuggerManager.js:
     12        (WebInspector.DebuggerManager.prototype.breakpointForIdentifier):
     13        Provide a way to get the breakpoint with an identifier.
     14
     15        * UserInterface/Images/PausedBreakpoint.svg: Added.
     16        * UserInterface/Images/gtk/PausedBreakpoint.svg: Added.
     17        Copy PseudoElement.svg icon and give it a new name.
     18
     19        * UserInterface/Views/BreakpointTreeElement.css:
     20        (.breakpoint-paused-icon .icon):
     21        New icon for a breakpoint causing a pause.
     22
     23        * UserInterface/Views/BreakpointTreeElement.js:
     24        (WebInspector.BreakpointTreeElement.prototype.removeStatusImage):
     25        (WebInspector.BreakpointTreeElement.prototype._updateStatus):
     26        Give API to remove the breakpoint status icon from a BreakpointTreeElement.
     27
     28        * UserInterface/Views/DebuggerSidebarPanel.js:
     29        (WebInspector.DebuggerSidebarPanel):
     30        (WebInspector.DebuggerSidebarPanel.prototype.get hasSelectedElement):
     31        (WebInspector.DebuggerSidebarPanel.prototype.deselectBreakpointContentTreeElements):
     32        (WebInspector.DebuggerSidebarPanel.prototype.deselectPauseReasonContentTreeElements):
     33        (WebInspector.DebuggerSidebarPanel.prototype._treeElementSelected):
     34        Give DebuggerSidebarPanel an optional pause reason tree outline. When available
     35        include it in the pattern of ensuring a single exclusive selection.
     36
     37        (WebInspector.DebuggerSidebarPanel.prototype._breakpointRemoved):
     38        When a breakpoint is removed, check if we should update the pause reason tree outline.
     39
     40        (WebInspector.DebuggerSidebarPanel.prototype._updatePauseReason):
     41        (WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
     42        Update Pause Reason section contents depending on the reason.
     43
     44        (WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonGotoArrow):
     45        Always try to include a goto arrow to jump to the original pause location
     46        if it is available at the time of pausing.
     47
    1482015-01-08  Joseph Pecoraro  <pecoraro@apple.com>
    249
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r175588 r178137  
    4848localizedStrings["All Uncaught Exceptions"] = "All Uncaught Exceptions";
    4949localizedStrings["An error occured trying to\nread the “%s” table."] = "An error occured trying to\nread the “%s” table.";
    50 localizedStrings["An error occurred trying to load the resource."] = "An error occurred trying to load the resource.";
    5150localizedStrings["An unexpected error %s occurred."] = "An unexpected error %s occurred.";
    5251localizedStrings["An unexpected error occurred."] = "An unexpected error occurred.";
     
    5958localizedStrings["Anonymous StyleSheet %d"] = "Anonymous StyleSheet %d";
    6059localizedStrings["Application Cache"] = "Application Cache";
    61 localizedStrings["Assertion"] = "Assertion";
     60localizedStrings["Assertion Failed"] = "Assertion Failed";
    6261localizedStrings["Assertion failed:"] = "Assertion failed:";
     62localizedStrings["Assertion with message: %s"] = "Assertion with message: %s";
    6363localizedStrings["Assertive"] = "Assertive";
    6464localizedStrings["Attribute"] = "Attribute";
     
    110110localizedStrings["Content"] = "Content";
    111111localizedStrings["Content Flow"] = "Content Flow";
    112 localizedStrings["Content Security Policy Violation"] = "Content Security Policy Violation";
     112localizedStrings["Content Security Policy violation of directive: %s"] = "Content Security Policy violation of directive: %s";
    113113localizedStrings["Continue script execution (%s or %s)"] = "Continue script execution (%s or %s)";
    114114localizedStrings["Continue to Here"] = "Continue to Here";
     
    125125localizedStrings["Debugger"] = "Debugger";
    126126localizedStrings["Debugger Paused"] = "Debugger Paused";
     127localizedStrings["Debugger Statement"] = "Debugger Statement";
    127128localizedStrings["Decoded"] = "Decoded";
    128129localizedStrings["Delete"] = "Delete";
     
    193194localizedStrings["Event Dispatched"] = "Event Dispatched";
    194195localizedStrings["Event Listeners"] = "Event Listeners";
    195 localizedStrings["Exception"] = "Exception";
     196localizedStrings["Exception with thrown value: %s"] = "Exception with thrown value: %s";
    196197localizedStrings["Expand columns"] = "Expand columns";
    197198localizedStrings["Expanded"] = "Expanded";
     
    242243localizedStrings["Image Size"] = "Image Size";
    243244localizedStrings["Images"] = "Images";
     245localizedStrings["Immediate Pause Requested"] = "Immediate Pause Requested";
    244246localizedStrings["Index Key \u2014 %s"] = "Index Key \u2014 %s";
    245247localizedStrings["Indexed Databases"] = "Indexed Databases";
     
    322324localizedStrings["Path"] = "Path";
    323325localizedStrings["Pause Playback"] = "Pause Playback";
     326localizedStrings["Pause Reason"] = "Pause Reason";
    324327localizedStrings["Pause script execution (%s or %s)"] = "Pause script execution (%s or %s)";
    325328localizedStrings["Play Sound"] = "Play Sound";
     
    445448localizedStrings["Total size of all resources, click to show the Network Requests timeline"] = "Total size of all resources, click to show the Network Requests timeline";
    446449localizedStrings["Transfered"] = "Transfered";
     450localizedStrings["Triggered Breakpoint"] = "Triggered Breakpoint";
    447451localizedStrings["Type"] = "Type";
    448452localizedStrings["Type Issue"] = "Type Issue";
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js

    r175588 r178137  
    9797
    9898WebInspector.DebuggerManager.PauseReason = {
     99    Assertion: "assertion",
     100    Breakpoint: "breakpoint",
     101    CSPViolation: "CSP-violation",
     102    DebuggerStatement: "debugger-statement",
    99103    Exception: "exception",
    100     Assertion: "assertion",
    101     CSPViolation: "CSP-violation",
     104    PauseOnNextStatement: "pause-on-next-statement",
    102105    Other: "other",
    103106}
     
    307310
    308311        return [];
     312    },
     313
     314    breakpointForIdentifier: function(id)
     315    {
     316        return this._breakpointIdMap[id];
    309317    },
    310318
     
    615623        // FIXME: Handle other backend pause seasons.
    616624        switch (payload) {
     625        case DebuggerAgent.PausedReason.Assert:
     626            return WebInspector.DebuggerManager.PauseReason.Assertion;
     627        case DebuggerAgent.PausedReason.Breakpoint:
     628            return WebInspector.DebuggerManager.PauseReason.Breakpoint;
     629        case DebuggerAgent.PausedReason.CSPViolation:
     630            return WebInspector.DebuggerManager.PauseReason.CSPViolation;
     631        case DebuggerAgent.PausedReason.DebuggerStatement:
     632            return WebInspector.DebuggerManager.PauseReason.DebuggerStatement;
    617633        case DebuggerAgent.PausedReason.Exception:
    618634            return WebInspector.DebuggerManager.PauseReason.Exception;
    619         case DebuggerAgent.PausedReason.Assert:
    620             return WebInspector.DebuggerManager.PauseReason.Assertion;
    621         case DebuggerAgent.PausedReason.CSPViolation:
    622             return WebInspector.DebuggerManager.PauseReason.CSPViolation;
     635        case DebuggerAgent.PausedReason.PauseOnNextStatement:
     636            return WebInspector.DebuggerManager.PauseReason.PauseOnNextStatement;
    623637        default:
    624638            return WebInspector.DebuggerManager.PauseReason.Other;
  • trunk/Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.css

    r173715 r178137  
    5151}
    5252
     53.breakpoint-paused-icon .icon {
     54    content: url(../Images/PausedBreakpoint.svg);
     55}
     56
    5357/* When animating a layer on top of a tree element's icon, move the main
    5458icon to the icon element's background so animations are layered on top. */
  • trunk/Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.js

    r172204 r178137  
    133133    },
    134134
     135    removeStatusImage: function()
     136    {
     137        this._statusImageElement.remove();
     138        this._statusImageElement = null;
     139    },
     140
    135141    // Private
    136142
     
    160166    _updateStatus: function()
    161167    {
     168        if (!this._statusImageElement)
     169            return;
     170
    162171        if (this._breakpoint.disabled)
    163172            this._statusImageElement.classList.add(WebInspector.BreakpointTreeElement.StatusImageDisabledStyleClassName);
  • trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js

    r175588 r178137  
    133133    this._callStackSection = new WebInspector.DetailsSection("call-stack", WebInspector.UIString("Call Stack"), [callStackGroup]);
    134134
    135     this._pauseReasonRow = new WebInspector.DetailsSectionTextRow;
    136     this._pauseReasonGroup = new WebInspector.DetailsSectionGroup([this._pauseReasonRow]);
    137     this._pauseReasonSection = new WebInspector.DetailsSection("paused-reason", null, [this._pauseReasonGroup]);
     135    this._pauseReasonTreeOutline = null;
     136
     137    this._pauseReasonLinkContainerElement = document.createElement("span");
     138    this._pauseReasonTextRow = new WebInspector.DetailsSectionTextRow;
     139    this._pauseReasonGroup = new WebInspector.DetailsSectionGroup([this._pauseReasonTextRow]);
     140    this._pauseReasonSection = new WebInspector.DetailsSection("paused-reason", null, [this._pauseReasonGroup], this._pauseReasonLinkContainerElement);
     141    this._pauseReasonSection.title = WebInspector.UIString("Pause Reason");
    138142
    139143    WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.DisplayLocationDidChange, this._breakpointDisplayLocationDidChange, this);
     
    142146WebInspector.DebuggerSidebarPanel.OffsetSectionsStyleClassName = "offset-sections";
    143147WebInspector.DebuggerSidebarPanel.ExceptionIconStyleClassName = "breakpoint-exception-icon";
     148WebInspector.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName = "breakpoint-paused-icon";
    144149
    145150WebInspector.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey = "debugger-sidebar-panel-all-exceptions-breakpoint";
     
    153158    get hasSelectedElement()
    154159    {
    155         return !!this._breakpointsContentTreeOutline.selectedTreeElement || !!this._callStackContentTreeOutline.selectedTreeElement;
     160        return !!this._breakpointsContentTreeOutline.selectedTreeElement
     161            || !!this._callStackContentTreeOutline.selectedTreeElement
     162            || (this._pauseReasonTreeOutline && !!this._pauseReasonTreeOutline.selectedTreeElement);
    156163    },
    157164
     
    352359        var breakpoint = event.data.breakpoint;
    353360
     361        if (this._pauseReasonTreeOutline) {
     362            var pauseReasonBreakpointTreeElement = this._pauseReasonTreeOutline.getCachedTreeElement(breakpoint);
     363            if (pauseReasonBreakpointTreeElement)
     364                pauseReasonBreakpointTreeElement.removeStatusImage();
     365        }
     366
    354367        var breakpointTreeElement = this._breakpointsContentTreeOutline.getCachedTreeElement(breakpoint);
    355368        console.assert(breakpointTreeElement);
     
    524537        function deselectCallStackContentTreeElements()
    525538        {
    526             // Deselect any tree element in the call stack content tree outline to prevent two selections in the sidebar.
    527539            var selectedTreeElement = this._callStackContentTreeOutline.selectedTreeElement;
     540            if (selectedTreeElement)
     541                selectedTreeElement.deselect();
     542        }
     543
     544        function deselectBreakpointContentTreeElements()
     545        {
     546            var selectedTreeElement = this._breakpointsContentTreeOutline.selectedTreeElement;
     547            if (selectedTreeElement)
     548                selectedTreeElement.deselect();
     549        }
     550
     551        function deselectPauseReasonContentTreeElements()
     552        {
     553            if (!this._pauseReasonTreeOutline)
     554                return;
     555
     556            var selectedTreeElement = this._pauseReasonTreeOutline.selectedTreeElement;
    528557            if (selectedTreeElement)
    529558                selectedTreeElement.deselect();
     
    535564                return;
    536565            deselectCallStackContentTreeElements.call(this);
     566            deselectPauseReasonContentTreeElements.call(this);
    537567            WebInspector.resourceSidebarPanel.showSourceCode(treeElement.representedObject);
    538568            return;
     
    540570
    541571        if (treeElement instanceof WebInspector.CallFrameTreeElement) {
    542             // Deselect any tree element in the breakpoints content tree outline to prevent two selections in the sidebar.
    543             var selectedTreeElement = this._breakpointsContentTreeOutline.selectedTreeElement;
    544             if (selectedTreeElement)
    545                 selectedTreeElement.deselect();
     572            // Deselect any tree element in the breakpoint / pause reason content tree outlines to prevent two selections in the sidebar.
     573            deselectBreakpointContentTreeElements.call(this);
     574            deselectPauseReasonContentTreeElements.call(this);
    546575
    547576            var callFrame = treeElement.callFrame;
     
    554583            return;
    555584
     585        // Deselect any other tree elements to prevent two selections in the sidebar.
    556586        deselectCallStackContentTreeElements.call(this);
     587
     588        if (treeElement.treeOutline === this._pauseReasonTreeOutline)
     589            deselectBreakpointContentTreeElements.call(this);
     590        else
     591            deselectPauseReasonContentTreeElements.call(this);
     592
     593        var breakpoint = treeElement.breakpoint;
     594        if (treeElement.treeOutline === this._pauseReasonTreeOutline) {
     595            WebInspector.resourceSidebarPanel.showSourceCodeLocation(breakpoint.sourceCodeLocation);
     596            return;
     597        }
    557598
    558599        if (!treeElement.parent.representedObject)
     
    563604            return;
    564605
    565         var breakpoint = treeElement.breakpoint;
    566606        WebInspector.resourceSidebarPanel.showSourceCodeLocation(breakpoint.sourceCodeLocation);
    567607    },
     
    596636    _updatePauseReason: function()
    597637    {
     638        this._pauseReasonTreeOutline = null;
     639
     640        this._updatePauseReasonGotoArrow();
     641        return this._updatePauseReasonSection();
     642    },
     643
     644    _updatePauseReasonSection: function()
     645    {
    598646        var pauseData = WebInspector.debuggerManager.pauseData;
    599647       
    600648        switch (WebInspector.debuggerManager.pauseReason) {
     649        case WebInspector.DebuggerManager.PauseReason.Assertion:
     650            // FIXME: We should include the assertion condition string.
     651            console.assert(pauseData, "Expected data with an assertion, but found none.");
     652            if (pauseData && pauseData.message) {
     653                this._pauseReasonTextRow.text = WebInspector.UIString("Assertion with message: %s").format(pauseData.message);
     654                return true;
     655            }           
     656
     657            this._pauseReasonTextRow.text = WebInspector.UIString("Assertion Failed");
     658            this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
     659            return true;
     660
     661        case WebInspector.DebuggerManager.PauseReason.Breakpoint:
     662            console.assert(pauseData, "Expected breakpoint identifier, but found none.");
     663            if (pauseData && pauseData.breakpointId) {
     664                var breakpoint = WebInspector.debuggerManager.breakpointForIdentifier(pauseData.breakpointId);
     665                var breakpointTreeOutline = this.createContentTreeOutline(true, true);
     666                breakpointTreeOutline.onselect = this._treeElementSelected.bind(this);
     667                var breakpointTreeElement = new WebInspector.BreakpointTreeElement(breakpoint, WebInspector.DebuggerSidebarPanel.PausedBreakpointIconStyleClassName, WebInspector.UIString("Triggered Breakpoint"));
     668                var breakpointDetailsSection = new WebInspector.DetailsSectionRow;
     669                breakpointTreeOutline.appendChild(breakpointTreeElement);
     670                breakpointDetailsSection.element.appendChild(breakpointTreeOutline.element);
     671
     672                this._pauseReasonGroup.rows = [breakpointDetailsSection];
     673                this._pauseReasonTreeOutline = breakpointTreeOutline;
     674                return true;
     675            }
     676            break;
     677
     678        case WebInspector.DebuggerManager.PauseReason.CSPViolation:
     679            console.assert(pauseData, "Expected data with a CSP Violation, but found none.");
     680            if (pauseData) {
     681                // COMPATIBILITY (iOS 8): 'directive' was 'directiveText'.
     682                this._pauseReasonTextRow.text = WebInspector.UIString("Content Security Policy violation of directive: %s").format(pauseData.directive || pauseData.directiveText);
     683                this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
     684                return true;
     685            }
     686            break;
     687
     688        case WebInspector.DebuggerManager.PauseReason.DebuggerStatement:
     689            this._pauseReasonTextRow.text = WebInspector.UIString("Debugger Statement");
     690            this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
     691            return true;
     692
    601693        case WebInspector.DebuggerManager.PauseReason.Exception:
    602694            console.assert(pauseData, "Expected data with an exception, but found none.");
     
    604696                // FIXME: We should improve the appearance of thrown objects. This works well for exception strings.
    605697                var data = WebInspector.RemoteObject.fromPayload(pauseData);
    606                 this._pauseReasonRow.text = data.description;
    607                 this._pauseReasonSection.title = WebInspector.UIString("Exception");
     698                this._pauseReasonTextRow.text = WebInspector.UIString("Exception with thrown value: %s").format(data.description);
     699                this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
    608700                return true;
    609701            }
    610702            break;
    611703
    612         case WebInspector.DebuggerManager.PauseReason.Assertion:
    613             console.assert(pauseData, "Expected data with an assertion, but found none.");
    614             if (pauseData && pauseData.message) {
    615                 // FIXME: We should include the assertion condition string.
    616                 this._pauseReasonRow.text = pauseData.message;
    617                 this._pauseReasonSection.title = WebInspector.UIString("Assertion");
    618                 return true;
    619             }
    620             break;
    621 
    622         case WebInspector.DebuggerManager.PauseReason.CSPViolation:
    623             console.assert(pauseData, "Expected data with a CSP Violation, but found none.");
    624             if (pauseData) {
    625                 // COMPATIBILITY (iOS 8): 'directive' was 'directiveText'.
    626                 this._pauseReasonRow.text = pauseData.directive || pauseData.directiveText;
    627                 this._pauseReasonSection.title = WebInspector.UIString("Content Security Policy Violation");
    628                 return true;
    629             }
    630             break;
     704        case WebInspector.DebuggerManager.PauseReason.PauseOnNextStatement:
     705            this._pauseReasonTextRow.text = WebInspector.UIString("Immediate Pause Requested");
     706            this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
     707            return true;
    631708
    632709        case WebInspector.DebuggerManager.PauseReason.Other:
     
    636713
    637714        return false;
     715    },
     716
     717    _updatePauseReasonGotoArrow: function()
     718    {
     719        this._pauseReasonLinkContainerElement.removeChildren();
     720
     721        var activeCallFrame = WebInspector.debuggerManager.activeCallFrame;
     722        if (!activeCallFrame)
     723            return;
     724
     725        var sourceCodeLocation = activeCallFrame.sourceCodeLocation;
     726        if (!sourceCodeLocation)
     727            return;
     728
     729        var linkElement = WebInspector.createSourceCodeLocationLink(sourceCodeLocation, false, true);
     730        this._pauseReasonLinkContainerElement.appendChild(linkElement);
    638731    }
    639732};
Note: See TracChangeset for help on using the changeset viewer.