Changeset 249450 in webkit


Ignore:
Timestamp:
Sep 3, 2019 7:26:37 PM (5 years ago)
Author:
Devin Rousso
Message:

Web Inspector: implement blackboxing of script resources
https://bugs.webkit.org/show_bug.cgi?id=17240
<rdar://problem/5732847>

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

When a script is blackboxed and the debugger attempts to pause in that script, the pause
reason/data will be saved and execution will continue until it has left the blackboxed
script. Once outside, execution is paused with the saved reason/data.

This is especially useful when debugging issues using libraries/frameworks, as it allows the
developer to "skip" the internal logic of the library/framework and instead focus only on
how they're using it.

  • inspector/protocol/Debugger.json:

Add setShouldBlackboxURL command.

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

(Inspector::InspectorDebuggerAgent):
(Inspector::InspectorDebuggerAgent::enable):
(Inspector::InspectorDebuggerAgent::updatePauseReasonAndData): Added.
(Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement):
(Inspector::InspectorDebuggerAgent::cancelPauseOnNextStatement):
(Inspector::InspectorDebuggerAgent::setShouldBlackboxURL): Added.
(Inspector::InspectorDebuggerAgent::setPauseForInternalScripts):
(Inspector::InspectorDebuggerAgent::didParseSource):
(Inspector::InspectorDebuggerAgent::didPause):
(Inspector::InspectorDebuggerAgent::didContinue):
(Inspector::InspectorDebuggerAgent::breakProgram):
(Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
(Inspector::InspectorDebuggerAgent::clearPauseDetails): Added.
(Inspector::InspectorDebuggerAgent::clearBreakDetails): Deleted.
Renamed "break" to "pause" to match Debugger naming.

  • debugger/Debugger.h:
  • debugger/Debugger.cpp:

(JSC::Debugger::pauseIfNeeded):
(JSC::Debugger::setBlackboxType): Added.
(JSC::Debugger::clearBlackbox): Added.
(JSC::Debugger::isBlacklisted const): Deleted.
(JSC::Debugger::addToBlacklist): Deleted.
(JSC::Debugger::clearBlacklist): Deleted.

Source/WebInspectorUI:

When a script is blackboxed and the debugger attempts to pause in that script, the pause
reason/data will be saved and execution will continue until it has left the blackboxed
script. Once outside, execution is paused with the saved reason/data.

This is especially useful when debugging issues using libraries/frameworks, as it allows the
developer to "skip" the internal logic of the library/framework and instead focus only on
how they're using it.

  • UserInterface/Controllers/DebuggerManager.js:

(WI.DebuggerManager):
(WI.DebuggerManager.prototype.initializeTarget):
(WI.DebuggerManager.supportsBlackboxingScripts): Added.
(WI.DebuggerManager.pauseReasonFromPayload): Added.
(WI.DebuggerManager.prototype.isScriptBlackboxed): Added.
(WI.DebuggerManager.prototype.setShouldBlackboxScript): Added.
(WI.DebuggerManager.prototype._pauseReasonFromPayload):
(WI.DebuggerManager.prototype._pauseReasonFromPayload): Deleted.

  • UserInterface/Models/SourceCode.js:

(WI.SourceCode.prototype.get isScript): Added.
(WI.SourceCode.prototype.get supportsScriptBlackboxing): Added.

  • UserInterface/Models/Script.js:

(WI.Script.prototype.get isScript): Added.

  • UserInterface/Models/Resource.js:

(WI.Resource.prototype.get isScript): Added.
Provide a more straightforward way of determining if a WI.SourceCode is a script.

  • UserInterface/Views/DebuggerSidebarPanel.js:

(WI.DebuggerSidebarPanel.prototype._updatePauseReason):
(WI.DebuggerSidebarPanel.prototype._updatePauseReasonSection):

  • UserInterface/Views/SourcesNavigationSidebarPanel.js:

(WI.SourcesNavigationSidebarPanel.prototype._updatePauseReason):
(WI.SourcesNavigationSidebarPanel.prototype._updatePauseReasonSection):
Display the original pause reason and breakpoint (if applicable) when pausing after leaving
a blackboxed script.

  • UserInterface/Views/SourceCodeTreeElement.js:

(WI.SourceCodeTreeElement.prototype.canSelectOnMouseDown): Added.
(WI.SourceCodeTreeElement.prototype.updateStatus): Added.
(WI.SourceCodeTreeElement.prototype._updateSourceCode):
(WI.SourceCodeTreeElement.prototype._updateToggleBlackboxImageElementState): Added.
(WI.SourceCodeTreeElement.prototype._handleToggleBlackboxedImageElementClick): Added.

  • UserInterface/Views/SourceCodeTreeElement.css: Added.

(.tree-outline .item .status > .toggle-script-blackboxed):
(.tree-outline:not(.navigation-sidebar-panel-content-tree-outline) .item .status > .toggle-script-blackboxed,):
(.tree-outline:focus .item.selected .status > .toggle-script-blackboxed):
(.tree-outline .item .status > .toggle-script-blackboxed.blackboxed):
(@media (prefers-color-scheme: dark) .tree-outline .item .status > .toggle-script-blackboxed):

  • UserInterface/Views/ResourceTreeElement.js:

(WI.ResourceTreeElement.prototype._updateResource):
(WI.ResourceTreeElement.prototype.updateStatus): Added.
(WI.ResourceTreeElement.prototype._updateStatus): Deleted.
Make sure that the loading indicator doesn't override the blackbox toggle.

  • UserInterface/Base/Setting.js:

(WI.Setting.prototype.set value):
(WI.Setting.prototype.save): Added.
When modifying an array value, that doesn't go through WI.Setting.prototype.set value, so
we need a more "manual" way of saving the new value.

  • UserInterface/Main.html:
  • Localizations/en.lproj/localizedStrings.js:
  • UserInterface/Test/TestHarness.js:

(TestHarness.prototype.newline): Added.
(TestHarness.prototype.expectException):
Add a special case for logging error message objects when running protocol tests.

LayoutTests:

  • inspector/debugger/setShouldBlackboxURL.html: Added.
  • inspector/debugger/setShouldBlackboxURL-expected.txt: Added.
  • inspector/model/remote-object-api-expected.txt:

Update output since WI.TestHarness.prototype.expectException now logs the .constructor.name.

Location:
trunk
Files:
3 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r249447 r249450  
     12019-09-03  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: implement blackboxing of script resources
     4        https://bugs.webkit.org/show_bug.cgi?id=17240
     5        <rdar://problem/5732847>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        * inspector/debugger/setShouldBlackboxURL.html: Added.
     10        * inspector/debugger/setShouldBlackboxURL-expected.txt: Added.
     11
     12        * inspector/model/remote-object-api-expected.txt:
     13        Update output since `WI.TestHarness.prototype.expectException` now logs the `.constructor.name`.
     14
    1152019-09-03  Devin Rousso  <drousso@apple.com>
    216
  • trunk/LayoutTests/inspector/model/remote-object-api-expected.txt

    r226417 r249450  
    3434-- Running test case: RemoteObject.getProperty.FailureWithPromise
    3535PASS: Should produce an exception.
    36 [object Object]
     36RemoteObject
    3737
    3838-- Running test case: RemoteObject.fetchProperties.Success
  • trunk/Source/JavaScriptCore/ChangeLog

    r249449 r249450  
     12019-09-03  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: implement blackboxing of script resources
     4        https://bugs.webkit.org/show_bug.cgi?id=17240
     5        <rdar://problem/5732847>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        When a script is blackboxed and the debugger attempts to pause in that script, the pause
     10        reason/data will be saved and execution will continue until it has left the blackboxed
     11        script. Once outside, execution is paused with the saved reason/data.
     12
     13        This is especially useful when debugging issues using libraries/frameworks, as it allows the
     14        developer to "skip" the internal logic of the library/framework and instead focus only on
     15        how they're using it.
     16
     17        * inspector/protocol/Debugger.json:
     18        Add `setShouldBlackboxURL` command.
     19
     20        * inspector/agents/InspectorDebuggerAgent.h:
     21        * inspector/agents/InspectorDebuggerAgent.cpp:
     22        (Inspector::InspectorDebuggerAgent):
     23        (Inspector::InspectorDebuggerAgent::enable):
     24        (Inspector::InspectorDebuggerAgent::updatePauseReasonAndData): Added.
     25        (Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement):
     26        (Inspector::InspectorDebuggerAgent::cancelPauseOnNextStatement):
     27        (Inspector::InspectorDebuggerAgent::setShouldBlackboxURL): Added.
     28        (Inspector::InspectorDebuggerAgent::setPauseForInternalScripts):
     29        (Inspector::InspectorDebuggerAgent::didParseSource):
     30        (Inspector::InspectorDebuggerAgent::didPause):
     31        (Inspector::InspectorDebuggerAgent::didContinue):
     32        (Inspector::InspectorDebuggerAgent::breakProgram):
     33        (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
     34        (Inspector::InspectorDebuggerAgent::clearPauseDetails): Added.
     35        (Inspector::InspectorDebuggerAgent::clearBreakDetails): Deleted.
     36        Renamed "break" to "pause" to match `Debugger` naming.
     37
     38        * debugger/Debugger.h:
     39        * debugger/Debugger.cpp:
     40        (JSC::Debugger::pauseIfNeeded):
     41        (JSC::Debugger::setBlackboxType): Added.
     42        (JSC::Debugger::clearBlackbox): Added.
     43        (JSC::Debugger::isBlacklisted const): Deleted.
     44        (JSC::Debugger::addToBlacklist): Deleted.
     45        (JSC::Debugger::clearBlacklist): Deleted.
     46
    1472019-09-03  Mark Lam  <mark.lam@apple.com>
    248
  • trunk/Source/JavaScriptCore/debugger/Debugger.cpp

    r249175 r249450  
    696696
    697697    intptr_t sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame);
    698     if (isBlacklisted(sourceID))
     698
     699    auto blackboxTypeIterator = m_blackboxedScripts.find(sourceID);
     700    if (blackboxTypeIterator != m_blackboxedScripts.end() && blackboxTypeIterator->value == BlackboxType::Ignored)
    699701        return;
    700702
     
    714716        return;
    715717
     718    bool afterBlackboxedScript = m_afterBlackboxedScript;
    716719    clearNextPauseState();
    717720
     
    737740    }
    738741
    739     {
    740         PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause);
     742    if (blackboxTypeIterator != m_blackboxedScripts.end() && blackboxTypeIterator->value == BlackboxType::Deferred) {
     743        m_afterBlackboxedScript = true;
     744        setPauseOnNextStatement(true);
     745        return;
     746    }
     747
     748    {
     749        auto reason = m_reasonForPause;
     750        if (afterBlackboxedScript)
     751            reason = PausedAfterBlackboxedScript;
     752        else if (didHitBreakpoint)
     753            reason = PausedForBreakpoint;
     754        PauseReasonDeclaration rauseReasonDeclaration(*this, reason);
     755
    741756        handlePause(vmEntryGlobalObject, m_reasonForPause);
    742757        scope.releaseAssertNoException();
     
    909924    m_pauseAtNextOpportunity = false;
    910925    m_pauseOnStepOut = false;
     926    m_afterBlackboxedScript = false;
    911927}
    912928
     
    929945}
    930946
    931 bool Debugger::isBlacklisted(SourceID sourceID) const
    932 {
    933     return m_blacklistedScripts.contains(sourceID);
    934 }
    935 
    936 void Debugger::addToBlacklist(SourceID sourceID)
    937 {
    938     m_blacklistedScripts.add(sourceID);
    939 }
    940 
    941 void Debugger::clearBlacklist()
    942 {
    943     m_blacklistedScripts.clear();
     947void Debugger::setBlackboxType(SourceID sourceID, Optional<BlackboxType> type)
     948{
     949    if (type)
     950        m_blackboxedScripts.set(sourceID, type.value());
     951    else
     952        m_blackboxedScripts.remove(sourceID);
     953}
     954
     955void Debugger::clearBlackbox()
     956{
     957    m_blackboxedScripts.clear();
    944958}
    945959
  • trunk/Source/JavaScriptCore/debugger/Debugger.h

    r248894 r249450  
    101101        PausedForBreakpoint,
    102102        PausedForDebuggerStatement,
     103        PausedAfterBlackboxedScript,
    103104    };
    104105    ReasonForPause reasonForPause() const { return m_reasonForPause; }
     
    112113    void stepOutOfFunction();
    113114
    114     bool isBlacklisted(SourceID) const;
    115     void addToBlacklist(SourceID);
    116     void clearBlacklist();
     115    enum class BlackboxType { Deferred, Ignored };
     116    void setBlackboxType(SourceID, Optional<BlackboxType>);
     117    void clearBlackbox();
    117118
    118119    bool isPaused() const { return m_isPaused; }
     
    225226    HashSet<JSGlobalObject*> m_globalObjects;
    226227    HashMap<SourceID, DebuggerParseData, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> m_parseDataMap;
    227     HashSet<SourceID, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> m_blacklistedScripts;
     228    HashMap<SourceID, BlackboxType, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> m_blackboxedScripts;
    228229
    229230    PauseOnExceptionsState m_pauseOnExceptionsState;
     
    243244    unsigned m_lastExecutedLine;
    244245    SourceID m_lastExecutedSourceID;
     246    bool m_afterBlackboxedScript { false };
    245247
    246248    BreakpointID m_topBreakpointID;
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp

    r249315 r249450  
    4242#include "ScriptDebugServer.h"
    4343#include "ScriptObject.h"
     44#include <wtf/Function.h>
    4445#include <wtf/JSONValues.h>
    4546#include <wtf/NeverDestroyed.h>
     
    5960{
    6061    return makeString("breakpoint-action-", action.identifier);
     62}
     63
     64static bool isWebKitInjectedScript(const String& sourceURL)
     65{
     66    return sourceURL.startsWith("__InjectedScript_") && sourceURL.endsWith(".js");
    6167}
    6268
     
    6874    , m_injectedScriptManager(context.injectedScriptManager)
    6975{
    70     // FIXME: make breakReason optional so that there was no need to init it with "other".
    71     clearBreakDetails();
     76    // FIXME: make pauseReason optional so that there was no need to init it with "other".
     77    clearPauseDetails();
    7278}
    7379
     
    9298    for (auto* listener : copyToVector(m_listeners))
    9399        listener->debuggerWasEnabled();
     100
     101    for (auto& [sourceID, script] : m_scripts) {
     102        Optional<JSC::Debugger::BlackboxType> blackboxType;
     103        if (isWebKitInjectedScript(script.sourceURL)) {
     104            if (!m_pauseForInternalScripts)
     105                blackboxType = JSC::Debugger::BlackboxType::Ignored;
     106        } else if ((!script.sourceURL.isEmpty() && m_blackboxedURLs.contains(script.sourceURL)) || (!script.url.isEmpty() && m_blackboxedURLs.contains(script.url)))
     107            blackboxType = JSC::Debugger::BlackboxType::Deferred;
     108        m_scriptDebugServer.setBlackboxType(sourceID, blackboxType);
     109    }
    94110}
    95111
     
    168184{
    169185    m_scriptDebugServer.setSuppressAllPauses(suppress);
     186}
     187
     188void InspectorDebuggerAgent::updatePauseReasonAndData(DebuggerFrontendDispatcher::Reason reason, RefPtr<JSON::Object>&& data)
     189{
     190    if (m_pauseReason != DebuggerFrontendDispatcher::Reason::BlackboxedScript) {
     191        m_preBlackboxPauseReason = m_pauseReason;
     192        m_preBlackboxPauseData = WTFMove(m_pauseData);
     193    }
     194
     195    m_pauseReason = reason;
     196    m_pauseData = WTFMove(data);
    170197}
    171198
     
    699726}
    700727
    701 void InspectorDebuggerAgent::schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<JSON::Object>&& data)
     728void InspectorDebuggerAgent::schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason reason, RefPtr<JSON::Object>&& data)
    702729{
    703730    if (m_javaScriptPauseScheduled)
     
    706733    m_javaScriptPauseScheduled = true;
    707734
    708     m_breakReason = breakReason;
    709     m_breakData = WTFMove(data);
     735    updatePauseReasonAndData(reason, WTFMove(data));
    710736
    711737    JSC::JSLockHolder locker(m_scriptDebugServer.vm());
     
    720746    m_javaScriptPauseScheduled = false;
    721747
    722     clearBreakDetails();
     748    clearPauseDetails();
    723749    m_scriptDebugServer.setPauseOnNextStatement(false);
    724750    m_enablePauseWhenIdle = false;
     
    865891}
    866892
     893void InspectorDebuggerAgent::setShouldBlackboxURL(ErrorString& errorString, const String& url, bool shouldBlackbox)
     894{
     895    if (url.isEmpty()) {
     896        errorString = "URL must not be empty"_s;
     897        return;
     898    }
     899
     900    if (isWebKitInjectedScript(url)) {
     901        errorString = "Blackboxing of internal scripts is controlled by 'Debugger.setPauseForInternalScripts'"_s;
     902        return;
     903    }
     904
     905    if (shouldBlackbox)
     906        m_blackboxedURLs.add(url);
     907    else
     908        m_blackboxedURLs.remove(url);
     909
     910    auto blackboxType = shouldBlackbox ? Optional<JSC::Debugger::BlackboxType>(JSC::Debugger::BlackboxType::Deferred) : WTF::nullopt;
     911    for (auto& [sourceID, script] : m_scripts) {
     912        if (isWebKitInjectedScript(script.sourceURL))
     913            continue;
     914        if (script.sourceURL != url && script.url != url)
     915            continue;
     916        m_scriptDebugServer.setBlackboxType(sourceID, blackboxType);
     917    }
     918}
     919
    867920void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText)
    868921{
     
    892945    m_pauseForInternalScripts = shouldPause;
    893946
    894     if (m_pauseForInternalScripts)
    895         m_scriptDebugServer.clearBlacklist();
    896 }
    897 
    898 static bool isWebKitInjectedScript(const String& sourceURL)
    899 {
    900     return sourceURL.startsWith("__InjectedScript_") && sourceURL.endsWith(".js");
     947    auto blackboxType = !m_pauseForInternalScripts ? Optional<JSC::Debugger::BlackboxType>(JSC::Debugger::BlackboxType::Ignored) : WTF::nullopt;
     948    for (auto& [sourceID, script] : m_scripts) {
     949        if (!isWebKitInjectedScript(script.sourceURL))
     950            continue;
     951        m_scriptDebugServer.setBlackboxType(sourceID, blackboxType);
     952    }
    901953}
    902954
     
    917969    m_scripts.set(sourceID, script);
    918970
    919     if (hasSourceURL && isWebKitInjectedScript(sourceURL) && !m_pauseForInternalScripts)
    920         m_scriptDebugServer.addToBlacklist(sourceID);
     971    if (isWebKitInjectedScript(sourceURL)) {
     972        if (!m_pauseForInternalScripts)
     973            m_scriptDebugServer.setBlackboxType(sourceID, JSC::Debugger::BlackboxType::Ignored);
     974    } else if ((hasSourceURL && m_blackboxedURLs.contains(sourceURL)) || (!script.url.isEmpty() && m_blackboxedURLs.contains(script.url)))
     975        m_scriptDebugServer.setBlackboxType(sourceID, JSC::Debugger::BlackboxType::Deferred);
    921976
    922977    String scriptURLForBreakpoints = hasSourceURL ? script.sourceURL : script.url;
     
    9971052
    9981053    // If a high level pause pause reason is not already set, try to infer a reason from the debugger.
    999     if (m_breakReason == DebuggerFrontendDispatcher::Reason::Other) {
     1054    if (m_pauseReason == DebuggerFrontendDispatcher::Reason::Other) {
    10001055        switch (m_scriptDebugServer.reasonForPause()) {
    10011056        case JSC::Debugger::PausedForBreakpoint: {
    1002             JSC::BreakpointID debuggerBreakpointId = m_scriptDebugServer.pausingBreakpointID();
    1003             if (debuggerBreakpointId != m_continueToLocationBreakpointID) {
    1004                 m_breakReason = DebuggerFrontendDispatcher::Reason::Breakpoint;
    1005                 m_breakData = buildBreakpointPauseReason(debuggerBreakpointId);
    1006             }
     1057            auto debuggerBreakpointId = m_scriptDebugServer.pausingBreakpointID();
     1058            if (debuggerBreakpointId != m_continueToLocationBreakpointID)
     1059                updatePauseReasonAndData(DebuggerFrontendDispatcher::Reason::Breakpoint, buildBreakpointPauseReason(debuggerBreakpointId));
    10071060            break;
    10081061        }
    10091062        case JSC::Debugger::PausedForDebuggerStatement:
    1010             m_breakReason = DebuggerFrontendDispatcher::Reason::DebuggerStatement;
    1011             m_breakData = nullptr;
     1063            updatePauseReasonAndData(DebuggerFrontendDispatcher::Reason::DebuggerStatement, nullptr);
    10121064            break;
    10131065        case JSC::Debugger::PausedForException:
    1014             m_breakReason = DebuggerFrontendDispatcher::Reason::Exception;
    1015             m_breakData = buildExceptionPauseReason(exceptionOrCaughtValue, injectedScript);
     1066            updatePauseReasonAndData(DebuggerFrontendDispatcher::Reason::Exception, buildExceptionPauseReason(exceptionOrCaughtValue, injectedScript));
    10161067            break;
     1068        case JSC::Debugger::PausedAfterBlackboxedScript: {
     1069            // There should be no break data, as we would've already continued past the breakpoint.
     1070            ASSERT(!m_pauseData);
     1071
     1072            // Don't call `updatePauseReasonAndData` so as to not override `m_preBlackboxPauseData`.
     1073            if (m_pauseReason != DebuggerFrontendDispatcher::Reason::BlackboxedScript)
     1074                m_preBlackboxPauseReason = m_pauseReason;
     1075            m_pauseReason = DebuggerFrontendDispatcher::Reason::BlackboxedScript;
     1076            break;
     1077        }
    10171078        case JSC::Debugger::PausedAtStatement:
    10181079        case JSC::Debugger::PausedAtExpression:
     
    10271088    }
    10281089
     1090    if (m_scriptDebugServer.reasonForPause() == JSC::Debugger::PausedAfterBlackboxedScript) {
     1091        // Ensure that `m_preBlackboxPauseReason` is populated with the most recent data.
     1092        updatePauseReasonAndData(m_pauseReason, nullptr);
     1093
     1094        RefPtr<JSON::Object> data;
     1095        if (auto debuggerBreakpointId = m_scriptDebugServer.pausingBreakpointID()) {
     1096            ASSERT(debuggerBreakpointId != m_continueToLocationBreakpointID);
     1097            data = JSON::Object::create();
     1098            data->setString("originalReason"_s, Protocol::InspectorHelpers::getEnumConstantValue(DebuggerFrontendDispatcher::Reason::Breakpoint));
     1099            data->setValue("originalData"_s, buildBreakpointPauseReason(debuggerBreakpointId));
     1100        } else if (m_preBlackboxPauseData) {
     1101            data = JSON::Object::create();
     1102            data->setString("originalReason"_s, Protocol::InspectorHelpers::getEnumConstantValue(m_preBlackboxPauseReason));
     1103            data->setValue("originalData"_s, m_preBlackboxPauseData);
     1104        }
     1105        updatePauseReasonAndData(DebuggerFrontendDispatcher::Reason::BlackboxedScript, WTFMove(data));
     1106    }
     1107
    10291108    // Set $exception to the exception or caught value.
    10301109    if (exceptionOrCaughtValue && !injectedScript.hasNoValue()) {
     
    10431122    }
    10441123
    1045     m_frontendDispatcher->paused(currentCallFrames(injectedScript), m_breakReason, m_breakData, asyncStackTrace);
     1124    m_frontendDispatcher->paused(currentCallFrames(injectedScript), m_pauseReason, m_pauseData, asyncStackTrace);
    10461125
    10471126    m_javaScriptPauseScheduled = false;
     
    10881167    m_currentCallStack = { };
    10891168    m_injectedScriptManager.releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
    1090     clearBreakDetails();
     1169    clearPauseDetails();
    10911170    clearExceptionValue();
    10921171
     
    10951174}
    10961175
    1097 void InspectorDebuggerAgent::breakProgram(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<JSON::Object>&& data)
    1098 {
    1099     m_breakReason = breakReason;
    1100     m_breakData = WTFMove(data);
     1176void InspectorDebuggerAgent::breakProgram(DebuggerFrontendDispatcher::Reason reason, RefPtr<JSON::Object>&& data)
     1177{
     1178    updatePauseReasonAndData(reason, WTFMove(data));
     1179
    11011180    m_scriptDebugServer.breakProgram();
    11021181}
     
    11191198        m_scriptDebugServer.clearBreakpointActions();
    11201199        m_scriptDebugServer.clearBreakpoints();
    1121         m_scriptDebugServer.clearBlacklist();
     1200        m_scriptDebugServer.clearBlackbox();
    11221201    }
    11231202
     
    11281207    m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.clear();
    11291208    m_continueToLocationBreakpointID = JSC::noBreakpointID;
    1130     clearBreakDetails();
     1209    clearPauseDetails();
    11311210    m_javaScriptPauseScheduled = false;
    11321211    m_hasExceptionValue = false;
     
    11591238}
    11601239
    1161 void InspectorDebuggerAgent::clearBreakDetails()
    1162 {
    1163     m_breakReason = DebuggerFrontendDispatcher::Reason::Other;
    1164     m_breakData = nullptr;
     1240void InspectorDebuggerAgent::clearPauseDetails()
     1241{
     1242    updatePauseReasonAndData(DebuggerFrontendDispatcher::Reason::Other, nullptr);
    11651243}
    11661244
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h

    r249315 r249450  
    8686    void setPauseForInternalScripts(ErrorString&, bool shouldPause) final;
    8787    void evaluateOnCallFrame(ErrorString&, const String& callFrameId, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, const bool* emulateUserGesture, RefPtr<Protocol::Runtime::RemoteObject>& result, Optional<bool>& wasThrown, Optional<int>& savedResultIndex) override;
     88    void setShouldBlackboxURL(ErrorString&, const String& url, bool shouldBlackbox) final;
    8889
    8990    // ScriptDebugListener
     
    116117    void didDispatchAsyncCall();
    117118
    118     void schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<JSON::Object>&& data);
     119    void schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason, RefPtr<JSON::Object>&& data);
    119120    void cancelPauseOnNextStatement();
    120121    bool pauseOnNextStatementEnabled() const { return m_javaScriptPauseScheduled; }
    121122
    122     void breakProgram(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<JSON::Object>&& data);
     123    void breakProgram(DebuggerFrontendDispatcher::Reason, RefPtr<JSON::Object>&& data);
    123124    void scriptExecutionBlockedByCSP(const String& directiveText);
    124125
     
    160161    void clearDebuggerBreakpointState();
    161162    void clearInspectorBreakpointState();
    162     void clearBreakDetails();
     163    void clearPauseDetails();
    163164    void clearExceptionValue();
    164165    void clearAsyncStackTraceData();
     
    169170    void didBecomeIdle();
    170171
     172    void updatePauseReasonAndData(DebuggerFrontendDispatcher::Reason, RefPtr<JSON::Object>&& data);
     173
    171174    RefPtr<JSON::Object> buildBreakpointPauseReason(JSC::BreakpointID);
    172175    RefPtr<JSON::Object> buildExceptionPauseReason(JSC::JSValue exception, const InjectedScript&);
     
    183186    InjectedScriptManager& m_injectedScriptManager;
    184187    HashMap<JSC::SourceID, Script> m_scripts;
     188    HashSet<String> m_blackboxedURLs;
    185189
    186190    HashSet<Listener*> m_listeners;
     
    193197    HashMap<JSC::BreakpointID, String> m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier;
    194198    JSC::BreakpointID m_continueToLocationBreakpointID { JSC::noBreakpointID };
    195     DebuggerFrontendDispatcher::Reason m_breakReason;
    196     RefPtr<JSON::Object> m_breakData;
    197199    ShouldDispatchResumed m_conditionToDispatchResumed { ShouldDispatchResumed::No };
     200
     201    DebuggerFrontendDispatcher::Reason m_pauseReason;
     202    RefPtr<JSON::Object> m_pauseData;
     203
     204    DebuggerFrontendDispatcher::Reason m_preBlackboxPauseReason;
     205    RefPtr<JSON::Object> m_preBlackboxPauseData;
    198206
    199207    HashMap<AsyncCallIdentifier, RefPtr<AsyncStackTrace>> m_pendingAsyncCalls;
  • trunk/Source/JavaScriptCore/inspector/protocol/Debugger.json

    r248894 r249450  
    294294                { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." },
    295295                { "name": "savedResultIndex", "type": "integer", "optional": true, "description": "If the result was saved, this is the $n index that can be used to access the value." }
     296            ]
     297        },
     298        {
     299            "name": "setShouldBlackboxURL",
     300            "description": "Sets whether the given URL should be in the list of blackboxed scripts, which are ignored when pausing/stepping/debugging.",
     301            "parameters": [
     302                { "name": "url", "type": "string" },
     303                { "name": "shouldBlackbox", "type": "boolean" }
    296304            ]
    297305        }
     
    342350            "parameters": [
    343351                { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." },
    344                 { "name": "reason", "type": "string", "enum": ["XHR", "Fetch", "DOM", "AnimationFrame", "Interval", "Listener", "Timeout", "exception", "assert", "CSPViolation", "DebuggerStatement", "Breakpoint", "PauseOnNextStatement", "Microtask", "other"], "description": "Pause reason." },
     352                { "name": "reason", "type": "string", "enum": ["XHR", "Fetch", "DOM", "AnimationFrame", "Interval", "Listener", "Timeout", "exception", "assert", "CSPViolation", "DebuggerStatement", "Breakpoint", "PauseOnNextStatement", "Microtask", "BlackboxedScript", "other"], "description": "Pause reason." },
    345353                { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." },
    346354                { "name": "asyncStackTrace", "$ref": "Console.StackTrace", "optional": true, "description": "Linked list of asynchronous StackTraces." }
  • trunk/Source/WebInspectorUI/ChangeLog

    r249312 r249450  
     12019-09-03  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: implement blackboxing of script resources
     4        https://bugs.webkit.org/show_bug.cgi?id=17240
     5        <rdar://problem/5732847>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        When a script is blackboxed and the debugger attempts to pause in that script, the pause
     10        reason/data will be saved and execution will continue until it has left the blackboxed
     11        script. Once outside, execution is paused with the saved reason/data.
     12
     13        This is especially useful when debugging issues using libraries/frameworks, as it allows the
     14        developer to "skip" the internal logic of the library/framework and instead focus only on
     15        how they're using it.
     16
     17        * UserInterface/Controllers/DebuggerManager.js:
     18        (WI.DebuggerManager):
     19        (WI.DebuggerManager.prototype.initializeTarget):
     20        (WI.DebuggerManager.supportsBlackboxingScripts): Added.
     21        (WI.DebuggerManager.pauseReasonFromPayload): Added.
     22        (WI.DebuggerManager.prototype.isScriptBlackboxed): Added.
     23        (WI.DebuggerManager.prototype.setShouldBlackboxScript): Added.
     24        (WI.DebuggerManager.prototype._pauseReasonFromPayload):
     25        (WI.DebuggerManager.prototype._pauseReasonFromPayload): Deleted.
     26
     27        * UserInterface/Models/SourceCode.js:
     28        (WI.SourceCode.prototype.get isScript): Added.
     29        (WI.SourceCode.prototype.get supportsScriptBlackboxing): Added.
     30        * UserInterface/Models/Script.js:
     31        (WI.Script.prototype.get isScript): Added.
     32        * UserInterface/Models/Resource.js:
     33        (WI.Resource.prototype.get isScript): Added.
     34        Provide a more straightforward way of determining if a `WI.SourceCode` is a script.
     35
     36        * UserInterface/Views/DebuggerSidebarPanel.js:
     37        (WI.DebuggerSidebarPanel.prototype._updatePauseReason):
     38        (WI.DebuggerSidebarPanel.prototype._updatePauseReasonSection):
     39        * UserInterface/Views/SourcesNavigationSidebarPanel.js:
     40        (WI.SourcesNavigationSidebarPanel.prototype._updatePauseReason):
     41        (WI.SourcesNavigationSidebarPanel.prototype._updatePauseReasonSection):
     42        Display the original pause reason and breakpoint (if applicable) when pausing after leaving
     43        a blackboxed script.
     44
     45        * UserInterface/Views/SourceCodeTreeElement.js:
     46        (WI.SourceCodeTreeElement.prototype.canSelectOnMouseDown): Added.
     47        (WI.SourceCodeTreeElement.prototype.updateStatus): Added.
     48        (WI.SourceCodeTreeElement.prototype._updateSourceCode):
     49        (WI.SourceCodeTreeElement.prototype._updateToggleBlackboxImageElementState): Added.
     50        (WI.SourceCodeTreeElement.prototype._handleToggleBlackboxedImageElementClick): Added.
     51        * UserInterface/Views/SourceCodeTreeElement.css: Added.
     52        (.tree-outline .item .status > .toggle-script-blackboxed):
     53        (.tree-outline:not(.navigation-sidebar-panel-content-tree-outline) .item .status > .toggle-script-blackboxed,):
     54        (.tree-outline:focus .item.selected .status > .toggle-script-blackboxed):
     55        (.tree-outline .item .status > .toggle-script-blackboxed.blackboxed):
     56        (@media (prefers-color-scheme: dark) .tree-outline .item .status > .toggle-script-blackboxed):
     57
     58        * UserInterface/Views/ResourceTreeElement.js:
     59        (WI.ResourceTreeElement.prototype._updateResource):
     60        (WI.ResourceTreeElement.prototype.updateStatus): Added.
     61        (WI.ResourceTreeElement.prototype._updateStatus): Deleted.
     62        Make sure that the loading indicator doesn't override the blackbox toggle.
     63
     64        * UserInterface/Base/Setting.js:
     65        (WI.Setting.prototype.set value):
     66        (WI.Setting.prototype.save): Added.
     67        When modifying an array value, that doesn't go through `WI.Setting.prototype.set value`, so
     68        we need a more "manual" way of saving the new value.
     69
     70        * UserInterface/Main.html:
     71        * Localizations/en.lproj/localizedStrings.js:
     72
     73        * UserInterface/Test/TestHarness.js:
     74        (TestHarness.prototype.newline): Added.
     75        (TestHarness.prototype.expectException):
     76        Add a special case for logging error message objects when running protocol tests.
     77
    1782019-08-29  Keith Rollin  <krollin@apple.com>
    279
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r249118 r249450  
    336336localizedStrings["Decoded"] = "Decoded";
    337337localizedStrings["Default"] = "Default";
     338localizedStrings["Deferred pause from blackboxed script"] = "Deferred pause from blackboxed script";
    338339localizedStrings["Delete"] = "Delete";
    339340localizedStrings["Delete Breakpoint"] = "Delete Breakpoint";
     
    588589localizedStrings["Idle"] = "Idle";
    589590localizedStrings["Ignore"] = "Ignore";
     591localizedStrings["Ignore script when debugging"] = "Ignore script when debugging";
    590592localizedStrings["Ignore the resource cache when loading resources"] = "Ignore the resource cache when loading resources";
    591593localizedStrings["Ignored"] = "Ignored";
     
    598600localizedStrings["Imported - %s"] = "Imported - %s";
    599601localizedStrings["Imported \u2014 %s"] = "Imported \u2014 %s";
     602localizedStrings["Include script when debugging"] = "Include script when debugging";
    600603localizedStrings["Incomplete"] = "Incomplete";
    601604localizedStrings["Indent width:"] = "Indent width:";
  • trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js

    r249014 r249450  
    114114        this._value = value;
    115115
     116        this.save();
     117    }
     118
     119    save()
     120    {
    116121        if (!window.InspectorTest && window.localStorage) {
    117122            try {
    118                 // Use Object.shallowEqual to properly compare objects.
    119123                if (Object.shallowEqual(this._value, this._defaultValue))
    120124                    delete window.localStorage[this._localStorageKey];
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js

    r248894 r249450  
    9090        this._nextBreakpointActionIdentifier = 1;
    9191
     92        this._blackboxURLsSetting = new WI.Setting("debugger-blackbox-urls", []);
     93
    9294        this._activeCallFrame = null;
    9395
     
    157159        if (target.DebuggerAgent.setAsyncStackTraceDepth)
    158160            target.DebuggerAgent.setAsyncStackTraceDepth(this._asyncStackTraceDepthSetting.value);
     161
     162        // COMPATIBILITY (iOS 13): Debugger.setShouldBlackboxURL did not exist yet.
     163        if (target.DebuggerAgent.setShouldBlackboxURL) {
     164            for (let url of this._blackboxURLsSetting.value)
     165                target.DebuggerAgent.setShouldBlackboxURL(url, true);
     166        }
    159167
    160168        if (WI.isEngineeringBuild) {
     
    177185        }
    178186        this._restoringBreakpoints = false;
     187    }
     188
     189    // Static
     190
     191    static supportsBlackboxingScripts()
     192    {
     193        return !!InspectorBackend.domains.Debugger.setShouldBlackboxURL;
     194    }
     195
     196    static pauseReasonFromPayload(payload)
     197    {
     198        switch (payload) {
     199        case InspectorBackend.domains.Debugger.PausedReason.AnimationFrame:
     200            return WI.DebuggerManager.PauseReason.AnimationFrame;
     201        case InspectorBackend.domains.Debugger.PausedReason.Assert:
     202            return WI.DebuggerManager.PauseReason.Assertion;
     203        case InspectorBackend.domains.Debugger.PausedReason.BlackboxedScript:
     204            return WI.DebuggerManager.PauseReason.BlackboxedScript;
     205        case InspectorBackend.domains.Debugger.PausedReason.Breakpoint:
     206            return WI.DebuggerManager.PauseReason.Breakpoint;
     207        case InspectorBackend.domains.Debugger.PausedReason.CSPViolation:
     208            return WI.DebuggerManager.PauseReason.CSPViolation;
     209        case InspectorBackend.domains.Debugger.PausedReason.DOM:
     210            return WI.DebuggerManager.PauseReason.DOM;
     211        case InspectorBackend.domains.Debugger.PausedReason.DebuggerStatement:
     212            return WI.DebuggerManager.PauseReason.DebuggerStatement;
     213        case InspectorBackend.domains.Debugger.PausedReason.EventListener:
     214            return WI.DebuggerManager.PauseReason.EventListener;
     215        case InspectorBackend.domains.Debugger.PausedReason.Exception:
     216            return WI.DebuggerManager.PauseReason.Exception;
     217        case InspectorBackend.domains.Debugger.PausedReason.Fetch:
     218            return WI.DebuggerManager.PauseReason.Fetch;
     219        case InspectorBackend.domains.Debugger.PausedReason.Interval:
     220            return WI.DebuggerManager.PauseReason.Interval;
     221        case InspectorBackend.domains.Debugger.PausedReason.Listener:
     222            return WI.DebuggerManager.PauseReason.Listener;
     223        case InspectorBackend.domains.Debugger.PausedReason.Microtask:
     224            return WI.DebuggerManager.PauseReason.Microtask;
     225        case InspectorBackend.domains.Debugger.PausedReason.PauseOnNextStatement:
     226            return WI.DebuggerManager.PauseReason.PauseOnNextStatement;
     227        case InspectorBackend.domains.Debugger.PausedReason.Timeout:
     228            return WI.DebuggerManager.PauseReason.Timeout;
     229        case InspectorBackend.domains.Debugger.PausedReason.Timer:
     230            return WI.DebuggerManager.PauseReason.Timer;
     231        case InspectorBackend.domains.Debugger.PausedReason.XHR:
     232            return WI.DebuggerManager.PauseReason.XHR;
     233        default:
     234            return WI.DebuggerManager.PauseReason.Other;
     235        }
    179236    }
    180237
     
    350407    }
    351408
     409    isScriptBlackboxed(sourceCode)
     410    {
     411        return this._blackboxURLsSetting.value.includes(sourceCode.contentIdentifier);
     412    }
     413
     414    setShouldBlackboxScript(sourceCode, shouldBlackbox)
     415    {
     416        console.assert(DebuggerManager.supportsBlackboxingScripts());
     417        console.assert(sourceCode instanceof WI.SourceCode);
     418        console.assert(sourceCode.contentIdentifier);
     419        console.assert(!isWebKitInjectedScript(sourceCode.contentIdentifier));
     420
     421        this._blackboxURLsSetting.value.toggleIncludes(sourceCode.contentIdentifier, shouldBlackbox);
     422        this._blackboxURLsSetting.save();
     423
     424        for (let target of WI.targets) {
     425            // COMPATIBILITY (iOS 13): Debugger.setShouldBlackboxURL did not exist yet.
     426            if (target.DebuggerAgent.setShouldBlackboxURL)
     427                target.DebuggerAgent.setShouldBlackboxURL(sourceCode.contentIdentifier, !!shouldBlackbox);
     428        }
     429
     430        this.dispatchEventToListeners(DebuggerManager.Event.BlackboxedURLsChanged);
     431    }
     432
    352433    get asyncStackTraceDepth()
    353434    {
     
    618699
    619700        let callFrames = [];
    620         let pauseReason = this._pauseReasonFromPayload(reason);
     701        let pauseReason = DebuggerManager.pauseReasonFromPayload(reason);
    621702        let pauseData = data || null;
    622703
     
    844925    }
    845926
    846     _pauseReasonFromPayload(payload)
    847     {
    848         // FIXME: Handle other backend pause reasons.
    849         switch (payload) {
    850         case DebuggerAgent.PausedReason.AnimationFrame:
    851             return WI.DebuggerManager.PauseReason.AnimationFrame;
    852         case DebuggerAgent.PausedReason.Assert:
    853             return WI.DebuggerManager.PauseReason.Assertion;
    854         case DebuggerAgent.PausedReason.Breakpoint:
    855             return WI.DebuggerManager.PauseReason.Breakpoint;
    856         case DebuggerAgent.PausedReason.CSPViolation:
    857             return WI.DebuggerManager.PauseReason.CSPViolation;
    858         case DebuggerAgent.PausedReason.DOM:
    859             return WI.DebuggerManager.PauseReason.DOM;
    860         case DebuggerAgent.PausedReason.DebuggerStatement:
    861             return WI.DebuggerManager.PauseReason.DebuggerStatement;
    862         case DebuggerAgent.PausedReason.EventListener:
    863             return WI.DebuggerManager.PauseReason.EventListener;
    864         case DebuggerAgent.PausedReason.Exception:
    865             return WI.DebuggerManager.PauseReason.Exception;
    866         case DebuggerAgent.PausedReason.Fetch:
    867             return WI.DebuggerManager.PauseReason.Fetch;
    868         case DebuggerAgent.PausedReason.Interval:
    869             return WI.DebuggerManager.PauseReason.Interval;
    870         case DebuggerAgent.PausedReason.Listener:
    871             return WI.DebuggerManager.PauseReason.Listener;
    872         case DebuggerAgent.PausedReason.Microtask:
    873             return WI.DebuggerManager.PauseReason.Microtask;
    874         case DebuggerAgent.PausedReason.PauseOnNextStatement:
    875             return WI.DebuggerManager.PauseReason.PauseOnNextStatement;
    876         case DebuggerAgent.PausedReason.Timeout:
    877             return WI.DebuggerManager.PauseReason.Timeout;
    878         case DebuggerAgent.PausedReason.Timer:
    879             return WI.DebuggerManager.PauseReason.Timer;
    880         case DebuggerAgent.PausedReason.XHR:
    881             return WI.DebuggerManager.PauseReason.XHR;
    882         default:
    883             return WI.DebuggerManager.PauseReason.Other;
    884         }
    885     }
    886 
    887927    _debuggerBreakpointActionType(type)
    888928    {
     
    13911431    ProbeSetAdded: "debugger-manager-probe-set-added",
    13921432    ProbeSetRemoved: "debugger-manager-probe-set-removed",
     1433    BlackboxedURLsChanged: "blackboxed-urls-changed",
    13931434};
    13941435
     
    13961437    AnimationFrame: "animation-frame",
    13971438    Assertion: "assertion",
     1439    BlackboxedScript: "blackboxed-script",
    13981440    Breakpoint: "breakpoint",
    13991441    CSPViolation: "CSP-violation",
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r249118 r249450  
    198198    <link rel="stylesheet" href="Views/SoftContextMenu.css">
    199199    <link rel="stylesheet" href="Views/SourceCodeTextEditor.css">
     200    <link rel="stylesheet" href="Views/SourceCodeTreeElement.css">
    200201    <link rel="stylesheet" href="Views/SourcesNavigationSidebarPanel.css">
    201202    <link rel="stylesheet" href="Views/SpreadsheetCSSStyleDeclarationEditor.css">
  • trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js

    r248284 r249450  
    353353    }
    354354
     355    get isScript()
     356    {
     357        return this._type === Resource.Type.Script;
     358    }
     359
    355360    get displayName()
    356361    {
  • trunk/Source/WebInspectorUI/UserInterface/Models/Script.js

    r247747 r249450  
    121121    }
    122122
     123    get isScript()
     124    {
     125        return true;
     126    }
     127
    123128    get displayName()
    124129    {
  • trunk/Source/WebInspectorUI/UserInterface/Models/SourceCode.js

    r247747 r249450  
    104104    }
    105105
     106    get isScript()
     107    {
     108        // Implemented by subclasses if needed.
     109        return false;
     110    }
     111
     112    get supportsScriptBlackboxing()
     113    {
     114        if (!this.isScript)
     115            return false;
     116        if (!WI.DebuggerManager.supportsBlackboxingScripts())
     117            return false;
     118        let contentIdentifier = this.contentIdentifier;
     119        return contentIdentifier && !isWebKitInjectedScript(contentIdentifier);
     120    }
     121
    106122    get sourceMaps()
    107123    {
  • trunk/Source/WebInspectorUI/UserInterface/Test/TestHarness.js

    r248760 r249450  
    220220        let expectAndDumpError = (e) => {
    221221            this.expectNotNull(e, "Should produce an exception.");
    222             if (e)
     222            if (!e)
     223                return;
     224
     225            if (e instanceof Error || !(e instanceof Object))
    223226                this.log(e.toString());
     227            else {
     228                try {
     229                    this.json(e);
     230                } catch {
     231                    this.log(e.constructor.name);
     232                }
     233            }
    224234        }
    225235
  • trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js

    r249291 r249450  
    11671167
    11681168        this._updatePauseReasonGotoArrow();
    1169         return this._updatePauseReasonSection();
    1170     }
    1171 
    1172     _updatePauseReasonSection()
    1173     {
    11741169        let target = WI.debuggerManager.activeCallFrame.target;
    11751170        let targetData = WI.debuggerManager.dataForTarget(target);
    1176         let {pauseReason, pauseData} = targetData;
    1177 
     1171        return this._updatePauseReasonSection(target, targetData.pauseReason, targetData.pauseData);
     1172    }
     1173
     1174    _updatePauseReasonSection(target, pauseReason, pauseData)
     1175    {
    11781176        switch (pauseReason) {
    11791177        case WI.DebuggerManager.PauseReason.AnimationFrame:
     
    12031201            this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
    12041202            return true;
     1203
     1204        case WI.DebuggerManager.PauseReason.BlackboxedScript: {
     1205            console.assert(pauseData);
     1206            if (pauseData)
     1207                this._updatePauseReasonSection(target, WI.DebuggerManager.pauseReasonFromPayload(pauseData.originalReason), pauseData.originalData);
     1208
     1209            // Don't use `_pauseReasonTextRow` as it may have already been set.
     1210            let blackboxReasonTextRow = new WI.DetailsSectionTextRow(WI.UIString("Deferred pause from blackboxed script"));
     1211            blackboxReasonTextRow.__blackboxReason = true;
     1212
     1213            let existingRows = this._pauseReasonGroup.rows.filter((row) => !row.__blackboxReason);
     1214            this._pauseReasonGroup.rows = [blackboxReasonTextRow, ...existingRows];
     1215            return true;
     1216        }
    12051217
    12061218        case WI.DebuggerManager.PauseReason.Breakpoint:
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js

    r243180 r249450  
    119119            this._resource.removeEventListener(WI.Resource.Event.URLDidChange, this._urlDidChange, this);
    120120            this._resource.removeEventListener(WI.Resource.Event.TypeDidChange, this._typeDidChange, this);
    121             this._resource.removeEventListener(WI.Resource.Event.LoadingDidFinish, this._updateStatus, this);
    122             this._resource.removeEventListener(WI.Resource.Event.LoadingDidFail, this._updateStatus, this);
     121            this._resource.removeEventListener(WI.Resource.Event.LoadingDidFinish, this.updateStatus, this);
     122            this._resource.removeEventListener(WI.Resource.Event.LoadingDidFail, this.updateStatus, this);
    123123        }
    124124
     
    129129        resource.addEventListener(WI.Resource.Event.URLDidChange, this._urlDidChange, this);
    130130        resource.addEventListener(WI.Resource.Event.TypeDidChange, this._typeDidChange, this);
    131         resource.addEventListener(WI.Resource.Event.LoadingDidFinish, this._updateStatus, this);
    132         resource.addEventListener(WI.Resource.Event.LoadingDidFail, this._updateStatus, this);
     131        resource.addEventListener(WI.Resource.Event.LoadingDidFinish, this.updateStatus, this);
     132        resource.addEventListener(WI.Resource.Event.LoadingDidFail, this.updateStatus, this);
    133133
    134134        this._updateTitles();
    135         this._updateStatus();
     135        this.updateStatus();
    136136        this._updateToolTip();
    137137    }
     
    176176    }
    177177
    178     populateContextMenu(contextMenu, event)
    179     {
    180         WI.appendContextMenuItemsForSourceCode(contextMenu, this._resource);
    181 
    182         super.populateContextMenu(contextMenu, event);
    183     }
    184 
    185     // Private
    186 
    187     _updateStatus()
    188     {
     178    updateStatus()
     179    {
     180        super.updateStatus();
     181
     182        if (!this._resource)
     183            return;
     184
    189185        if (this._resource.hadLoadingError())
    190186            this.addClassName(WI.ResourceTreeElement.FailedStyleClassName);
     
    195191            if (!this.status || !this.status[WI.ResourceTreeElement.SpinnerSymbol]) {
    196192                let spinner = new WI.IndeterminateProgressSpinner;
    197                 this.status = spinner.element;
    198                 this.status[WI.ResourceTreeElement.SpinnerSymbol] = true;
     193                if (this.status)
     194                    this.statusElement.insertAdjacentElement("afterbegin", spinner.element);
     195                else
     196                    this.status = spinner.element;
     197                this.status[WI.ResourceTreeElement.SpinnerSymbol] = spinner.element;
    199198            }
    200199        } else {
    201             if (this.status && this.status[WI.ResourceTreeElement.SpinnerSymbol])
    202                 this.status = "";
    203         }
    204     }
     200            if (this.status && this.status[WI.ResourceTreeElement.SpinnerSymbol]) {
     201                if (this.status === this.status[WI.ResourceTreeElement.SpinnerSymbol])
     202                    this.status = null;
     203                else {
     204                    this.status[WI.ResourceTreeElement.SpinnerSymbol].remove();
     205                    this.status[WI.ResourceTreeElement.SpinnerSymbol] = null;
     206                }
     207            }
     208        }
     209    }
     210
     211    populateContextMenu(contextMenu, event)
     212    {
     213        WI.appendContextMenuItemsForSourceCode(contextMenu, this._resource);
     214
     215        super.populateContextMenu(contextMenu, event);
     216    }
     217
     218    // Private
    205219
    206220    _updateToolTip()
  • trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTreeElement.js

    r243180 r249450  
    129129    }
    130130
     131    canSelectOnMouseDown(event)
     132    {
     133        if (this._toggleBlackboxedImageElement && this._toggleBlackboxedImageElement.contains(event.target))
     134            return false;
     135        return super.canSelectOnMouseDown(event);
     136    }
     137
    131138    // Protected
    132139
     
    151158    }
    152159
     160    updateStatus()
     161    {
     162        if (this._sourceCode.supportsScriptBlackboxing) {
     163            if (!this._toggleBlackboxedImageElement) {
     164                this._toggleBlackboxedImageElement = document.createElement("img");
     165                this._toggleBlackboxedImageElement.classList.add("toggle-script-blackboxed");
     166                this._toggleBlackboxedImageElement.addEventListener("click", this._handleToggleBlackboxedImageElementClicked.bind(this));
     167            }
     168
     169            this.status = this._toggleBlackboxedImageElement;
     170            this._updateToggleBlackboxImageElementState();
     171        }
     172    }
     173
    153174    // Protected (ResourceTreeElement calls this when its Resource changes dynamically for Frames)
    154175
     
    160181            return;
    161182
    162         if (this._sourceCode)
     183        let oldSupportsScriptBlackboxing = false;
     184
     185        if (this._sourceCode) {
     186            oldSupportsScriptBlackboxing = this._sourceCode.supportsScriptBlackboxing;
     187
    163188            this._sourceCode.removeEventListener(WI.SourceCode.Event.SourceMapAdded, this.updateSourceMapResources, this);
     189        }
    164190
    165191        this._sourceCode = sourceCode;
    166192        this._sourceCode.addEventListener(WI.SourceCode.Event.SourceMapAdded, this.updateSourceMapResources, this);
    167193
     194        let newSupportsScriptBlackboxing = this._sourceCode.supportsScriptBlackboxing;
     195        if (oldSupportsScriptBlackboxing !== newSupportsScriptBlackboxing) {
     196            if (newSupportsScriptBlackboxing)
     197                WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BlackboxedURLsChanged, this._updateToggleBlackboxImageElementState, this);
     198            else
     199                WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.BlackboxedURLsChanged, this._updateToggleBlackboxImageElementState, this);
     200        }
     201
    168202        this.updateSourceMapResources();
     203
     204        this.updateStatus();
     205    }
     206
     207    // Private
     208
     209    _updateToggleBlackboxImageElementState()
     210    {
     211        let isBlackboxed = WI.debuggerManager.isScriptBlackboxed(this._sourceCode);
     212        this._toggleBlackboxedImageElement.classList.toggle("blackboxed", isBlackboxed);
     213        this._toggleBlackboxedImageElement.title = isBlackboxed ? WI.UIString("Include script when debugging") : WI.UIString("Ignore script when debugging");
     214    }
     215
     216    _handleToggleBlackboxedImageElementClicked(event)
     217    {
     218        let isBlackboxed = WI.debuggerManager.isScriptBlackboxed(this._sourceCode);
     219        WI.debuggerManager.setShouldBlackboxScript(this._sourceCode, !isBlackboxed);
     220
     221        this._updateToggleBlackboxImageElementState();
    169222    }
    170223};
  • trunk/Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js

    r249291 r249450  
    11731173
    11741174        this._updatePauseReasonGotoArrow();
    1175         return this._updatePauseReasonSection();
     1175
     1176        let target = WI.debuggerManager.activeCallFrame.target;
     1177        let targetData = WI.debuggerManager.dataForTarget(target);
     1178        return this._updatePauseReasonSection(target, targetData.pauseReason, targetData.pauseData);
    11761179    }
    11771180
     
    11951198    }
    11961199
    1197     _updatePauseReasonSection()
    1198     {
    1199         let target = WI.debuggerManager.activeCallFrame.target;
    1200         let targetData = WI.debuggerManager.dataForTarget(target);
    1201         let {pauseReason, pauseData} = targetData;
    1202 
     1200    _updatePauseReasonSection(target, pauseReason, pauseData)
     1201    {
    12031202        switch (pauseReason) {
    12041203        case WI.DebuggerManager.PauseReason.AnimationFrame: {
     
    12271226            this._pauseReasonGroup.rows = [this._pauseReasonTextRow];
    12281227            return true;
     1228
     1229        case WI.DebuggerManager.PauseReason.BlackboxedScript: {
     1230            console.assert(pauseData);
     1231            if (pauseData)
     1232                this._updatePauseReasonSection(target, WI.DebuggerManager.pauseReasonFromPayload(pauseData.originalReason), pauseData.originalData);
     1233
     1234            // Don't use `_pauseReasonTextRow` as it may have already been set.
     1235            let blackboxReasonTextRow = new WI.DetailsSectionTextRow(WI.UIString("Deferred pause from blackboxed script"));
     1236            blackboxReasonTextRow.__blackboxReason = true;
     1237
     1238            let existingRows = this._pauseReasonGroup.rows.filter((row) => !row.__blackboxReason);
     1239            this._pauseReasonGroup.rows = [blackboxReasonTextRow, ...existingRows];
     1240            return true;
     1241        }
    12291242
    12301243        case WI.DebuggerManager.PauseReason.Breakpoint: {
Note: See TracChangeset for help on using the changeset viewer.