Shard html5lib/runner.html into many separate tests
[WebKit-https.git] / Source / WebCore / inspector / InspectorDebuggerAgent.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010-2011 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "InspectorDebuggerAgent.h"
32
33 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)
34 #include "ContentSearchUtils.h"
35 #include "InjectedScript.h"
36 #include "InjectedScriptManager.h"
37 #include "InspectorFrontend.h"
38 #include "InspectorPageAgent.h"
39 #include "InspectorState.h"
40 #include "InspectorValues.h"
41 #include "InstrumentingAgents.h"
42 #include "RegularExpression.h"
43 #include "ScriptDebugServer.h"
44 #include "ScriptObject.h"
45 #include <wtf/text/WTFString.h>
46
47 namespace WebCore {
48
49 namespace DebuggerAgentState {
50 static const char debuggerEnabled[] = "debuggerEnabled";
51 static const char javaScriptBreakpoints[] = "javaScriptBreakopints";
52 };
53
54 const char* InspectorDebuggerAgent::backtraceObjectGroup = "backtrace-object-group";
55
56 InspectorDebuggerAgent::InspectorDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorState* inspectorState, InjectedScriptManager* injectedScriptManager)
57     : InspectorBaseAgent<InspectorDebuggerAgent>("Debugger", instrumentingAgents, inspectorState)
58     , m_injectedScriptManager(injectedScriptManager)
59     , m_frontend(0)
60     , m_pausedScriptState(0)
61     , m_javaScriptPauseScheduled(false)
62     , m_listener(0)
63 {
64     // FIXME: make breakReason optional so that there was no need to init it with "other".
65     clearBreakDetails();
66 }
67
68 InspectorDebuggerAgent::~InspectorDebuggerAgent()
69 {
70     ASSERT(!m_instrumentingAgents->inspectorDebuggerAgent());
71 }
72
73 void InspectorDebuggerAgent::enable()
74 {
75     m_instrumentingAgents->setInspectorDebuggerAgent(this);
76
77     // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends
78     scriptDebugServer().setBreakpointsActivated(true);
79     startListeningScriptDebugServer();
80
81     if (m_listener)
82         m_listener->debuggerWasEnabled();
83 }
84
85 void InspectorDebuggerAgent::disable()
86 {
87     m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, InspectorObject::create());
88     m_instrumentingAgents->setInspectorDebuggerAgent(0);
89
90     stopListeningScriptDebugServer();
91     scriptDebugServer().clearBreakpoints();
92     clear();
93
94     if (m_listener)
95         m_listener->debuggerWasDisabled();
96 }
97
98 bool InspectorDebuggerAgent::enabled()
99 {
100     return m_state->getBoolean(DebuggerAgentState::debuggerEnabled);
101 }
102
103 void InspectorDebuggerAgent::causesRecompilation(ErrorString*, bool* result)
104 {
105     *result = scriptDebugServer().causesRecompilation();
106 }
107
108 void InspectorDebuggerAgent::canSetScriptSource(ErrorString*, bool* result)
109 {
110     *result = scriptDebugServer().canSetScriptSource();
111 }
112
113 void InspectorDebuggerAgent::supportsNativeBreakpoints(ErrorString*, bool* result)
114 {
115     *result = scriptDebugServer().supportsNativeBreakpoints();
116 }
117
118 void InspectorDebuggerAgent::enable(ErrorString*)
119 {
120     if (enabled())
121         return;
122
123     enable();
124     m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
125
126     ASSERT(m_frontend);
127 }
128
129 void InspectorDebuggerAgent::disable(ErrorString*)
130 {
131     if (!enabled())
132         return;
133
134     disable();
135     m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
136 }
137
138 void InspectorDebuggerAgent::restore()
139 {
140     if (enabled()) {
141         m_frontend->globalObjectCleared();
142         enable();
143     }
144 }
145
146 void InspectorDebuggerAgent::setFrontend(InspectorFrontend* frontend)
147 {
148     m_frontend = frontend->debugger();
149 }
150
151 void InspectorDebuggerAgent::clearFrontend()
152 {
153     m_frontend = 0;
154
155     if (!enabled())
156         return;
157
158     disable();
159
160     // FIXME: due to m_state->mute() hack in InspectorController, debuggerEnabled is actually set to false only
161     // in InspectorState, but not in cookie. That's why after navigation debuggerEnabled will be true,
162     // but after front-end re-open it will still be false.
163     m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
164 }
165
166 void InspectorDebuggerAgent::setBreakpointsActive(ErrorString*, bool active)
167 {
168     if (active)
169         scriptDebugServer().activateBreakpoints();
170     else
171         scriptDebugServer().deactivateBreakpoints();
172 }
173
174 void InspectorDebuggerAgent::didClearMainFrameWindowObject()
175 {
176     m_scripts.clear();
177     m_breakpointIdToDebugServerBreakpointIds.clear();
178     if (m_frontend)
179         m_frontend->globalObjectCleared();
180 }
181
182 static PassRefPtr<InspectorObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, bool isRegex)
183 {
184     RefPtr<InspectorObject> breakpointObject = InspectorObject::create();
185     breakpointObject->setString("url", url);
186     breakpointObject->setNumber("lineNumber", lineNumber);
187     breakpointObject->setNumber("columnNumber", columnNumber);
188     breakpointObject->setString("condition", condition);
189     breakpointObject->setBoolean("isRegex", isRegex);
190     return breakpointObject;
191 }
192
193 static bool matches(const String& url, const String& pattern, bool isRegex)
194 {
195     if (isRegex) {
196         RegularExpression regex(pattern, TextCaseSensitive);
197         return regex.match(url) != -1;
198     }
199     return url == pattern;
200 }
201
202 void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const String* const optionalCondition, String* outBreakpointId, RefPtr<InspectorArray>& locations)
203 {
204     if (!optionalURL == !optionalURLRegex) {
205         *errorString = "Either url or urlRegex must be specified.";
206         return;
207     }
208
209     String url = optionalURL ? *optionalURL : *optionalURLRegex;
210     int columnNumber = optionalColumnNumber ? *optionalColumnNumber : 0;
211     String condition = optionalCondition ? *optionalCondition : "";
212     bool isRegex = optionalURLRegex;
213
214     String breakpointId = (isRegex ? "/" + url + "/" : url) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber);
215     RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
216     if (breakpointsCookie->find(breakpointId) != breakpointsCookie->end()) {
217         *errorString = "Breakpoint at specified location already exists.";
218         return;
219     }
220
221     breakpointsCookie->setObject(breakpointId, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, isRegex));
222     m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie);
223
224     ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
225     for (ScriptsMap::iterator it = m_scripts.begin(); it != m_scripts.end(); ++it) {
226         if (!matches(it->second.url, url, isRegex))
227             continue;
228         RefPtr<InspectorObject> location = resolveBreakpoint(breakpointId, it->first, breakpoint);
229         if (location)
230             locations->pushObject(location);
231     }
232     *outBreakpointId = breakpointId;
233 }
234
235 static bool parseLocation(ErrorString* errorString, RefPtr<InspectorObject> location, String* scriptId, int* lineNumber, int* columnNumber)
236 {
237     if (!location->getString("scriptId", scriptId) || !location->getNumber("lineNumber", lineNumber)) {
238         // FIXME: replace with input validation.
239         *errorString = "scriptId and lineNumber are required.";
240         return false;
241     }
242     *columnNumber = 0;
243     location->getNumber("columnNumber", columnNumber);
244     return true;
245 }
246
247 void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, PassRefPtr<InspectorObject> location, const String* const optionalCondition, String* outBreakpointId, RefPtr<InspectorObject>& actualLocation)
248 {
249     String scriptId;
250     int lineNumber;
251     int columnNumber;
252
253     if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
254         return;
255
256     String condition = optionalCondition ? *optionalCondition : emptyString();
257
258     String breakpointId = scriptId + ':' + String::number(lineNumber) + ':' + String::number(columnNumber);
259     if (m_breakpointIdToDebugServerBreakpointIds.find(breakpointId) != m_breakpointIdToDebugServerBreakpointIds.end())
260         return;
261     ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
262     actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint);
263     if (actualLocation)
264         *outBreakpointId = breakpointId;
265     else
266         *errorString = "Could not resolve breakpoint";
267 }
268
269 void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakpointId)
270 {
271     RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
272     breakpointsCookie->remove(breakpointId);
273     m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie);
274
275     BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
276     if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
277         return;
278     for (size_t i = 0; i < debugServerBreakpointIdsIterator->second.size(); ++i)
279         scriptDebugServer().removeBreakpoint(debugServerBreakpointIdsIterator->second[i]);
280     m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIterator);
281 }
282
283 void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, PassRefPtr<InspectorObject> location)
284 {
285     if (!m_continueToLocationBreakpointId.isEmpty()) {
286         scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
287         m_continueToLocationBreakpointId = "";
288     }
289
290     String scriptId;
291     int lineNumber;
292     int columnNumber;
293
294     if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
295         return;
296
297     ScriptBreakpoint breakpoint(lineNumber, columnNumber, "");
298     m_continueToLocationBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber);
299     resume(errorString);
300 }
301
302 PassRefPtr<InspectorObject> InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const String& scriptId, const ScriptBreakpoint& breakpoint)
303 {
304     ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
305     if (scriptIterator == m_scripts.end())
306         return 0;
307     Script& script = scriptIterator->second;
308     if (breakpoint.lineNumber < script.startLine || script.endLine < breakpoint.lineNumber)
309         return 0;
310
311     int actualLineNumber;
312     int actualColumnNumber;
313     String debugServerBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber);
314     if (debugServerBreakpointId.isEmpty())
315         return 0;
316
317     BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
318     if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
319         debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.set(breakpointId, Vector<String>()).first;
320     debugServerBreakpointIdsIterator->second.append(debugServerBreakpointId);
321
322     RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
323         .setScriptId(scriptId)
324         .setLineNumber(actualLineNumber);
325     location->setColumnNumber(actualColumnNumber);
326     return location;
327 }
328
329 static PassRefPtr<InspectorObject> scriptToInspectorObject(ScriptObject scriptObject)
330 {
331     if (scriptObject.hasNoValue())
332         return 0;
333     RefPtr<InspectorValue> value = scriptObject.toInspectorValue(scriptObject.scriptState());
334     if (!value)
335         return 0;
336     return value->asObject();
337 }
338
339 void InspectorDebuggerAgent::searchInContent(ErrorString* error, const String& scriptId, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<InspectorArray>& results)
340 {
341     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
342     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
343
344     ScriptsMap::iterator it = m_scripts.find(scriptId);
345     if (it != m_scripts.end())
346         results = ContentSearchUtils::searchInTextByLines(it->second.source, query, caseSensitive, isRegex);
347     else
348         *error = "No script for id: " + scriptId;
349 }
350
351 void InspectorDebuggerAgent::setScriptSource(ErrorString* error, const String& scriptId, const String& newContent, const bool* const preview, RefPtr<InspectorArray>& newCallFrames, RefPtr<InspectorObject>& result)
352 {
353     bool previewOnly = preview && *preview;
354     ScriptObject resultObject;
355     if (!scriptDebugServer().setScriptSource(scriptId, newContent, previewOnly, error, &m_currentCallStack, &resultObject))
356         return;
357     newCallFrames = currentCallFrames();
358     RefPtr<InspectorObject> object = scriptToInspectorObject(resultObject);
359     if (object)
360         result = object;
361 }
362
363 void InspectorDebuggerAgent::getScriptSource(ErrorString* error, const String& scriptId, String* scriptSource)
364 {
365     ScriptsMap::iterator it = m_scripts.find(scriptId);
366     if (it != m_scripts.end())
367         *scriptSource = it->second.source;
368     else
369         *error = "No script for id: " + scriptId;
370 }
371
372 void InspectorDebuggerAgent::getFunctionLocation(ErrorString* errorString, const String& functionId, RefPtr<InspectorObject>& location)
373 {
374     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(functionId);
375     if (injectedScript.hasNoValue()) {
376         *errorString = "Inspected frame has gone";
377         return;
378     }
379     injectedScript.getFunctionLocation(errorString, functionId, &location);
380 }
381
382 void InspectorDebuggerAgent::schedulePauseOnNextStatement(const String& breakReason, PassRefPtr<InspectorObject> data)
383 {
384     if (m_javaScriptPauseScheduled)
385         return;
386     m_breakReason = breakReason;
387     m_breakAuxData = data;
388     scriptDebugServer().setPauseOnNextStatement(true);
389 }
390
391 void InspectorDebuggerAgent::cancelPauseOnNextStatement()
392 {
393     if (m_javaScriptPauseScheduled)
394         return;
395     clearBreakDetails();
396     scriptDebugServer().setPauseOnNextStatement(false);
397 }
398
399 void InspectorDebuggerAgent::pause(ErrorString*)
400 {
401     if (m_javaScriptPauseScheduled)
402         return;
403     clearBreakDetails();
404     scriptDebugServer().setPauseOnNextStatement(true);
405     m_javaScriptPauseScheduled = true;
406 }
407
408 void InspectorDebuggerAgent::resume(ErrorString* errorString)
409 {
410     if (!assertPaused(errorString))
411         return;
412     m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
413     scriptDebugServer().continueProgram();
414 }
415
416 void InspectorDebuggerAgent::stepOver(ErrorString* errorString)
417 {
418     if (!assertPaused(errorString))
419         return;
420     scriptDebugServer().stepOverStatement();
421 }
422
423 void InspectorDebuggerAgent::stepInto(ErrorString* errorString)
424 {
425     if (!assertPaused(errorString))
426         return;
427     scriptDebugServer().stepIntoStatement();
428 }
429
430 void InspectorDebuggerAgent::stepOut(ErrorString* errorString)
431 {
432     if (!assertPaused(errorString))
433         return;
434     scriptDebugServer().stepOutOfFunction();
435 }
436
437 void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, const String& stringPauseState)
438 {
439     ScriptDebugServer::PauseOnExceptionsState pauseState;
440     if (stringPauseState == "none")
441         pauseState = ScriptDebugServer::DontPauseOnExceptions;
442     else if (stringPauseState == "all")
443         pauseState = ScriptDebugServer::PauseOnAllExceptions;
444     else if (stringPauseState == "uncaught")
445         pauseState = ScriptDebugServer::PauseOnUncaughtExceptions;
446     else {
447         *errorString = "Unknown pause on exceptions mode: " + stringPauseState;
448         return;
449     }
450     scriptDebugServer().setPauseOnExceptionsState(static_cast<ScriptDebugServer::PauseOnExceptionsState>(pauseState));
451     if (scriptDebugServer().pauseOnExceptionsState() != pauseState)
452         *errorString = "Internal error. Could not change pause on exceptions state";
453 }
454
455 void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const returnByValue, RefPtr<InspectorObject>& result, bool* wasThrown)
456 {
457     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
458     if (injectedScript.hasNoValue()) {
459         *errorString = "Inspected frame has gone";
460         return;
461     }
462     injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, &result, wasThrown);
463 }
464
465 PassRefPtr<InspectorArray> InspectorDebuggerAgent::currentCallFrames()
466 {
467     if (!m_pausedScriptState)
468         return InspectorArray::create();
469     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState);
470     if (injectedScript.hasNoValue()) {
471         ASSERT_NOT_REACHED();
472         return InspectorArray::create();
473     }
474     return injectedScript.wrapCallFrames(m_currentCallStack);
475 }
476
477 String InspectorDebuggerAgent::sourceMapURLForScript(const Script& script)
478 {
479     DEFINE_STATIC_LOCAL(String, sourceMapHttpHeader, ("X-SourceMap"));
480
481     if (script.url.isEmpty())
482         return String();
483
484     InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent();
485     CachedResource* resource = pageAgent->cachedResource(pageAgent->mainFrame(), KURL(ParsedURLString, script.url));
486     if (resource)
487         return resource->response().httpHeaderField(sourceMapHttpHeader);
488     return String();
489 }
490
491 // JavaScriptDebugListener functions
492
493 void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& script)
494 {
495     // Don't send script content to the front end until it's really needed.
496     const bool* isContentScript = script.isContentScript ? &script.isContentScript : 0;
497     String sourceMapURL = sourceMapURLForScript(script);
498     m_frontend->scriptParsed(scriptId, script.url, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURL);
499
500     m_scripts.set(scriptId, script);
501
502     if (script.url.isEmpty())
503         return;
504
505     RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
506     for (InspectorObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
507         RefPtr<InspectorObject> breakpointObject = it->second->asObject();
508         bool isRegex;
509         breakpointObject->getBoolean("isRegex", &isRegex);
510         String url;
511         breakpointObject->getString("url", &url);
512         if (!matches(script.url, url, isRegex))
513             continue;
514         ScriptBreakpoint breakpoint;
515         breakpointObject->getNumber("lineNumber", &breakpoint.lineNumber);
516         breakpointObject->getNumber("columnNumber", &breakpoint.columnNumber);
517         breakpointObject->getString("condition", &breakpoint.condition);
518         RefPtr<InspectorObject> location = resolveBreakpoint(it->first, scriptId, breakpoint);
519         if (location)
520             m_frontend->breakpointResolved(it->first, location);
521     }
522 }
523
524 void InspectorDebuggerAgent::failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage)
525 {
526     m_frontend->scriptFailedToParse(url, data, firstLine, errorLine, errorMessage);
527 }
528
529 void InspectorDebuggerAgent::didPause(ScriptState* scriptState, const ScriptValue& callFrames, const ScriptValue& exception)
530 {
531     ASSERT(scriptState && !m_pausedScriptState);
532     m_pausedScriptState = scriptState;
533     m_currentCallStack = callFrames;
534
535     if (!exception.hasNoValue()) {
536         InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
537         if (!injectedScript.hasNoValue()) {
538             m_breakReason = "exception";
539             m_breakAuxData = injectedScript.wrapObject(exception, "backtrace");
540         }
541     }
542
543     m_frontend->paused(currentCallFrames(), m_breakReason, m_breakAuxData);
544     m_javaScriptPauseScheduled = false;
545
546     if (!m_continueToLocationBreakpointId.isEmpty()) {
547         scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
548         m_continueToLocationBreakpointId = "";
549     }
550 }
551
552 void InspectorDebuggerAgent::didContinue()
553 {
554     m_pausedScriptState = 0;
555     m_currentCallStack = ScriptValue();
556     clearBreakDetails();
557     m_frontend->resumed();
558 }
559
560 void InspectorDebuggerAgent::breakProgram(const String& breakReason, PassRefPtr<InspectorObject> data)
561 {
562     m_breakReason = breakReason;
563     m_breakAuxData = data;
564     scriptDebugServer().breakProgram();
565 }
566
567 void InspectorDebuggerAgent::clear()
568 {
569     m_pausedScriptState = 0;
570     m_currentCallStack = ScriptValue();
571     m_scripts.clear();
572     m_breakpointIdToDebugServerBreakpointIds.clear();
573     m_continueToLocationBreakpointId = String();
574     clearBreakDetails();
575     m_javaScriptPauseScheduled = false;
576 }
577
578 bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString)
579 {
580     if (!m_pausedScriptState) {
581         *errorString = "Can only perform operation while paused.";
582         return false;
583     }
584     return true;
585 }
586
587 void InspectorDebuggerAgent::clearBreakDetails()
588 {
589     m_breakReason = "other";
590     m_breakAuxData = 0;
591 }
592
593 } // namespace WebCore
594
595 #endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)