diff options
Diffstat (limited to 'WebKit/chromium')
65 files changed, 9674 insertions, 353 deletions
diff --git a/WebKit/chromium/ChangeLog b/WebKit/chromium/ChangeLog index 58c37a8..9cd3644 100644 --- a/WebKit/chromium/ChangeLog +++ b/WebKit/chromium/ChangeLog @@ -1,3 +1,1274 @@ +2010-02-12 Jeremy Orlow <jorlow@chromium.org> + + Reviewed by Darin Fisher. + + [Chromium] Add a blockedByPolicy output to WebStorageArea::setItem. + https://bugs.webkit.org/show_bug.cgi?id=34897 + + * public/WebStorageArea.h: + (WebKit::WebStorageArea::setItem): + * src/WebStorageAreaImpl.cpp: + (WebKit::WebStorageAreaImpl::setItem): + * src/WebStorageAreaImpl.h: + +2010-02-11 Jeremy Orlow <jorlow@chromium.org> + + Reviewed by David Levin. + + [Chromium] Add ENABLE_RUBY to the feature defines gypi + https://bugs.webkit.org/show_bug.cgi?id=34841 + + * features.gypi: + +2010-02-12 Yury Semikhatsky <yurys@chromium.org> + + Reviewed by Pavel Feldman. + + Chromium: Web Inspector on an element in a page where JS is blocked crashes the renderer + + https://bugs.webkit.org/show_bug.cgi?id=34890 + + * src/DebuggerAgentImpl.cpp: + (WebKit::DebuggerAgentImpl::createUtilityContext): + +2010-02-11 Mikhail Naganov <mnaganov@chromium.org> + + Reviewed by Pavel Feldman. + + [Chromium] Ignore subsequent requests of the same profiler log + chunks. This eliminates emission of several instances for the same + heap snapshot. + + https://bugs.webkit.org/show_bug.cgi?id=34833 + + * src/js/ProfilerAgent.js: + (devtools.ProfilerAgent): + (devtools.ProfilerAgent.prototype.initializeProfiling): + (devtools.ProfilerAgent.prototype._getNextLogLines): + (devtools.ProfilerAgent.prototype.startProfiling): + (devtools.ProfilerAgent.prototype._didGetActiveProfilerModules): + (devtools.ProfilerAgent.prototype._didGetLogLines): + +2010-02-10 James Hawkins <jhawkins@chromium.org> + + Reviewed by Eric Seidel. + + [Chromium] Remove code from SuggestionsPopup that was removed in a + previous revision of AutocompletePopup and accidentally added back in + the refactoring. + + https://bugs.webkit.org/show_bug.cgi?id=34818 + + * src/AutoFillPopupMenuClient.cpp: + * src/AutoFillPopupMenuClient.h: Added property svn:eol-style. + * src/SuggestionsPopupMenuClient.cpp: + (WebKit::SuggestionsPopupMenuClient::popupDidHide): + (WebKit::SuggestionsPopupMenuClient::setTextFromItem): + (WebKit::SuggestionsPopupMenuClient::initialize): + * src/SuggestionsPopupMenuClient.h: + +2010-02-10 Nate Chapin <japhet@chromium.org> + + Reviewed by Adam Barth. + + Update call to V8DOMWrapper::lookupDOMWrapper() to match new parameters. + + https://bugs.webkit.org/show_bug.cgi?id=34768 + + * src/DebuggerAgentImpl.cpp: + (WebKit::DebuggerAgentImpl::createUtilityContext): + +2010-02-10 Kenneth Russell <kbr@google.com> + + Reviewed by Oliver Hunt. + + Remove automatic viewport resizing + https://bugs.webkit.org/show_bug.cgi?id=34766 + + Removed automatic viewport resizing per conclusions on the WebGL + mailing list. Added test verifying new behavior and updated a + couple of previous tests failing after this change. + + * src/GraphicsContext3D.cpp: + (WebCore::GraphicsContext3DInternal::reshape): + +2010-02-10 Yury Semikhatsky <yurys@chromium.org> + + Reviewed by Pavel Feldman. + + Chromium Win build fix. Add third_party/nss to the dependencies list on Windows. + + https://bugs.webkit.org/show_bug.cgi?id=34789 + + * DEPS: + +2010-02-10 Yury Semikhatsky <yurys@chromium.org> + + Reviewed by Pavel Feldman. + + Rolling Chromium dependencies to match Chromium revision 38580. + + https://bugs.webkit.org/show_bug.cgi?id=34789 + + * DEPS: + +2010-02-10 Yury Semikhatsky <yurys@chromium.org> + + Reviewed by Pavel Feldman. + + Use v8::Debug::ProcessDebugMessages instead of executing an empty function + + https://bugs.webkit.org/show_bug.cgi?id=34704 + + * src/DebuggerAgent.h: + * src/DebuggerAgentImpl.cpp: + (WebKit::DebuggerAgentImpl::processDebugCommands): + * src/DebuggerAgentImpl.h: + * src/ToolsAgent.h: + * src/WebDevToolsAgentImpl.cpp: + * src/WebDevToolsAgentImpl.h: + * src/js/DebuggerAgent.js: + (devtools.DebuggerAgent.prototype.addBreakpoint): + * src/js/DevToolsHostStub.js: + (.RemoteDebuggerAgentStub.prototype.processDebugCommands): + * src/js/InjectDispatch.js: + (dispatch): + * src/js/ProfilerAgent.js: + (devtools.ProfilerAgent.prototype.startProfiling): + (devtools.ProfilerAgent.prototype.stopProfiling): + * src/js/Tests.js: + +2010-02-10 Tony Chang <tony@chromium.org> + + Unreviewed, build fix for Chromium Mac take 2. + + * src/AutoFillPopupMenuClient.cpp: + (WebKit::AutoFillPopupMenuClient::removeSuggestionAtIndex): + +2010-02-10 Tony Chang <tony@chromium.org> + + Unreviewed, build fix for Chromium Mac. + + * src/AutoFillPopupMenuClient.cpp: + (WebKit::AutoFillPopupMenuClient::removeSuggestionAtIndex): + +2010-02-09 James Hawkins <jhawkins@chromium.org> + + Reviewed by Darin Fisher. + + [Chromium] Refactor AutocompletePopupMenuClient into a base class, + SuggestionsPopupMenuClient, and two derived classes, + AutocompletePopupMenuClient and AutoFillPopupMenuClient. Currently + the behavior of suggestions popups has not changed. + + https://bugs.webkit.org/show_bug.cgi?id=34721 + + * WebKit.gyp: + * public/WebView.h: + * src/AutoFillPopupMenuClient.cpp: Added. + * src/AutoFillPopupMenuClient.h: Added. + * src/AutocompletePopupMenuClient.cpp: + (WebKit::AutocompletePopupMenuClient::getSuggestionsCount): + (WebKit::AutocompletePopupMenuClient::getSuggestion): + (WebKit::AutocompletePopupMenuClient::removeSuggestionAtIndex): + (WebKit::AutocompletePopupMenuClient::initialize): + (WebKit::AutocompletePopupMenuClient::setSuggestions): + * src/AutocompletePopupMenuClient.h: + * src/SuggestionsPopupMenuClient.cpp: Added. + * src/SuggestionsPopupMenuClient.h: Added. + * src/WebViewImpl.cpp: + (WebKit::WebViewImpl::WebViewImpl): + (WebKit::WebViewImpl::keyEvent): + (WebKit::WebViewImpl::autocompleteHandleKeyEvent): + (WebKit::WebViewImpl::applyAutofillSuggestions): + (WebKit::WebViewImpl::applyAutoFillSuggestions): + (WebKit::WebViewImpl::applyAutocompleteSuggestions): + * src/WebViewImpl.h: + +2010-02-09 Chris Guillory <ctguil@google.com> + + Reviewed by Darin Fisher. + + [Chromium] Add function for accessibility object state change notifications. + + https://bugs.webkit.org/show_bug.cgi?id=34464 + + * gyp_webkit: + * public/WebViewClient.h: + (WebKit::WebViewClient::didChangeAccessibilityObjectState): + * src/ChromeClientImpl.cpp: + (WebKit::ChromeClientImpl::didChangeAccessibilityObjectState): + * src/ChromeClientImpl.h: + +2010-02-09 Mikhail Naganov <mnaganov@chromium.org> + + Reviewed by Pavel Feldman. + + Continuing debugger and profiler unforking: narrow scope of JSC-specific ifdefs. + Also, enable JAVASCRIPT_DEBUGGER explicitly in features, it appears to be required + for really enabling it in V8 bindings generation. + + https://bugs.webkit.org/show_bug.cgi?id=34706 + + * features.gypi: + +2010-02-09 Jian Li <jianli@chromium.org> + + Reviewed by Darin Fisher. + + [chromium] Add the chromium interface to support Blob.slice. + https://bugs.webkit.org/show_bug.cgi?id=34652 + + * WebKit.gyp: + * public/WebFileInfo.h: Added. + * public/WebHTTPBody.h: + * src/WebHTTPBody.cpp: + (WebKit::WebHTTPBody::elementAt): + (WebKit::WebHTTPBody::appendFile): + +2010-02-09 Yury Semikhatsky <yurys@chromium.org> + + Unreviewed. Follow-up fix. + + Add missing devTools.css file. + + https://bugs.webkit.org/show_bug.cgi?id=34756 + + * src/js/devTools.css: Added. + +2010-02-09 Yury Semikhatsky <yurys@chromium.org> + + Reviewed by Pavel Feldman. + + Upstream DevTools Images and .css files. + + https://bugs.webkit.org/show_bug.cgi?id=34756 + + * WebKit.gypi: + * src/js/DevTools.css: Added. + * src/js/Images/segmentChromium.png: Added. + * src/js/Images/segmentHoverChromium.png: Added. + * src/js/Images/segmentHoverEndChromium.png: Added. + * src/js/Images/segmentSelectedChromium.png: Added. + * src/js/Images/segmentSelectedEndChromium.png: Added. + * src/js/Images/statusbarBackgroundChromium.png: Added. + * src/js/Images/statusbarBottomBackgroundChromium.png: Added. + * src/js/Images/statusbarButtonsChromium.png: Added. + * src/js/Images/statusbarMenuButtonChromium.png: Added. + * src/js/Images/statusbarMenuButtonSelectedChromium.png: Added. + +2010-02-09 Yury Semikhatsky <yurys@chromium.org> + + Reviewed by Pavel Feldman. + + Upstream JavaScript part of DevTools WebKit API implementation(now + with the added files). + + https://bugs.webkit.org/show_bug.cgi?id=34744 + + * WebKit.gypi: Added. + * src/js/DebuggerAgent.js: Added. + (devtools.DebuggerAgent): + (devtools.DebuggerAgent.prototype.reset): + (devtools.DebuggerAgent.prototype.initUI): + (devtools.DebuggerAgent.prototype.resolveScriptSource.this.requestSeqToCallback_.cmd.getSequenceNumber): + (devtools.DebuggerAgent.prototype.resolveScriptSource): + (devtools.DebuggerAgent.prototype.pauseExecution): + (devtools.DebuggerAgent.prototype.addBreakpoint): + (devtools.DebuggerAgent.prototype.removeBreakpoint): + (devtools.DebuggerAgent.prototype.updateBreakpoint): + (devtools.DebuggerAgent.prototype.stepIntoStatement): + (devtools.DebuggerAgent.prototype.stepOutOfFunction): + (devtools.DebuggerAgent.prototype.stepOverStatement): + (devtools.DebuggerAgent.prototype.resumeExecution): + (devtools.DebuggerAgent.prototype.createExceptionMessage_): + (devtools.DebuggerAgent.prototype.showPendingExceptionMessage_): + (devtools.DebuggerAgent.prototype.clearExceptionMessage_): + (devtools.DebuggerAgent.prototype.pauseOnExceptions): + (devtools.DebuggerAgent.prototype.setPauseOnExceptions): + (devtools.DebuggerAgent.prototype.requestEvaluate): + (devtools.DebuggerAgent.prototype.resolveChildren): + (devtools.DebuggerAgent.prototype.resolveScope.this.requestSeqToCallback_.cmd.getSequenceNumber): + (devtools.DebuggerAgent.prototype.resolveScope): + (devtools.DebuggerAgent.prototype.resolveFrameVariables_.scopeResponseHandler): + (devtools.DebuggerAgent.prototype.resolveFrameVariables_): + (devtools.DebuggerAgent.prototype.resolveCompletionsOnFrame): + (devtools.DebuggerAgent.prototype.getScriptContextType): + (devtools.DebuggerAgent.prototype.requestClearBreakpoint_): + (devtools.DebuggerAgent.prototype.requestChangeBreakpoint_): + (devtools.DebuggerAgent.prototype.requestBacktrace_): + (devtools.DebuggerAgent.sendCommand_): + (devtools.DebuggerAgent.prototype.stepCommand_): + (devtools.DebuggerAgent.prototype.requestLookup_): + (devtools.DebuggerAgent.prototype.setContextId_.this.requestSeqToCallback_.cmd.getSequenceNumber): + (devtools.DebuggerAgent.prototype.setContextId_): + (devtools.DebuggerAgent.prototype.handleDebuggerOutput_): + (devtools.DebuggerAgent.prototype.handleBreakEvent_): + (devtools.DebuggerAgent.prototype.handleExceptionEvent_): + (devtools.DebuggerAgent.prototype.handleScriptsResponse_): + (devtools.DebuggerAgent.prototype.isScriptFromInspectedContext_): + (devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_): + (devtools.DebuggerAgent.prototype.handleAfterCompileEvent_): + (devtools.DebuggerAgent.prototype.addScriptInfo_): + (devtools.DebuggerAgent.prototype.handleClearBreakpointResponse_): + (devtools.DebuggerAgent.prototype.handleBacktraceResponse_): + (devtools.DebuggerAgent.prototype.doHandleBacktraceResponse_): + (devtools.DebuggerAgent.prototype.evaluateInCallFrame): + (devtools.DebuggerAgent.prototype.invokeCallbackForResponse_): + (devtools.DebuggerAgent.prototype.formatCallFrame_): + (devtools.DebuggerAgent.formatObjectProperties_): + (devtools.DebuggerAgent.propertiesToProxies_): + (devtools.DebuggerAgent.formatObjectProxy_): + (devtools.DebuggerAgent.webkitToV8LineNumber_): + (devtools.DebuggerAgent.v8ToWwebkitLineNumber_): + (devtools.ScriptInfo): + (devtools.ScriptInfo.prototype.getLineOffset): + (devtools.ScriptInfo.prototype.getContextType): + (devtools.ScriptInfo.prototype.getUrl): + (devtools.ScriptInfo.prototype.isUnresolved): + (devtools.ScriptInfo.prototype.getBreakpointInfo): + (devtools.ScriptInfo.prototype.addBreakpointInfo): + (devtools.ScriptInfo.prototype.removeBreakpointInfo): + (devtools.BreakpointInfo): + (devtools.BreakpointInfo.prototype.getLine): + (devtools.BreakpointInfo.prototype.getV8Id): + (devtools.BreakpointInfo.prototype.setV8Id): + (devtools.BreakpointInfo.prototype.markAsRemoved): + (devtools.BreakpointInfo.prototype.isRemoved): + (devtools.CallFrame): + (devtools.CallFrame.prototype.evaluate_): + (devtools.DebugCommand): + (devtools.DebugCommand.prototype.getSequenceNumber): + (devtools.DebugCommand.prototype.toJSONProtocol): + (devtools.DebuggerMessage): + (devtools.DebuggerMessage.prototype.getType): + (devtools.DebuggerMessage.prototype.getEvent): + (devtools.DebuggerMessage.prototype.getCommand): + (devtools.DebuggerMessage.prototype.getRequestSeq): + (devtools.DebuggerMessage.prototype.isRunning): + (devtools.DebuggerMessage.prototype.isSuccess): + (devtools.DebuggerMessage.prototype.getMessage): + (devtools.DebuggerMessage.prototype.getBody): + (devtools.DebuggerMessage.prototype.lookup): + * src/js/DevTools.js: Added. + (devtools.dispatch): + (devtools.ToolsAgent): + (devtools.ToolsAgent.prototype.reset): + (devtools.ToolsAgent.prototype.evaluateJavaScript): + (devtools.ToolsAgent.prototype.getDebuggerAgent): + (devtools.ToolsAgent.prototype.getProfilerAgent): + (devtools.ToolsAgent.prototype.frameNavigate_): + (devtools.ToolsAgent.prototype.dispatchOnClient_): + (devtools.ToolsAgent.prototype.evaluate): + (WebInspector.setResourcesPanelEnabled): + (debugPrint): + (devtools): + (WebInspector.loaded): + (): + (WebInspector.ScriptView.prototype.setupSourceFrameIfNeeded): + (WebInspector.ScriptView.prototype.didResolveScriptSource_): + (WebInspector.UnresolvedPropertyValue): + (WebInspector.UIString): + (WebInspector.resourceTrackingWasEnabled): + (WebInspector.resourceTrackingWasDisabled): + (WebInspector.TestController.prototype.runAfterPendingDispatches): + (WebInspector.queuesAreEmpty): + (WebInspector.pausedScript): + * src/js/DevToolsHostStub.js: Added. + (.RemoteDebuggerAgentStub): + (.RemoteDebuggerAgentStub.prototype.getContextId): + (.RemoteProfilerAgentStub): + (.RemoteProfilerAgentStub.prototype.getActiveProfilerModules): + (.RemoteProfilerAgentStub.prototype.getLogLines): + (.RemoteToolsAgentStub): + (.RemoteToolsAgentStub.prototype.dispatchOnInjectedScript): + (.RemoteToolsAgentStub.prototype.dispatchOnInspectorController): + (.RemoteToolsAgentStub.prototype.executeVoidJavaScript): + (.ProfilerStubHelper): + (.ProfilerStubHelper.GetInstance): + (.ProfilerStubHelper.prototype.StopProfiling): + (.ProfilerStubHelper.prototype.StartProfiling): + (.ProfilerStubHelper.prototype.getActiveProfilerModules): + (.ProfilerStubHelper.prototype.getLogLines): + (.RemoteDebuggerCommandExecutorStub): + (.RemoteDebuggerCommandExecutorStub.prototype.DebuggerCommand): + (.RemoteDebuggerCommandExecutorStub.prototype.DebuggerPauseScript): + (.RemoteDebuggerCommandExecutorStub.prototype.sendResponse_): + (.DevToolsHostStub): + (.DevToolsHostStub.prototype.reset): + (.DevToolsHostStub.prototype.setting): + (.DevToolsHostStub.prototype.setSetting): + * src/js/HeapProfilerPanel.js: Added. + (WebInspector.ProfilesPanel.prototype.addSnapshot): + (WebInspector.HeapSnapshotView): + (WebInspector.HeapSnapshotView.prototype.get statusBarItems): + (WebInspector.HeapSnapshotView.prototype.get profile): + (WebInspector.HeapSnapshotView.prototype.set profile): + (WebInspector.HeapSnapshotView.prototype.show): + (WebInspector.HeapSnapshotView.prototype.hide): + (WebInspector.HeapSnapshotView.prototype.resize): + (WebInspector.HeapSnapshotView.prototype.refresh): + (WebInspector.HeapSnapshotView.prototype.refreshShowAsPercents): + (WebInspector.HeapSnapshotView.prototype._deleteSearchMatchedFlags): + (WebInspector.HeapSnapshotView.prototype.searchCanceled): + (WebInspector.HeapSnapshotView.prototype.performSearch): + (WebInspector.HeapSnapshotView.prototype.jumpToFirstSearchResult.WebInspector.CPUProfileView.prototype.jumpToFirstSearchResult.jumpToLastSearchResult.WebInspector.CPUProfileView.prototype.jumpToLastSearchResult.jumpToNextSearchResult.WebInspector.CPUProfileView.prototype.jumpToNextSearchResult.jumpToPreviousSearchResult.WebInspector.CPUProfileView.prototype.jumpToPreviousSearchResult.showingFirstSearchResult.WebInspector.CPUProfileView.prototype.showingFirstSearchResult.showingLastSearchResult.WebInspector.CPUProfileView.prototype.showingLastSearchResult._jumpToSearchResult.WebInspector.CPUProfileView.prototype._jumpToSearchResult.refreshVisibleData): + (WebInspector.HeapSnapshotView.prototype._changeBase): + (WebInspector.HeapSnapshotView.prototype._createSnapshotDataGridList): + (WebInspector.HeapSnapshotView.prototype._mouseDownInDataGrid): + (WebInspector.HeapSnapshotView.prototype.get _isShowingAsPercent): + (WebInspector.HeapSnapshotView.prototype._percentClicked): + (WebInspector.HeapSnapshotView.prototype._resetDataGridList): + (WebInspector.HeapSnapshotView.prototype._sortData): + (WebInspector.HeapSnapshotView.prototype._updateBaseOptions): + (WebInspector.HeapSnapshotView.prototype._updatePercentButton): + (WebInspector.HeapSnapshotView.prototype._updateSummaryGraph): + (WebInspector.HeapSnapshotView.SearchHelper.operations.LESS): + (WebInspector.HeapSnapshotView.SearchHelper.operations.LESS_OR_EQUAL): + (WebInspector.HeapSnapshotView.SearchHelper.operations.EQUAL): + (WebInspector.HeapSnapshotView.SearchHelper.operations.GREATER_OR_EQUAL): + (WebInspector.HeapSnapshotView.SearchHelper.operations.GREATER): + (WebInspector.HeapSnapshotView.SearchHelper.parseOperationAndNumber): + (WebInspector.HeapSummaryCalculator): + (WebInspector.HeapSummaryCalculator.prototype.computeSummaryValues): + (WebInspector.HeapSummaryCalculator.prototype.formatValue): + (WebInspector.HeapSummaryCalculator.prototype.get showAsPercent): + (WebInspector.HeapSummaryCalculator.prototype.set showAsPercent): + (WebInspector.HeapSummaryCountCalculator): + (WebInspector.HeapSummaryCountCalculator.prototype._highFromLow): + (WebInspector.HeapSummaryCountCalculator.prototype._valueToString): + (WebInspector.HeapSummarySizeCalculator): + (WebInspector.HeapSummarySizeCalculator.prototype._highFromLow): + (WebInspector.HeapSnapshotSidebarTreeElement): + (WebInspector.HeapSnapshotSidebarTreeElement.prototype.get mainTitle): + (WebInspector.HeapSnapshotSidebarTreeElement.prototype.set mainTitle): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get _hasRetainers): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get _parent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype._populate.if): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype._populate): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.produceDiff): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.sort): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.signForDelta): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.showDeltaAsPercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalCount): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalSize): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get countPercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get sizePercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get countDeltaPercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get sizeDeltaPercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get data): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.createCell): + (WebInspector.HeapSnapshotDataGridNode): + (WebInspector.HeapSnapshotDataGridList): + (WebInspector.HeapSnapshotDataGridList.prototype.appendChild): + (WebInspector.HeapSnapshotDataGridList.prototype.insertChild): + (WebInspector.HeapSnapshotDataGridList.prototype.removeChildren): + (WebInspector.HeapSnapshotDataGridList.prototype.populateChildren): + (WebInspector.HeapSnapshotDataGridList.propertyComparator.comparator): + (WebInspector.HeapSnapshotDataGridList.propertyComparator): + (WebInspector.HeapSnapshotDataGridRetainerNode): + (WebInspector.HeapSnapshotDataGridRetainerNode.prototype.get sizePercent): + (WebInspector.HeapSnapshotDataGridRetainerNode.prototype.get sizeDeltaPercent): + (WebInspector.HeapSnapshotDataGridRetainerNode.prototype._calculateRetainers): + (WebInspector.HeapSnapshotProfileType): + (WebInspector.HeapSnapshotProfileType.prototype.get buttonTooltip): + (WebInspector.HeapSnapshotProfileType.prototype.get buttonStyle): + (WebInspector.HeapSnapshotProfileType.prototype.buttonClicked): + (WebInspector.HeapSnapshotProfileType.prototype.get welcomeMessage): + (WebInspector.HeapSnapshotProfileType.prototype.createSidebarTreeElementForProfile): + (WebInspector.HeapSnapshotProfileType.prototype.createView): + (): + * src/js/InjectDispatch.js: Added. + (InspectorControllerDispatcher.dispatch): + (ApuAgentDispatcher.dispatchToApu): + (dispatch): + (devtools): + * src/js/InspectorControllerImpl.js: Added. + (devtools.InspectorBackendImpl): + (devtools.InspectorBackendImpl.prototype.toggleNodeSearch): + (devtools.InspectorBackendImpl.prototype.debuggerEnabled): + (devtools.InspectorBackendImpl.prototype.profilerEnabled): + (devtools.InspectorBackendImpl.prototype.addBreakpoint): + (devtools.InspectorBackendImpl.prototype.removeBreakpoint): + (devtools.InspectorBackendImpl.prototype.updateBreakpoint): + (devtools.InspectorBackendImpl.prototype.pauseInDebugger): + (devtools.InspectorBackendImpl.prototype.resumeDebugger): + (devtools.InspectorBackendImpl.prototype.stepIntoStatementInDebugger): + (devtools.InspectorBackendImpl.prototype.stepOutOfFunctionInDebugger): + (devtools.InspectorBackendImpl.prototype.stepOverStatementInDebugger): + (devtools.InspectorBackendImpl.prototype.setPauseOnExceptionsState): + (devtools.InspectorBackendImpl.prototype.pauseOnExceptionsState): + (devtools.InspectorBackendImpl.prototype.pauseOnExceptions): + (devtools.InspectorBackendImpl.prototype.setPauseOnExceptions): + (devtools.InspectorBackendImpl.prototype.startProfiling): + (devtools.InspectorBackendImpl.prototype.stopProfiling): + (devtools.InspectorBackendImpl.prototype.getProfileHeaders): + (devtools.InspectorBackendImpl.prototype.addFullProfile): + (devtools.InspectorBackendImpl.prototype.getProfile): + (devtools.InspectorBackendImpl.prototype.takeHeapSnapshot): + (devtools.InspectorBackendImpl.prototype.dispatchOnInjectedScript): + (devtools.InspectorBackendImpl.prototype.installInspectorControllerDelegate_): + (devtools.InspectorBackendImpl.prototype.callInspectorController_): + * src/js/ProfilerAgent.js: Added. + (devtools.ProfilerAgent): + (devtools.ProfilerAgent.prototype.setupProfilerProcessorCallbacks): + (devtools.ProfilerAgent.prototype.initializeProfiling): + (devtools.ProfilerAgent.prototype.startProfiling): + (devtools.ProfilerAgent.prototype.stopProfiling): + (devtools.ProfilerAgent.prototype.didGetActiveProfilerModules_): + (devtools.ProfilerAgent.prototype.didGetLogLines_): + * src/js/ProfilerProcessor.js: Added. + (devtools.profiler.WebKitViewBuilder): + (devtools.profiler.WebKitViewBuilder.prototype.createViewNode): + (devtools.profiler.WebKitViewNode): + (set get devtools.profiler.WebKitViewNode.prototype.initFuncInfo_): + (devtools.profiler.JsProfile): + (devtools.profiler.JsProfile.prototype.skipThisFunction): + (devtools.profiler.Processor): + (devtools.profiler.Processor.prototype.printError): + (devtools.profiler.Processor.prototype.skipDispatch): + (devtools.profiler.Processor.prototype.setCallbacks): + (devtools.profiler.Processor.prototype.setNewProfileCallback): + (devtools.profiler.Processor.prototype.processProfiler_.switch.break): + (devtools.profiler.Processor.prototype.processProfiler_): + (devtools.profiler.Processor.prototype.processCodeCreation_): + (devtools.profiler.Processor.prototype.processCodeMove_): + (devtools.profiler.Processor.prototype.processCodeDelete_): + (devtools.profiler.Processor.prototype.processFunctionCreation_): + (devtools.profiler.Processor.prototype.processFunctionMove_): + (devtools.profiler.Processor.prototype.processFunctionDelete_): + (devtools.profiler.Processor.prototype.processTick_): + (devtools.profiler.Processor.prototype.processTickV2_): + (devtools.profiler.Processor.prototype.processHeapSampleBegin_): + (devtools.profiler.Processor.prototype.processHeapSampleStats_): + (devtools.profiler.Processor.prototype.processHeapSampleItem_): + (devtools.profiler.Processor.prototype.processHeapJsConsItem_): + (devtools.profiler.Processor.prototype.processHeapJsRetItem_.mergeRetainers): + (devtools.profiler.Processor.prototype.processHeapJsRetItem_): + (devtools.profiler.Processor.prototype.processHeapSampleEnd_): + (devtools.profiler.Processor.prototype.createProfileForView): + * src/js/Tests.js: Added. + (.TestSuite): + (.TestSuite.prototype.fail): + (.TestSuite.prototype.assertEquals): + (.TestSuite.prototype.assertTrue): + (.TestSuite.prototype.assertContains): + (.TestSuite.prototype.takeControl): + (.TestSuite.prototype.releaseControl): + (.TestSuite.prototype.reportOk_): + (.TestSuite.prototype.reportFailure_): + (.TestSuite.prototype.runTest): + (.TestSuite.prototype.showPanel): + (.TestSuite.prototype.addSniffer.receiver.methodName): + (.TestSuite.prototype.addSniffer): + (.TestSuite.prototype.testHostIsPresent): + (.TestSuite.prototype.testElementsTreeRoot): + (.TestSuite.prototype.testMainResource): + (.TestSuite.prototype.testResourceContentLength.this.addSniffer.): + (.TestSuite.prototype.testResourceHeaders): + (.TestSuite.prototype.testCachedResourceMimeType.this.addSniffer.): + (.TestSuite.prototype.testCachedResourceMimeType): + (.TestSuite.prototype.testProfilerTab): + (.TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh.waitUntilScriptIsParsed): + (.TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh.checkScriptsPanel): + (.TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh): + (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.switchToElementsTab): + (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.switchToScriptsTab): + (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.checkScriptsPanel): + (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.checkNoDuplicates): + (.TestSuite.prototype.testPauseOnException): + (.TestSuite.prototype.testPauseWhenLoadingDevTools): + (.TestSuite.prototype.testPauseWhenScriptIsRunning.testScriptPauseAfterDelay): + (.TestSuite.prototype.testPauseWhenScriptIsRunning.testScriptPause): + (.TestSuite.prototype.testPauseWhenScriptIsRunning): + (.TestSuite.prototype.optionsToString_): + (.TestSuite.prototype.evaluateInConsole_): + (.TestSuite.prototype.waitForSetBreakpointResponse_): + (.TestSuite.prototype.testEvalOnCallFrame.setBreakpointCallback): + (.TestSuite.prototype.testEvalOnCallFrame.waitForBreakpointHit): + (.TestSuite.prototype.testCompletionOnPause): + (.TestSuite.prototype.testCompletionOnPause.testLocalsCompletion): + (.TestSuite.prototype.testCompletionOnPause.testThisCompletion): + (.TestSuite.prototype.testCompletionOnPause.testFieldCompletion): + (.TestSuite.prototype.testCompletionOnPause.checkCompletions): + (.TestSuite.prototype.testAutoContinueOnSyntaxError.checkScriptsList): + (.TestSuite.prototype.testAutoContinueOnSyntaxError.waitForExceptionEvent.test): + (.TestSuite.prototype.testAutoContinueOnSyntaxError.waitForExceptionEvent): + (.TestSuite.prototype._checkExecutionLine): + (.TestSuite.prototype._scriptsAreParsed): + (.TestSuite.prototype._waitForScriptPause): + (.TestSuite.prototype._checkSourceFrameWhenLoaded.checkExecLine): + (.TestSuite.prototype._checkSourceFrameWhenLoaded): + (.TestSuite.prototype._performSteps.doNextAction): + (.TestSuite.prototype._performSteps): + (.TestSuite.prototype._executeCodeWhenScriptsAreParsed.executeFunctionInInspectedPage): + (.TestSuite.prototype._waitUntilScriptsAreParsed.waitForAllScripts): + (.TestSuite.prototype._waitUntilScriptsAreParsed): + (.TestSuite.prototype._executeFunctionForStepTest): + (.TestSuite.prototype.testStepOver): + (.TestSuite.prototype.testStepOut): + (.TestSuite.prototype.testStepIn): + (.TestSuite.prototype._evaluateXpath): + (.TestSuite.prototype._findNode): + (.TestSuite.prototype._findText): + (.TestSuite.prototype._nodeIterator): + (.TestSuite.prototype._checkScopeSectionDiv): + (.TestSuite.prototype._expandScopeSections.updateListener): + (.TestSuite.prototype._expandScopeSections): + (.TestSuite.prototype.testExpandScope): + (.TestSuite.prototype.testExpandScope.examineScopes): + (.TestSuite.prototype._findChildProperty): + (.TestSuite.prototype._hookGetPropertiesCallback.accessor.getProperties): + (.TestSuite.prototype._hookGetPropertiesCallback.try): + (.TestSuite.prototype._hookGetPropertiesCallback): + (.TestSuite.prototype.testDebugIntrinsicProperties.expandLocalScope): + (.TestSuite.prototype.testDebugIntrinsicProperties): + (.TestSuite.prototype.testDebugIntrinsicProperties.expandAndCheckNextProperty): + (.TestSuite.prototype.testDebugIntrinsicProperties.checkProperty): + (.TestSuite.createKeyEvent): + (.TestSuite.prototype.testConsoleLog.assertNext): + (.TestSuite.prototype.testConsoleLog): + (.TestSuite.prototype.testEvalGlobal.initEval): + (.TestSuite.prototype.testEvalGlobal): + (.TestSuite.prototype.testShowStoragePanel.this.addSniffer.): + (.TestSuite.prototype.testShowStoragePanel.this.addSniffer): + (.uiTests.runAllTests): + (.uiTests.runTest): + +2010-02-09 Yury Semikhatsky <yurys@chromium.org> + + Reviewed by Pavel Feldman. + + Upstream JavaScript part of DevTools WebKit API implementation + + https://bugs.webkit.org/show_bug.cgi?id=34744 + + * WebKit.gypi: Added. + * src/js/DebuggerAgent.js: Added. + (devtools.DebuggerAgent): + (devtools.DebuggerAgent.prototype.reset): + (devtools.DebuggerAgent.prototype.initUI): + (devtools.DebuggerAgent.prototype.resolveScriptSource.this.requestSeqToCallback_.cmd.getSequenceNumber): + (devtools.DebuggerAgent.prototype.resolveScriptSource): + (devtools.DebuggerAgent.prototype.pauseExecution): + (devtools.DebuggerAgent.prototype.addBreakpoint): + (devtools.DebuggerAgent.prototype.removeBreakpoint): + (devtools.DebuggerAgent.prototype.updateBreakpoint): + (devtools.DebuggerAgent.prototype.stepIntoStatement): + (devtools.DebuggerAgent.prototype.stepOutOfFunction): + (devtools.DebuggerAgent.prototype.stepOverStatement): + (devtools.DebuggerAgent.prototype.resumeExecution): + (devtools.DebuggerAgent.prototype.createExceptionMessage_): + (devtools.DebuggerAgent.prototype.showPendingExceptionMessage_): + (devtools.DebuggerAgent.prototype.clearExceptionMessage_): + (devtools.DebuggerAgent.prototype.pauseOnExceptions): + (devtools.DebuggerAgent.prototype.setPauseOnExceptions): + (devtools.DebuggerAgent.prototype.requestEvaluate): + (devtools.DebuggerAgent.prototype.resolveChildren): + (devtools.DebuggerAgent.prototype.resolveScope.this.requestSeqToCallback_.cmd.getSequenceNumber): + (devtools.DebuggerAgent.prototype.resolveScope): + (devtools.DebuggerAgent.prototype.resolveFrameVariables_.scopeResponseHandler): + (devtools.DebuggerAgent.prototype.resolveFrameVariables_): + (devtools.DebuggerAgent.prototype.resolveCompletionsOnFrame): + (devtools.DebuggerAgent.prototype.getScriptContextType): + (devtools.DebuggerAgent.prototype.requestClearBreakpoint_): + (devtools.DebuggerAgent.prototype.requestChangeBreakpoint_): + (devtools.DebuggerAgent.prototype.requestBacktrace_): + (devtools.DebuggerAgent.sendCommand_): + (devtools.DebuggerAgent.prototype.stepCommand_): + (devtools.DebuggerAgent.prototype.requestLookup_): + (devtools.DebuggerAgent.prototype.setContextId_.this.requestSeqToCallback_.cmd.getSequenceNumber): + (devtools.DebuggerAgent.prototype.setContextId_): + (devtools.DebuggerAgent.prototype.handleDebuggerOutput_): + (devtools.DebuggerAgent.prototype.handleBreakEvent_): + (devtools.DebuggerAgent.prototype.handleExceptionEvent_): + (devtools.DebuggerAgent.prototype.handleScriptsResponse_): + (devtools.DebuggerAgent.prototype.isScriptFromInspectedContext_): + (devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_): + (devtools.DebuggerAgent.prototype.handleAfterCompileEvent_): + (devtools.DebuggerAgent.prototype.addScriptInfo_): + (devtools.DebuggerAgent.prototype.handleClearBreakpointResponse_): + (devtools.DebuggerAgent.prototype.handleBacktraceResponse_): + (devtools.DebuggerAgent.prototype.doHandleBacktraceResponse_): + (devtools.DebuggerAgent.prototype.evaluateInCallFrame): + (devtools.DebuggerAgent.prototype.invokeCallbackForResponse_): + (devtools.DebuggerAgent.prototype.formatCallFrame_): + (devtools.DebuggerAgent.formatObjectProperties_): + (devtools.DebuggerAgent.propertiesToProxies_): + (devtools.DebuggerAgent.formatObjectProxy_): + (devtools.DebuggerAgent.webkitToV8LineNumber_): + (devtools.DebuggerAgent.v8ToWwebkitLineNumber_): + (devtools.ScriptInfo): + (devtools.ScriptInfo.prototype.getLineOffset): + (devtools.ScriptInfo.prototype.getContextType): + (devtools.ScriptInfo.prototype.getUrl): + (devtools.ScriptInfo.prototype.isUnresolved): + (devtools.ScriptInfo.prototype.getBreakpointInfo): + (devtools.ScriptInfo.prototype.addBreakpointInfo): + (devtools.ScriptInfo.prototype.removeBreakpointInfo): + (devtools.BreakpointInfo): + (devtools.BreakpointInfo.prototype.getLine): + (devtools.BreakpointInfo.prototype.getV8Id): + (devtools.BreakpointInfo.prototype.setV8Id): + (devtools.BreakpointInfo.prototype.markAsRemoved): + (devtools.BreakpointInfo.prototype.isRemoved): + (devtools.CallFrame): + (devtools.CallFrame.prototype.evaluate_): + (devtools.DebugCommand): + (devtools.DebugCommand.prototype.getSequenceNumber): + (devtools.DebugCommand.prototype.toJSONProtocol): + (devtools.DebuggerMessage): + (devtools.DebuggerMessage.prototype.getType): + (devtools.DebuggerMessage.prototype.getEvent): + (devtools.DebuggerMessage.prototype.getCommand): + (devtools.DebuggerMessage.prototype.getRequestSeq): + (devtools.DebuggerMessage.prototype.isRunning): + (devtools.DebuggerMessage.prototype.isSuccess): + (devtools.DebuggerMessage.prototype.getMessage): + (devtools.DebuggerMessage.prototype.getBody): + (devtools.DebuggerMessage.prototype.lookup): + * src/js/DevTools.js: Added. + (devtools.dispatch): + (devtools.ToolsAgent): + (devtools.ToolsAgent.prototype.reset): + (devtools.ToolsAgent.prototype.evaluateJavaScript): + (devtools.ToolsAgent.prototype.getDebuggerAgent): + (devtools.ToolsAgent.prototype.getProfilerAgent): + (devtools.ToolsAgent.prototype.frameNavigate_): + (devtools.ToolsAgent.prototype.dispatchOnClient_): + (devtools.ToolsAgent.prototype.evaluate): + (WebInspector.setResourcesPanelEnabled): + (debugPrint): + (devtools): + (WebInspector.loaded): + (): + (WebInspector.ScriptView.prototype.setupSourceFrameIfNeeded): + (WebInspector.ScriptView.prototype.didResolveScriptSource_): + (WebInspector.UnresolvedPropertyValue): + (WebInspector.UIString): + (WebInspector.resourceTrackingWasEnabled): + (WebInspector.resourceTrackingWasDisabled): + (WebInspector.TestController.prototype.runAfterPendingDispatches): + (WebInspector.queuesAreEmpty): + (WebInspector.pausedScript): + * src/js/DevToolsHostStub.js: Added. + (.RemoteDebuggerAgentStub): + (.RemoteDebuggerAgentStub.prototype.getContextId): + (.RemoteProfilerAgentStub): + (.RemoteProfilerAgentStub.prototype.getActiveProfilerModules): + (.RemoteProfilerAgentStub.prototype.getLogLines): + (.RemoteToolsAgentStub): + (.RemoteToolsAgentStub.prototype.dispatchOnInjectedScript): + (.RemoteToolsAgentStub.prototype.dispatchOnInspectorController): + (.RemoteToolsAgentStub.prototype.executeVoidJavaScript): + (.ProfilerStubHelper): + (.ProfilerStubHelper.GetInstance): + (.ProfilerStubHelper.prototype.StopProfiling): + (.ProfilerStubHelper.prototype.StartProfiling): + (.ProfilerStubHelper.prototype.getActiveProfilerModules): + (.ProfilerStubHelper.prototype.getLogLines): + (.RemoteDebuggerCommandExecutorStub): + (.RemoteDebuggerCommandExecutorStub.prototype.DebuggerCommand): + (.RemoteDebuggerCommandExecutorStub.prototype.DebuggerPauseScript): + (.RemoteDebuggerCommandExecutorStub.prototype.sendResponse_): + (.DevToolsHostStub): + (.DevToolsHostStub.prototype.reset): + (.DevToolsHostStub.prototype.setting): + (.DevToolsHostStub.prototype.setSetting): + * src/js/HeapProfilerPanel.js: Added. + (WebInspector.ProfilesPanel.prototype.addSnapshot): + (WebInspector.HeapSnapshotView): + (WebInspector.HeapSnapshotView.prototype.get statusBarItems): + (WebInspector.HeapSnapshotView.prototype.get profile): + (WebInspector.HeapSnapshotView.prototype.set profile): + (WebInspector.HeapSnapshotView.prototype.show): + (WebInspector.HeapSnapshotView.prototype.hide): + (WebInspector.HeapSnapshotView.prototype.resize): + (WebInspector.HeapSnapshotView.prototype.refresh): + (WebInspector.HeapSnapshotView.prototype.refreshShowAsPercents): + (WebInspector.HeapSnapshotView.prototype._deleteSearchMatchedFlags): + (WebInspector.HeapSnapshotView.prototype.searchCanceled): + (WebInspector.HeapSnapshotView.prototype.performSearch): + (WebInspector.HeapSnapshotView.prototype.jumpToFirstSearchResult.WebInspector.CPUProfileView.prototype.jumpToFirstSearchResult.jumpToLastSearchResult.WebInspector.CPUProfileView.prototype.jumpToLastSearchResult.jumpToNextSearchResult.WebInspector.CPUProfileView.prototype.jumpToNextSearchResult.jumpToPreviousSearchResult.WebInspector.CPUProfileView.prototype.jumpToPreviousSearchResult.showingFirstSearchResult.WebInspector.CPUProfileView.prototype.showingFirstSearchResult.showingLastSearchResult.WebInspector.CPUProfileView.prototype.showingLastSearchResult._jumpToSearchResult.WebInspector.CPUProfileView.prototype._jumpToSearchResult.refreshVisibleData): + (WebInspector.HeapSnapshotView.prototype._changeBase): + (WebInspector.HeapSnapshotView.prototype._createSnapshotDataGridList): + (WebInspector.HeapSnapshotView.prototype._mouseDownInDataGrid): + (WebInspector.HeapSnapshotView.prototype.get _isShowingAsPercent): + (WebInspector.HeapSnapshotView.prototype._percentClicked): + (WebInspector.HeapSnapshotView.prototype._resetDataGridList): + (WebInspector.HeapSnapshotView.prototype._sortData): + (WebInspector.HeapSnapshotView.prototype._updateBaseOptions): + (WebInspector.HeapSnapshotView.prototype._updatePercentButton): + (WebInspector.HeapSnapshotView.prototype._updateSummaryGraph): + (WebInspector.HeapSnapshotView.SearchHelper.operations.LESS): + (WebInspector.HeapSnapshotView.SearchHelper.operations.LESS_OR_EQUAL): + (WebInspector.HeapSnapshotView.SearchHelper.operations.EQUAL): + (WebInspector.HeapSnapshotView.SearchHelper.operations.GREATER_OR_EQUAL): + (WebInspector.HeapSnapshotView.SearchHelper.operations.GREATER): + (WebInspector.HeapSnapshotView.SearchHelper.parseOperationAndNumber): + (WebInspector.HeapSummaryCalculator): + (WebInspector.HeapSummaryCalculator.prototype.computeSummaryValues): + (WebInspector.HeapSummaryCalculator.prototype.formatValue): + (WebInspector.HeapSummaryCalculator.prototype.get showAsPercent): + (WebInspector.HeapSummaryCalculator.prototype.set showAsPercent): + (WebInspector.HeapSummaryCountCalculator): + (WebInspector.HeapSummaryCountCalculator.prototype._highFromLow): + (WebInspector.HeapSummaryCountCalculator.prototype._valueToString): + (WebInspector.HeapSummarySizeCalculator): + (WebInspector.HeapSummarySizeCalculator.prototype._highFromLow): + (WebInspector.HeapSnapshotSidebarTreeElement): + (WebInspector.HeapSnapshotSidebarTreeElement.prototype.get mainTitle): + (WebInspector.HeapSnapshotSidebarTreeElement.prototype.set mainTitle): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get _hasRetainers): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get _parent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype._populate.if): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype._populate): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.produceDiff): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.sort): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.signForDelta): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.showDeltaAsPercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalCount): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalSize): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get countPercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get sizePercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get countDeltaPercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get sizeDeltaPercent): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.get data): + (WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.createCell): + (WebInspector.HeapSnapshotDataGridNode): + (WebInspector.HeapSnapshotDataGridList): + (WebInspector.HeapSnapshotDataGridList.prototype.appendChild): + (WebInspector.HeapSnapshotDataGridList.prototype.insertChild): + (WebInspector.HeapSnapshotDataGridList.prototype.removeChildren): + (WebInspector.HeapSnapshotDataGridList.prototype.populateChildren): + (WebInspector.HeapSnapshotDataGridList.propertyComparator.comparator): + (WebInspector.HeapSnapshotDataGridList.propertyComparator): + (WebInspector.HeapSnapshotDataGridRetainerNode): + (WebInspector.HeapSnapshotDataGridRetainerNode.prototype.get sizePercent): + (WebInspector.HeapSnapshotDataGridRetainerNode.prototype.get sizeDeltaPercent): + (WebInspector.HeapSnapshotDataGridRetainerNode.prototype._calculateRetainers): + (WebInspector.HeapSnapshotProfileType): + (WebInspector.HeapSnapshotProfileType.prototype.get buttonTooltip): + (WebInspector.HeapSnapshotProfileType.prototype.get buttonStyle): + (WebInspector.HeapSnapshotProfileType.prototype.buttonClicked): + (WebInspector.HeapSnapshotProfileType.prototype.get welcomeMessage): + (WebInspector.HeapSnapshotProfileType.prototype.createSidebarTreeElementForProfile): + (WebInspector.HeapSnapshotProfileType.prototype.createView): + (): + * src/js/InjectDispatch.js: Added. + (InspectorControllerDispatcher.dispatch): + (ApuAgentDispatcher.dispatchToApu): + (dispatch): + (devtools): + * src/js/InspectorControllerImpl.js: Added. + (devtools.InspectorBackendImpl): + (devtools.InspectorBackendImpl.prototype.toggleNodeSearch): + (devtools.InspectorBackendImpl.prototype.debuggerEnabled): + (devtools.InspectorBackendImpl.prototype.profilerEnabled): + (devtools.InspectorBackendImpl.prototype.addBreakpoint): + (devtools.InspectorBackendImpl.prototype.removeBreakpoint): + (devtools.InspectorBackendImpl.prototype.updateBreakpoint): + (devtools.InspectorBackendImpl.prototype.pauseInDebugger): + (devtools.InspectorBackendImpl.prototype.resumeDebugger): + (devtools.InspectorBackendImpl.prototype.stepIntoStatementInDebugger): + (devtools.InspectorBackendImpl.prototype.stepOutOfFunctionInDebugger): + (devtools.InspectorBackendImpl.prototype.stepOverStatementInDebugger): + (devtools.InspectorBackendImpl.prototype.setPauseOnExceptionsState): + (devtools.InspectorBackendImpl.prototype.pauseOnExceptionsState): + (devtools.InspectorBackendImpl.prototype.pauseOnExceptions): + (devtools.InspectorBackendImpl.prototype.setPauseOnExceptions): + (devtools.InspectorBackendImpl.prototype.startProfiling): + (devtools.InspectorBackendImpl.prototype.stopProfiling): + (devtools.InspectorBackendImpl.prototype.getProfileHeaders): + (devtools.InspectorBackendImpl.prototype.addFullProfile): + (devtools.InspectorBackendImpl.prototype.getProfile): + (devtools.InspectorBackendImpl.prototype.takeHeapSnapshot): + (devtools.InspectorBackendImpl.prototype.dispatchOnInjectedScript): + (devtools.InspectorBackendImpl.prototype.installInspectorControllerDelegate_): + (devtools.InspectorBackendImpl.prototype.callInspectorController_): + * src/js/ProfilerAgent.js: Added. + (devtools.ProfilerAgent): + (devtools.ProfilerAgent.prototype.setupProfilerProcessorCallbacks): + (devtools.ProfilerAgent.prototype.initializeProfiling): + (devtools.ProfilerAgent.prototype.startProfiling): + (devtools.ProfilerAgent.prototype.stopProfiling): + (devtools.ProfilerAgent.prototype.didGetActiveProfilerModules_): + (devtools.ProfilerAgent.prototype.didGetLogLines_): + * src/js/ProfilerProcessor.js: Added. + (devtools.profiler.WebKitViewBuilder): + (devtools.profiler.WebKitViewBuilder.prototype.createViewNode): + (devtools.profiler.WebKitViewNode): + (set get devtools.profiler.WebKitViewNode.prototype.initFuncInfo_): + (devtools.profiler.JsProfile): + (devtools.profiler.JsProfile.prototype.skipThisFunction): + (devtools.profiler.Processor): + (devtools.profiler.Processor.prototype.printError): + (devtools.profiler.Processor.prototype.skipDispatch): + (devtools.profiler.Processor.prototype.setCallbacks): + (devtools.profiler.Processor.prototype.setNewProfileCallback): + (devtools.profiler.Processor.prototype.processProfiler_.switch.break): + (devtools.profiler.Processor.prototype.processProfiler_): + (devtools.profiler.Processor.prototype.processCodeCreation_): + (devtools.profiler.Processor.prototype.processCodeMove_): + (devtools.profiler.Processor.prototype.processCodeDelete_): + (devtools.profiler.Processor.prototype.processFunctionCreation_): + (devtools.profiler.Processor.prototype.processFunctionMove_): + (devtools.profiler.Processor.prototype.processFunctionDelete_): + (devtools.profiler.Processor.prototype.processTick_): + (devtools.profiler.Processor.prototype.processTickV2_): + (devtools.profiler.Processor.prototype.processHeapSampleBegin_): + (devtools.profiler.Processor.prototype.processHeapSampleStats_): + (devtools.profiler.Processor.prototype.processHeapSampleItem_): + (devtools.profiler.Processor.prototype.processHeapJsConsItem_): + (devtools.profiler.Processor.prototype.processHeapJsRetItem_.mergeRetainers): + (devtools.profiler.Processor.prototype.processHeapJsRetItem_): + (devtools.profiler.Processor.prototype.processHeapSampleEnd_): + (devtools.profiler.Processor.prototype.createProfileForView): + * src/js/Tests.js: Added. + (.TestSuite): + (.TestSuite.prototype.fail): + (.TestSuite.prototype.assertEquals): + (.TestSuite.prototype.assertTrue): + (.TestSuite.prototype.assertContains): + (.TestSuite.prototype.takeControl): + (.TestSuite.prototype.releaseControl): + (.TestSuite.prototype.reportOk_): + (.TestSuite.prototype.reportFailure_): + (.TestSuite.prototype.runTest): + (.TestSuite.prototype.showPanel): + (.TestSuite.prototype.addSniffer.receiver.methodName): + (.TestSuite.prototype.addSniffer): + (.TestSuite.prototype.testHostIsPresent): + (.TestSuite.prototype.testElementsTreeRoot): + (.TestSuite.prototype.testMainResource): + (.TestSuite.prototype.testResourceContentLength.this.addSniffer.): + (.TestSuite.prototype.testResourceHeaders): + (.TestSuite.prototype.testCachedResourceMimeType.this.addSniffer.): + (.TestSuite.prototype.testCachedResourceMimeType): + (.TestSuite.prototype.testProfilerTab): + (.TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh.waitUntilScriptIsParsed): + (.TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh.checkScriptsPanel): + (.TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh): + (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.switchToElementsTab): + (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.switchToScriptsTab): + (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.checkScriptsPanel): + (.TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch.checkNoDuplicates): + (.TestSuite.prototype.testPauseOnException): + (.TestSuite.prototype.testPauseWhenLoadingDevTools): + (.TestSuite.prototype.testPauseWhenScriptIsRunning.testScriptPauseAfterDelay): + (.TestSuite.prototype.testPauseWhenScriptIsRunning.testScriptPause): + (.TestSuite.prototype.testPauseWhenScriptIsRunning): + (.TestSuite.prototype.optionsToString_): + (.TestSuite.prototype.evaluateInConsole_): + (.TestSuite.prototype.waitForSetBreakpointResponse_): + (.TestSuite.prototype.testEvalOnCallFrame.setBreakpointCallback): + (.TestSuite.prototype.testEvalOnCallFrame.waitForBreakpointHit): + (.TestSuite.prototype.testCompletionOnPause): + (.TestSuite.prototype.testCompletionOnPause.testLocalsCompletion): + (.TestSuite.prototype.testCompletionOnPause.testThisCompletion): + (.TestSuite.prototype.testCompletionOnPause.testFieldCompletion): + (.TestSuite.prototype.testCompletionOnPause.checkCompletions): + (.TestSuite.prototype.testAutoContinueOnSyntaxError.checkScriptsList): + (.TestSuite.prototype.testAutoContinueOnSyntaxError.waitForExceptionEvent.test): + (.TestSuite.prototype.testAutoContinueOnSyntaxError.waitForExceptionEvent): + (.TestSuite.prototype._checkExecutionLine): + (.TestSuite.prototype._scriptsAreParsed): + (.TestSuite.prototype._waitForScriptPause): + (.TestSuite.prototype._checkSourceFrameWhenLoaded.checkExecLine): + (.TestSuite.prototype._checkSourceFrameWhenLoaded): + (.TestSuite.prototype._performSteps.doNextAction): + (.TestSuite.prototype._performSteps): + (.TestSuite.prototype._executeCodeWhenScriptsAreParsed.executeFunctionInInspectedPage): + (.TestSuite.prototype._waitUntilScriptsAreParsed.waitForAllScripts): + (.TestSuite.prototype._waitUntilScriptsAreParsed): + (.TestSuite.prototype._executeFunctionForStepTest): + (.TestSuite.prototype.testStepOver): + (.TestSuite.prototype.testStepOut): + (.TestSuite.prototype.testStepIn): + (.TestSuite.prototype._evaluateXpath): + (.TestSuite.prototype._findNode): + (.TestSuite.prototype._findText): + (.TestSuite.prototype._nodeIterator): + (.TestSuite.prototype._checkScopeSectionDiv): + (.TestSuite.prototype._expandScopeSections.updateListener): + (.TestSuite.prototype._expandScopeSections): + (.TestSuite.prototype.testExpandScope): + (.TestSuite.prototype.testExpandScope.examineScopes): + (.TestSuite.prototype._findChildProperty): + (.TestSuite.prototype._hookGetPropertiesCallback.accessor.getProperties): + (.TestSuite.prototype._hookGetPropertiesCallback.try): + (.TestSuite.prototype._hookGetPropertiesCallback): + (.TestSuite.prototype.testDebugIntrinsicProperties.expandLocalScope): + (.TestSuite.prototype.testDebugIntrinsicProperties): + (.TestSuite.prototype.testDebugIntrinsicProperties.expandAndCheckNextProperty): + (.TestSuite.prototype.testDebugIntrinsicProperties.checkProperty): + (.TestSuite.createKeyEvent): + (.TestSuite.prototype.testConsoleLog.assertNext): + (.TestSuite.prototype.testConsoleLog): + (.TestSuite.prototype.testEvalGlobal.initEval): + (.TestSuite.prototype.testEvalGlobal): + (.TestSuite.prototype.testShowStoragePanel.this.addSniffer.): + (.TestSuite.prototype.testShowStoragePanel.this.addSniffer): + (.uiTests.runAllTests): + (.uiTests.runTest): + +2010-02-09 Avi Drissman <avi@chromium.org> + + Reviewed by David Levin. + + Chromium Mac: Control-A shouldn't select all/Control-C shouldn't copy + https://bugs.webkit.org/show_bug.cgi?id=34615 + + * src/WebViewImpl.cpp: + (WebKit::WebViewImpl::keyEventDefault): + +2010-02-08 Evan Martin <evan@chromium.org> + + dlopen() knows how to search the library search path, so just rely on + it. While I'm at it, print out the dlerror() error message on failure. + + [chromium] webgl shouldn't hard code library search path + https://bugs.webkit.org/show_bug.cgi?id=34659 + + * src/GraphicsContext3D.cpp: + (WebCore::GraphicsContext3DInternal::GLConnection::GLConnection): + (WebCore::GraphicsContext3DInternal::GLConnection::create): + +2010-02-08 Charlie Reis <creis@chromium.org> + + Reviewed by Darin Adler. + + onbeforeunload not called at window close + frame or iframe focused + https://bugs.webkit.org/show_bug.cgi?id=27481 + http://code.google.com/p/chromium/issues/detail?id=32615 + http://code.google.com/p/chromium/issues/detail?id=17157 + + Chromium and WebKit on Windows will now fire beforeunload handlers + even if an inner frame is focused. + + Layout tests aren't able to test this bug, since it requires closing + the actual browser window, not calling window.close(). Instead, + test with WebCore/manual-tests/onbeforeunload-focused-iframe.html. + + * src/WebViewImpl.cpp: + (WebKit::WebViewImpl::dispatchBeforeUnloadEvent): + +2010-02-08 Pavel Feldman <pfeldman@chromium.org> + + Reviewed by David Levin. + + WebKit/chromium: Custom context menu does not work in inspector. + https://bugs.webkit.org/show_bug.cgi?id=34711 + + * src/WebDevToolsFrontendImpl.cpp: + (WebKit::WebDevToolsFrontendImpl::jsShowContextMenu): + +2010-02-08 Nate Chapin <japhet@chromium.org> + + Reviewed by Darin Fisher. + + Check that the index passed into BackForwardListClientImpl::itemAtIndex() + is valid, and return null if it isn't. + + https://bugs.webkit.org/show_bug.cgi?id=34722 + + * src/BackForwardListClientImpl.cpp: + (WebKit::BackForwardListClientImpl::itemAtIndex): + +2010-02-05 Dumitru Daniliuc <dumi@chromium.org> + + Reviewed by Jeremy Orlow. + + Adding a way to close all database handles pointing to a certain + database as soon as possible. + https://bugs.webkit.org/show_bug.cgi?id=34619 + + * public/WebDatabase.h: + * src/WebDatabase.cpp: + (WebKit::WebDatabase::closeDatabaseImmediately): + +2010-02-08 Dirk Schulze <krit@webkit.org> + + Reviewed by Nikolas Zimmermann. + + Add back an AffineTransform class for use by SVG + https://bugs.webkit.org/show_bug.cgi?id=33750 + + Use AffineTransform instead of TransformationMatrix here. + + * tests/TransparencyWinTest.cpp: + (WebCore::TEST): + +2010-02-07 Jian Li <jianli@chromium.org> + + Reviewed by Darin Fisher. + + [chromium] Change chromium interface to handle DownloadURL format. + https://bugs.webkit.org/show_bug.cgi?id=34655 + + * public/WebDragData.h: + * src/WebDragData.cpp: + (WebKit::WebDragData::downloadMetadata): + (WebKit::WebDragData::setDownloadMetadata): + +2010-02-06 Dimitri Glazkov <dglazkov@chromium.org> + + No review, rolling out r54364. + http://trac.webkit.org/changeset/54364 + https://bugs.webkit.org/show_bug.cgi?id=34464 + + Introduced asserts in layout tests, needs more testing + locally. + + * public/WebViewClient.h: + * src/ChromeClientImpl.cpp: + * src/ChromeClientImpl.h: + +2010-02-05 James Hawkins <jhawkins@chromium.org> + + Reviewed by David Levin. + + [Chromium] Rename autocomplete* to suggestions* to prepare for the + refactoring of AutocompletePopupMenuClient. + + https://bugs.webkit.org/show_bug.cgi?id=34664 + + * public/WebView.h: + * src/AutocompletePopupMenuClient.cpp: + (WebKit::AutocompletePopupMenuClient::popupDidHide): + * src/EditorClientImpl.cpp: + (WebKit::EditorClientImpl::textFieldDidEndEditing): + (WebKit::EditorClientImpl::doAutofill): + * src/WebViewImpl.cpp: + (WebKit::): + (WebKit::WebViewImpl::WebViewImpl): + (WebKit::WebViewImpl::mouseDown): + (WebKit::WebViewImpl::autocompleteHandleKeyEvent): + (WebKit::WebViewImpl::setFocus): + (WebKit::WebViewImpl::applyAutofillSuggestions): + (WebKit::WebViewImpl::hideAutofillPopup): + (WebKit::WebViewImpl::hideSuggestionsPopup): + (WebKit::WebViewImpl::refreshSuggestionsPopup): + * src/WebViewImpl.h: + (WebKit::WebViewImpl::suggestionsPopupDidHide): + +2010-02-05 James Hawkins <jhawkins@chromium.org> + + Reviewed by David Levin. + + [Chromium] Remove an unused forward declaration in WebKitClient.h. + + https://bugs.webkit.org/show_bug.cgi?id=34622 + + * public/WebKitClient.h: + +2010-02-05 James Hawkins <jhawkins@chromium.org> + + Reviewed by Darin Fisher. + + Implement WebInputElement::isActivatedSubmit(). + + https://bugs.webkit.org/show_bug.cgi?id=34623 + + * public/WebInputElement.h: + * src/WebInputElement.cpp: + (WebKit::WebInputElement::isActivatedSubmit): + +2010-02-05 Nate Chapin <japhet@chromium.org> + + Reviewed by Dimitri Glazkov. + + Update code for getting a v8::FunctionTemplate. + + https://bugs.webkit.org/show_bug.cgi?id=34606 + + * src/WebDevToolsAgentImpl.cpp: + (WebKit::WebDevToolsAgentImpl::createInspectorBackendV8Wrapper): + +2010-02-05 Mikhail Naganov <mnaganov@chromium.org> + + Reviewed by Pavel Feldman. + + Enable JAVASCRIPT_DEBUGGER in chromium port. + + https://bugs.webkit.org/show_bug.cgi?id=34638 + + * features.gypi: + +2010-02-04 Yaar Schnitman <yaar@chromium.org> + + Reviewed by Darin Fisher. + + Upstreaming gtests from chromium: UniscribeHelper and TransparencyWin + https://bugs.webkit.org/show_bug.cgi?id=34509 + + Resubmit: The previous commit (r54333) was rolled back. + + * WebKit.gyp: + * tests/TransparencyWinTest.cpp: Added. + (WebCore::RECTToFloatRect): + (WebCore::drawNativeRect): + (WebCore::getPixelAt): + (WebCore::clearTopLayerAlphaChannel): + (WebCore::clearTopLayerAlphaPixel): + (WebCore::operator<<): + (WebCore::TEST): + * tests/UniscribeHelperTest.cpp: Added. + (WebCore::UniscribeTest::UniscribeTest): + (WebCore::UniscribeTest::MakeFont): + (WebCore::UniscribeTest::SetUp): + (WebCore::UniscribeTest::TearDown): + (TEST_F): + +2010-02-04 Drew Wilson <atwilson@chromium.org> + + Reviewed by David Levin. + + WorkerContext.close() does not work in the chromium port + https://bugs.webkit.org/show_bug.cgi?id=34551 + + Test: Adding new downstream test. + + * src/WebWorkerBase.cpp: + (WebKit::WebWorkerBase::workerContextClosedTask): + Now shuts down the worker thread when WorkerContext::close() is invoked. + +2010-02-04 Chris Guillory <chris.guillory@google.com> + + Reviewed by Darin Fisher. + + [Chromium] Add function for AccessibilityObject state change notifications. + + https://bugs.webkit.org/show_bug.cgi?id=34464 + + * public/WebViewClient.h: + (WebKit::WebViewClient::didChangeAccessibilityObjectState): + * src/ChromeClientImpl.cpp: + (WebKit::ChromeClientImpl::didChangeAccessibilityObjectState): + * src/ChromeClientImpl.h: + +2010-02-04 Jeremy Moskovich <jeremy@chromium.org> + + Reviewed by Darin Fisher. + + Update comments to better document the possible values of the + writing direction menu state variables. + + * public/WebContextMenuData.h: + +2010-02-04 Nate Chapin <japhet@chromium.org> + + Reviewed by Dimitri Glazkov. + + Remove references to V8Custom. + + https://bugs.webkit.org/show_bug.cgi?id=32638 + + * src/DebuggerAgentImpl.cpp: + * src/WebDevToolsFrontendImpl.cpp: + 2010-02-04 Yury Semikhatsky <yurys@chromium.org> Unreviewed. Revert 54333 which broke Chromium build. diff --git a/WebKit/chromium/DEPS b/WebKit/chromium/DEPS index fc90187..9c45b83 100644 --- a/WebKit/chromium/DEPS +++ b/WebKit/chromium/DEPS @@ -35,21 +35,22 @@ vars = { 'chromium_deps_svn': 'http://src.chromium.org/svn/trunk/deps/third_party', # Dependencies' revisions to use: - 'chromium_rev': '31834', - 'google-url_rev': '120', - 'gtest_rev': '336', - 'gyp_rev': '751', - 'icu_rev': '31724', + 'chromium_rev': '38580', + 'google-url_rev': '121', + 'gtest_rev': '359', + 'gyp_rev': '781', + 'icu_rev': '37341', 'openvcdiff_rev': '28', - 'ots_rev': '19', - 'skia_rev': '424', - 'v8_rev': '3276', + 'ots_rev': '26', + 'skia_rev': '490', + 'v8_rev': '3781', # Windows: 'cygwin_rev': '11984', - 'ffmpeg_ia32_rev': '30374', + 'ffmpeg_ia32_rev': '34297', 'pthreads-win32_rev': '26716', 'python_24_rev': '22967', + 'nss_rev': '36871', } deps = { @@ -142,6 +143,10 @@ deps_os = { 'third_party/pthreads-win32': Var('chromium_deps_svn')+'/pthreads-win32@'+Var('pthreads-win32_rev'), + + # base.gypi depends on nss on Windows + 'third_party/nss': + Var('chromium_deps_svn')+'/nss@'+Var('nss_rev'), }, 'unix': { # Linux, actually. diff --git a/WebKit/chromium/WebKit.gyp b/WebKit/chromium/WebKit.gyp index 4f6d3f6..4b0ad2b 100644 --- a/WebKit/chromium/WebKit.gyp +++ b/WebKit/chromium/WebKit.gyp @@ -112,6 +112,7 @@ 'public/WebEventListener.h', 'public/WebFileChooserCompletion.h', 'public/WebFileChooserParams.h', + 'public/WebFileInfo.h', 'public/WebFindOptions.h', 'public/WebFrame.h', 'public/WebFrameClient.h', @@ -199,6 +200,8 @@ 'src/AssertMatchingEnums.cpp', 'src/AutocompletePopupMenuClient.cpp', 'src/AutocompletePopupMenuClient.h', + 'src/AutoFillPopupMenuClient.cpp', + 'src/AutoFillPopupMenuClient.h', 'src/BackForwardListClientImpl.cpp', 'src/BackForwardListClientImpl.h', 'src/BoundObject.cpp', @@ -257,6 +260,8 @@ 'src/StorageEventDispatcherImpl.h', 'src/StorageNamespaceProxy.cpp', 'src/StorageNamespaceProxy.h', + 'src/SuggestionsPopupMenuClient.cpp', + 'src/SuggestionsPopupMenuClient.h', 'src/TemporaryGlue.h', 'src/ToolsAgent.h', 'src/WebAccessibilityCache.cpp', @@ -453,6 +458,14 @@ 'tests/KURLTest.cpp', 'tests/RunAllTests.cpp', ], + 'conditions': [ + ['OS=="win"', { + 'sources': [ + 'tests/TransparencyWinTest.cpp', + 'tests/UniscribeHelperTest.cpp', + ], + }], + ], }, ], # targets } diff --git a/WebKit/chromium/WebKit.gypi b/WebKit/chromium/WebKit.gypi new file mode 100644 index 0000000..69b1479 --- /dev/null +++ b/WebKit/chromium/WebKit.gypi @@ -0,0 +1,67 @@ +# +# Copyright (C) 2010 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +{ + 'variables': { + # List of DevTools source files, ordered by dependencies. It is used both + # for copying them to resource dir, and for generating 'devtools.html' file. + 'devtools_js_files': [ + 'src/js/InspectorControllerImpl.js', + 'src/js/DebuggerAgent.js', + 'src/js/ProfilerAgent.js', + 'src/js/ProfilerProcessor.js', + 'src/js/HeapProfilerPanel.js', + 'src/js/DevTools.js', + 'src/js/DevToolsHostStub.js', + 'src/js/Tests.js', + ], + 'devtools_css_files': [ + 'src/js/devTools.css', + ], + 'devtools_image_files': [ + 'src/js/Images/segmentChromium.png', + 'src/js/Images/segmentHoverChromium.png', + 'src/js/Images/segmentHoverEndChromium.png', + 'src/js/Images/segmentSelectedChromium.png', + 'src/js/Images/segmentSelectedEndChromium.png', + 'src/js/Images/statusbarBackgroundChromium.png', + 'src/js/Images/statusbarBottomBackgroundChromium.png', + 'src/js/Images/statusbarButtonsChromium.png', + 'src/js/Images/statusbarMenuButtonChromium.png', + 'src/js/Images/statusbarMenuButtonSelectedChromium.png', + ], + }, +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/WebKit/chromium/features.gypi b/WebKit/chromium/features.gypi index da2386b..6091b8f 100644 --- a/WebKit/chromium/features.gypi +++ b/WebKit/chromium/features.gypi @@ -47,13 +47,14 @@ 'ENABLE_DASHBOARD_SUPPORT=0', 'ENABLE_DOM_STORAGE=1', 'ENABLE_GEOLOCATION=1', - 'ENABLE_JAVASCRIPT_DEBUGGER=0', + 'ENABLE_JAVASCRIPT_DEBUGGER=1', 'ENABLE_JSC_MULTIPLE_THREADS=0', 'ENABLE_ICONDATABASE=0', 'ENABLE_INDEXED_DATABASE=1', 'ENABLE_NOTIFICATIONS=1', 'ENABLE_OPENTYPE_SANITIZER=1', 'ENABLE_ORIENTATION_EVENTS=0', + 'ENABLE_RUBY=1', 'ENABLE_XHTMLMP=0', 'ENABLE_XSLT=1', 'ENABLE_XPATH=1', diff --git a/WebKit/chromium/public/WebContextMenuData.h b/WebKit/chromium/public/WebContextMenuData.h index 049da9c..5d67046 100644 --- a/WebKit/chromium/public/WebContextMenuData.h +++ b/WebKit/chromium/public/WebContextMenuData.h @@ -103,7 +103,8 @@ struct WebContextMenuData { CheckableMenuItemChecked = 0x2, }; - // Writing direction menu items. + // Writing direction menu items - values are unions of + // CheckableMenuItemFlags. // Currently only used on OS X. int writingDirectionDefault; int writingDirectionLeftToRight; diff --git a/WebKit/chromium/public/WebDatabase.h b/WebKit/chromium/public/WebDatabase.h index 179e828..108201d 100644 --- a/WebKit/chromium/public/WebDatabase.h +++ b/WebKit/chromium/public/WebDatabase.h @@ -72,6 +72,8 @@ public: WEBKIT_API static void updateDatabaseSize( const WebString& originIdentifier, const WebString& databaseName, unsigned long long databaseSize, unsigned long long spaceAvailable); + WEBKIT_API static void closeDatabaseImmediately( + const WebString& originIdentifier, const WebString& databaseName); #if WEBKIT_IMPLEMENTATION WebDatabase(const WTF::PassRefPtr<WebCore::Database>&); diff --git a/WebKit/chromium/public/WebDragData.h b/WebKit/chromium/public/WebDragData.h index 01582a9..0b861c8 100644 --- a/WebKit/chromium/public/WebDragData.h +++ b/WebKit/chromium/public/WebDragData.h @@ -74,6 +74,8 @@ public: WEBKIT_API WebURL downloadURL() const; WEBKIT_API void setDownloadURL(const WebURL&); + WEBKIT_API WebString downloadMetadata() const; + WEBKIT_API void setDownloadMetadata(const WebString&); WEBKIT_API WebString fileExtension() const; WEBKIT_API void setFileExtension(const WebString&); diff --git a/WebKit/chromium/public/WebFileInfo.h b/WebKit/chromium/public/WebFileInfo.h new file mode 100644 index 0000000..4590a30 --- /dev/null +++ b/WebKit/chromium/public/WebFileInfo.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebFileInfo_h +#define WebFileInfo_h + +namespace WebKit { + +struct WebFileInfo { + // The last modification time of the file, in seconds. + // The value 0.0 means that the time is not set. + double modificationTime; + + WebFileInfo() : modificationTime(0.0) { } +}; + +} // namespace WebKit + +#endif diff --git a/WebKit/chromium/public/WebHTTPBody.h b/WebKit/chromium/public/WebHTTPBody.h index 43f51a6..fcc44ff 100644 --- a/WebKit/chromium/public/WebHTTPBody.h +++ b/WebKit/chromium/public/WebHTTPBody.h @@ -32,6 +32,7 @@ #define WebHTTPBody_h #include "WebData.h" +#include "WebFileInfo.h" #include "WebNonCopyable.h" #include "WebString.h" @@ -50,6 +51,9 @@ public: enum { TypeData, TypeFile } type; WebData data; WebString filePath; + long long fileStart; + long long fileLength; // -1 means to the end of the file. + WebFileInfo fileInfo; }; ~WebHTTPBody() { reset(); } @@ -77,7 +81,9 @@ public: // Append to the list of elements. WEBKIT_API void appendData(const WebData&); - WEBKIT_API void appendFile(const WebString&); + WEBKIT_API void appendFile(const WebString&); // FIXME: to be removed. + // Passing -1 to fileLength means to the end of the file. + WEBKIT_API void appendFile(const WebString&, long long fileStart, long long fileLength, const WebFileInfo&); // Identifies a particular form submission instance. A value of 0 is // used to indicate an unspecified identifier. diff --git a/WebKit/chromium/public/WebInputElement.h b/WebKit/chromium/public/WebInputElement.h index 226624a..59643d1 100644 --- a/WebKit/chromium/public/WebInputElement.h +++ b/WebKit/chromium/public/WebInputElement.h @@ -81,11 +81,12 @@ namespace WebKit { Time, Week }; - + WEBKIT_API bool autoComplete() const; WEBKIT_API bool isEnabledFormControl() const; WEBKIT_API InputType inputType() const; WEBKIT_API WebString formControlType() const; + WEBKIT_API bool isActivatedSubmit() const; WEBKIT_API void setActivatedSubmit(bool); WEBKIT_API void setValue(const WebString& value); WEBKIT_API WebString value() const; @@ -97,7 +98,6 @@ namespace WebKit { // storing autofill data. This is either the field name or its id, an empty // string if it has no name and no id. WEBKIT_API WebString nameForAutofill() const; - }; } // namespace WebKit diff --git a/WebKit/chromium/public/WebKitClient.h b/WebKit/chromium/public/WebKitClient.h index fe6c801..fbaa218 100644 --- a/WebKit/chromium/public/WebKitClient.h +++ b/WebKit/chromium/public/WebKitClient.h @@ -59,7 +59,6 @@ class WebStorageNamespace; class WebThemeEngine; class WebURLLoader; struct WebCookie; -struct WebPluginInfo; template <typename T> class WebVector; class WebKitClient { diff --git a/WebKit/chromium/public/WebStorageArea.h b/WebKit/chromium/public/WebStorageArea.h index 19d98c6..5e2c11c 100644 --- a/WebKit/chromium/public/WebStorageArea.h +++ b/WebKit/chromium/public/WebStorageArea.h @@ -45,6 +45,12 @@ class WebStorageArea { public: virtual ~WebStorageArea() { } + enum Result { + ResultOK = 0, + ResultBlockedByQuota, + ResultBlockedByPolicy + }; + // The number of key/value pairs in the storage area. virtual unsigned length() = 0; @@ -57,10 +63,22 @@ public: // no entry for that key. virtual WebString getItem(const WebString& key) = 0; - // Set the value that corresponds to a specific key. QuotaException is set if - // the StorageArea would have exceeded its quota. The value is NOT set when there's - // an exception. url is the url that should be used if a storage event fires. - virtual void setItem(const WebString& key, const WebString& newValue, const WebURL& url, bool& quotaException, WebString& oldValue) = 0; + // Set the value that corresponds to a specific key. Result will either be ResultOK + // or some particular error. The value is NOT set when there's an error. url is the + // url that should be used if a storage event fires. + virtual void setItem(const WebString& key, const WebString& newValue, const WebURL& url, Result& result, WebString& oldValue) + { + bool quotaException = false; + setItem(key, newValue, url, quotaException, oldValue); + result = quotaException ? ResultBlockedByQuota : ResultOK; + } + // FIXME: Remove soon (once Chrome has rolled past this revision). + virtual void setItem(const WebString& key, const WebString& newValue, const WebURL& url, bool& quotaException, WebString& oldValue) + { + Result result; + setItem(key, newValue, url, result, oldValue); + quotaException = result != ResultOK; + } // Remove the value associated with a particular key. url is the url that should be used // if a storage event fires. diff --git a/WebKit/chromium/public/WebView.h b/WebKit/chromium/public/WebView.h index 7b3294f..99125d4 100644 --- a/WebKit/chromium/public/WebView.h +++ b/WebKit/chromium/public/WebView.h @@ -223,17 +223,35 @@ public: virtual WebAccessibilityObject accessibilityObject() = 0; - // Autofill ------------------------------------------------------------ + // AutoFill / Autocomplete --------------------------------------------- - // Notifies the WebView that autofill suggestions are available for a node. + // DEPRECATED: WebView::applyAutocompleteSuggestions is the new way to + // access this. virtual void applyAutofillSuggestions( const WebNode&, const WebVector<WebString>& suggestions, int defaultSuggestionIndex) = 0; - // Hides the autofill popup if any are showing. + // Notifies the WebView that AutoFill suggestions are available for a node. + virtual void applyAutoFillSuggestions( + const WebNode&, + const WebVector<WebString>& names, + const WebVector<WebString>& labels, + int defaultSuggestionIndex) = 0; + + // Notifies the WebView that Autocomplete suggestions are available for a + // node. + virtual void applyAutocompleteSuggestions( + const WebNode&, + const WebVector<WebString>& suggestions, + int defaultSuggestionIndex) = 0; + + // DEPRECATED: WebView::hideSuggestionsPopup is the new way to access this. virtual void hideAutofillPopup() = 0; + // Hides the suggestions popup if any are showing. + virtual void hideSuggestionsPopup() = 0; + // Context menu -------------------------------------------------------- diff --git a/WebKit/chromium/public/WebViewClient.h b/WebKit/chromium/public/WebViewClient.h index 964d382..4d272bb 100644 --- a/WebKit/chromium/public/WebViewClient.h +++ b/WebKit/chromium/public/WebViewClient.h @@ -252,6 +252,9 @@ public: // accessibility object. virtual void focusAccessibilityObject(const WebAccessibilityObject&) { } + // Notifies embedder that the state of an accessibility object has changed. + virtual void didChangeAccessibilityObjectState(const WebAccessibilityObject&) { } + // Developer tools ----------------------------------------------------- diff --git a/WebKit/chromium/src/AutoFillPopupMenuClient.cpp b/WebKit/chromium/src/AutoFillPopupMenuClient.cpp new file mode 100644 index 0000000..8e6cab4 --- /dev/null +++ b/WebKit/chromium/src/AutoFillPopupMenuClient.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AutoFillPopupMenuClient.h" + +#include "HTMLInputElement.h" +#include "WebString.h" +#include "WebVector.h" + +using namespace WebCore; + +namespace WebKit { + +unsigned AutoFillPopupMenuClient::getSuggestionsCount() const +{ + return m_names.size(); +} + +WebString AutoFillPopupMenuClient::getSuggestion(unsigned listIndex) const +{ + // FIXME: Modify the PopupMenu to add the label in gray right-justified. + ASSERT(listIndex >= 0 && listIndex < m_names.size()); + return m_names[listIndex] + String(" (") + m_labels[listIndex] + String(")"); +} + +void AutoFillPopupMenuClient::removeSuggestionAtIndex(unsigned listIndex) +{ + // FIXME: Do we want to remove AutoFill suggestions? + ASSERT(listIndex >= 0 && listIndex < m_names.size()); + m_names.remove(listIndex); + m_labels.remove(listIndex); +} + +void AutoFillPopupMenuClient::initialize( + HTMLInputElement* textField, + const WebVector<WebString>& names, + const WebVector<WebString>& labels, + int defaultSuggestionIndex) +{ + ASSERT(names.size() == labels.size()); + ASSERT(defaultSuggestionIndex < static_cast<int>(names.size())); + + // The suggestions must be set before initializing the + // SuggestionsPopupMenuClient. + setSuggestions(names, labels); + + SuggestionsPopupMenuClient::initialize(textField, defaultSuggestionIndex); +} + +void AutoFillPopupMenuClient::setSuggestions(const WebVector<WebString>& names, + const WebVector<WebString>& labels) +{ + ASSERT(names.size() == labels.size()); + + m_names.clear(); + m_labels.clear(); + for (size_t i = 0; i < names.size(); ++i) { + m_names.append(names[i]); + m_labels.append(labels[i]); + } + + // Try to preserve selection if possible. + if (getSelectedIndex() >= static_cast<int>(names.size())) + setSelectedIndex(-1); +} + +} // namespace WebKit diff --git a/WebKit/chromium/src/AutoFillPopupMenuClient.h b/WebKit/chromium/src/AutoFillPopupMenuClient.h new file mode 100644 index 0000000..fe11334 --- /dev/null +++ b/WebKit/chromium/src/AutoFillPopupMenuClient.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AutoFillPopupMenuClient_h +#define AutoFillPopupMenuClient_h + +#include "SuggestionsPopupMenuClient.h" + +namespace WebCore { +class HTMLInputElement; +} + +namespace WebKit { +class WebString; +template <typename T> class WebVector; + +// The AutoFill suggestions popup menu client, used to display name suggestions +// with right-justified labels. +class AutoFillPopupMenuClient : public SuggestionsPopupMenuClient { +public: + // SuggestionsPopupMenuClient implementation: + virtual unsigned getSuggestionsCount() const; + virtual WebString getSuggestion(unsigned listIndex) const; + virtual void removeSuggestionAtIndex(unsigned listIndex); + + void initialize(WebCore::HTMLInputElement*, + const WebVector<WebString>& names, + const WebVector<WebString>& labels, + int defaultSuggestionIndex); + + void setSuggestions(const WebVector<WebString>& names, + const WebVector<WebString>& labels); + +private: + Vector<WebCore::String> m_names; + Vector<WebCore::String> m_labels; +}; + +<<<<<<< HEAD:WebCore/bindings/v8/RuntimeEnabledFeatures.cpp +bool RuntimeEnabledFeatures::isLocalStorageEnabled = true; +bool RuntimeEnabledFeatures::isSessionStorageEnabled = true; +bool RuntimeEnabledFeatures::isNotificationsEnabled = false; +#if PLATFORM(ANDROID) +// These should default to true, to match the behavior with JSC +bool RuntimeEnabledFeatures::isApplicationCacheEnabled = true; +bool RuntimeEnabledFeatures::isGeolocationEnabled = true; +#endif +bool RuntimeEnabledFeatures::isIndexedDatabaseEnabled = false; +======= +} // namespace WebKit +>>>>>>> webkit.org at r54731:WebKit/chromium/src/AutoFillPopupMenuClient.h + +#endif diff --git a/WebKit/chromium/src/AutocompletePopupMenuClient.cpp b/WebKit/chromium/src/AutocompletePopupMenuClient.cpp index 62d4dff..9620ffc 100644 --- a/WebKit/chromium/src/AutocompletePopupMenuClient.cpp +++ b/WebKit/chromium/src/AutocompletePopupMenuClient.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,27 +31,29 @@ #include "config.h" #include "AutocompletePopupMenuClient.h" -#include "CSSStyleSelector.h" -#include "CSSValueKeywords.h" -#include "FrameView.h" #include "HTMLInputElement.h" -#include "RenderTheme.h" +#include "WebString.h" #include "WebVector.h" -#include "WebViewImpl.h" using namespace WebCore; namespace WebKit { -AutocompletePopupMenuClient::AutocompletePopupMenuClient(WebViewImpl* webView) - : m_textField(0) - , m_selectedIndex(0) - , m_webView(webView) +unsigned AutocompletePopupMenuClient::getSuggestionsCount() const { + return m_suggestions.size(); } -AutocompletePopupMenuClient::~AutocompletePopupMenuClient() +WebString AutocompletePopupMenuClient::getSuggestion(unsigned listIndex) const { + ASSERT(listIndex >= 0 && listIndex < m_suggestions.size()); + return m_suggestions[listIndex]; +} + +void AutocompletePopupMenuClient::removeSuggestionAtIndex(unsigned listIndex) +{ + ASSERT(listIndex >= 0 && listIndex < m_suggestions.size()); + m_suggestions.remove(listIndex); } void AutocompletePopupMenuClient::initialize( @@ -60,90 +62,12 @@ void AutocompletePopupMenuClient::initialize( int defaultSuggestionIndex) { ASSERT(defaultSuggestionIndex < static_cast<int>(suggestions.size())); - m_textField = textField; - m_selectedIndex = defaultSuggestionIndex; - setSuggestions(suggestions); - - FontDescription fontDescription; - m_webView->theme()->systemFont(CSSValueWebkitControl, fontDescription); - // Use a smaller font size to match IE/Firefox. - // FIXME: http://crbug.com/7376 use the system size instead of a - // fixed font size value. - fontDescription.setComputedSize(12.0); - Font font(fontDescription, 0, 0); - font.update(textField->document()->styleSelector()->fontSelector()); - // The direction of text in popup menu is set the same as the direction of - // the input element: textField. - m_style.set(new PopupMenuStyle(Color::black, Color::white, font, true, - Length(WebCore::Fixed), - textField->renderer()->style()->direction())); -} - -void AutocompletePopupMenuClient::valueChanged(unsigned listIndex, bool fireEvents) -{ - m_textField->setValue(m_suggestions[listIndex]); - EditorClientImpl* editor = - static_cast<EditorClientImpl*>(m_webView->page()->editorClient()); - ASSERT(editor); - editor->onAutofillSuggestionAccepted( - static_cast<HTMLInputElement*>(m_textField.get())); -} - -String AutocompletePopupMenuClient::itemText(unsigned listIndex) const -{ - return m_suggestions[listIndex]; -} - -PopupMenuStyle AutocompletePopupMenuClient::itemStyle(unsigned listIndex) const -{ - return *m_style; -} - -PopupMenuStyle AutocompletePopupMenuClient::menuStyle() const -{ - return *m_style; -} - -int AutocompletePopupMenuClient::clientPaddingLeft() const -{ - // Bug http://crbug.com/7708 seems to indicate the style can be 0. - RenderStyle* style = textFieldStyle(); - return style ? m_webView->theme()->popupInternalPaddingLeft(style) : 0; -} -int AutocompletePopupMenuClient::clientPaddingRight() const -{ - // Bug http://crbug.com/7708 seems to indicate the style can be 0. - RenderStyle* style = textFieldStyle(); - return style ? m_webView->theme()->popupInternalPaddingRight(style) : 0; -} - -void AutocompletePopupMenuClient::popupDidHide() -{ - m_webView->autoCompletePopupDidHide(); -} - -void AutocompletePopupMenuClient::setTextFromItem(unsigned listIndex) -{ - m_textField->setValue(m_suggestions[listIndex]); -} - -FontSelector* AutocompletePopupMenuClient::fontSelector() const -{ - return m_textField->document()->styleSelector()->fontSelector(); -} - -HostWindow* AutocompletePopupMenuClient::hostWindow() const -{ - return m_textField->document()->view()->hostWindow(); -} + // The suggestions must be set before initializing the + // SuggestionsPopupMenuClient. + setSuggestions(suggestions); -PassRefPtr<Scrollbar> AutocompletePopupMenuClient::createScrollbar( - ScrollbarClient* client, - ScrollbarOrientation orientation, - ScrollbarControlSize size) -{ - return Scrollbar::createNativeScrollbar(client, orientation, size); + SuggestionsPopupMenuClient::initialize(textField, defaultSuggestionIndex); } void AutocompletePopupMenuClient::setSuggestions(const WebVector<WebString>& suggestions) @@ -151,28 +75,10 @@ void AutocompletePopupMenuClient::setSuggestions(const WebVector<WebString>& sug m_suggestions.clear(); for (size_t i = 0; i < suggestions.size(); ++i) m_suggestions.append(suggestions[i]); - // Try to preserve selection if possible. - if (m_selectedIndex >= static_cast<int>(suggestions.size())) - m_selectedIndex = -1; -} -void AutocompletePopupMenuClient::removeItemAtIndex(int index) -{ - ASSERT(index >= 0 && index < static_cast<int>(m_suggestions.size())); - m_suggestions.remove(index); -} - -RenderStyle* AutocompletePopupMenuClient::textFieldStyle() const -{ - RenderStyle* style = m_textField->computedStyle(); - if (!style) { - // It seems we can only have a 0 style in a TextField if the - // node is detached, in which case we the popup shoud not be - // showing. Please report this in http://crbug.com/7708 and - // include the page you were visiting. - ASSERT_NOT_REACHED(); - } - return style; + // Try to preserve selection if possible. + if (getSelectedIndex() >= static_cast<int>(suggestions.size())) + setSelectedIndex(-1); } } // namespace WebKit diff --git a/WebKit/chromium/src/AutocompletePopupMenuClient.h b/WebKit/chromium/src/AutocompletePopupMenuClient.h index ad24e54..16a3771 100644 --- a/WebKit/chromium/src/AutocompletePopupMenuClient.h +++ b/WebKit/chromium/src/AutocompletePopupMenuClient.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,69 +28,38 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "PopupMenuClient.h" +#ifndef AutocompletePopupMenuClient_h +#define AutocompletePopupMenuClient_h + +#include "SuggestionsPopupMenuClient.h" namespace WebCore { class HTMLInputElement; -class PopupMenuStyle; -class RenderStyle; } namespace WebKit { class WebString; -class WebViewImpl; template <typename T> class WebVector; -// AutocompletePopupMenuClient -class AutocompletePopupMenuClient : public WebCore::PopupMenuClient { +// The Autocomplete suggestions popup menu client, used to display a list of +// autocomplete suggestions. +class AutocompletePopupMenuClient : public SuggestionsPopupMenuClient { public: - AutocompletePopupMenuClient(WebViewImpl* webview); - ~AutocompletePopupMenuClient(); + // SuggestionsPopupMenuClient implementation: + virtual unsigned getSuggestionsCount() const; + virtual WebString getSuggestion(unsigned listIndex) const; + virtual void removeSuggestionAtIndex(unsigned listIndex); void initialize(WebCore::HTMLInputElement*, const WebVector<WebString>& suggestions, int defaultSuggestionIndex); - WebCore::HTMLInputElement* textField() const { return m_textField.get(); } - void setSuggestions(const WebVector<WebString>&); - void removeItemAtIndex(int index); - - // WebCore::PopupMenuClient methods: - virtual void valueChanged(unsigned listIndex, bool fireEvents = true); - virtual WebCore::String itemText(unsigned listIndex) const; - virtual WebCore::String itemToolTip(unsigned lastIndex) const { return WebCore::String(); } - virtual bool itemIsEnabled(unsigned listIndex) const { return true; } - virtual WebCore::PopupMenuStyle itemStyle(unsigned listIndex) const; - virtual WebCore::PopupMenuStyle menuStyle() const; - virtual int clientInsetLeft() const { return 0; } - virtual int clientInsetRight() const { return 0; } - virtual int clientPaddingLeft() const; - virtual int clientPaddingRight() const; - virtual int listSize() const { return m_suggestions.size(); } - virtual int selectedIndex() const { return m_selectedIndex; } - virtual void popupDidHide(); - virtual bool itemIsSeparator(unsigned listIndex) const { return false; } - virtual bool itemIsLabel(unsigned listIndex) const { return false; } - virtual bool itemIsSelected(unsigned listIndex) const { return false; } - virtual bool shouldPopOver() const { return false; } - virtual bool valueShouldChangeOnHotTrack() const { return false; } - virtual void setTextFromItem(unsigned listIndex); - virtual WebCore::FontSelector* fontSelector() const; - virtual WebCore::HostWindow* hostWindow() const; - virtual PassRefPtr<WebCore::Scrollbar> createScrollbar( - WebCore::ScrollbarClient* client, - WebCore::ScrollbarOrientation orientation, - WebCore::ScrollbarControlSize size); private: - WebCore::RenderStyle* textFieldStyle() const; - - RefPtr<WebCore::HTMLInputElement> m_textField; Vector<WebCore::String> m_suggestions; - int m_selectedIndex; - WebViewImpl* m_webView; - OwnPtr<WebCore::PopupMenuStyle> m_style; }; } // namespace WebKit + +#endif diff --git a/WebKit/chromium/src/BackForwardListClientImpl.cpp b/WebKit/chromium/src/BackForwardListClientImpl.cpp index 8feae32..f5b04ab 100644 --- a/WebKit/chromium/src/BackForwardListClientImpl.cpp +++ b/WebKit/chromium/src/BackForwardListClientImpl.cpp @@ -90,7 +90,7 @@ HistoryItem* BackForwardListClientImpl::currentItem() HistoryItem* BackForwardListClientImpl::itemAtIndex(int index) { - if (!m_webView->client()) + if (!m_webView->client() || index > forwardListCount() || -index > backListCount()) return 0; // Since we don't keep the entire back/forward list, we have no way to diff --git a/WebKit/chromium/src/ChromeClientImpl.cpp b/WebKit/chromium/src/ChromeClientImpl.cpp index 9079094..ce2f00c 100644 --- a/WebKit/chromium/src/ChromeClientImpl.cpp +++ b/WebKit/chromium/src/ChromeClientImpl.cpp @@ -659,6 +659,14 @@ void ChromeClientImpl::getPopupMenuInfo(PopupContainer* popupContainer, info->items.swap(outputItems); } +void ChromeClientImpl::didChangeAccessibilityObjectState(AccessibilityObject* obj) +{ + // Alert assistive technology about the accessibility object state change + if (obj) + m_webView->client()->didChangeAccessibilityObjectState(WebAccessibilityObject(obj)); +} + + #if ENABLE(NOTIFICATIONS) NotificationPresenter* ChromeClientImpl::notificationPresenter() const { diff --git a/WebKit/chromium/src/ChromeClientImpl.h b/WebKit/chromium/src/ChromeClientImpl.h index 5a1e9cc..9e8c2e3 100644 --- a/WebKit/chromium/src/ChromeClientImpl.h +++ b/WebKit/chromium/src/ChromeClientImpl.h @@ -34,6 +34,7 @@ #include "ChromeClientChromium.h" namespace WebCore { +class AccessibilityObject; class HTMLParserQuirks; class PopupContainer; class SecurityOrigin; @@ -132,6 +133,7 @@ public: const WebCore::IntRect& bounds, bool activatable, bool handleExternally); + virtual void didChangeAccessibilityObjectState(WebCore::AccessibilityObject*); // ChromeClientImpl: void setCursor(const WebCursorInfo& cursor); diff --git a/WebKit/chromium/src/DebuggerAgent.h b/WebKit/chromium/src/DebuggerAgent.h index cac9686..17cde11 100644 --- a/WebKit/chromium/src/DebuggerAgent.h +++ b/WebKit/chromium/src/DebuggerAgent.h @@ -37,7 +37,10 @@ namespace WebKit { #define DEBUGGER_AGENT_STRUCT(METHOD0, METHOD1, METHOD2, METHOD3, METHOD4, METHOD5) \ /* Requests global context id of the inspected tab. */ \ - METHOD0(getContextId) + METHOD0(getContextId) \ + \ + /* Request v8 to process all debug commands in the queue. */ \ + METHOD0(processDebugCommands) DEFINE_RPC_CLASS(DebuggerAgent, DEBUGGER_AGENT_STRUCT) diff --git a/WebKit/chromium/src/DebuggerAgentImpl.cpp b/WebKit/chromium/src/DebuggerAgentImpl.cpp index 0c3d1ea..d592710 100644 --- a/WebKit/chromium/src/DebuggerAgentImpl.cpp +++ b/WebKit/chromium/src/DebuggerAgentImpl.cpp @@ -51,7 +51,6 @@ using WebCore::Frame; using WebCore::Page; using WebCore::String; using WebCore::V8ClassIndex; -using WebCore::V8Custom; using WebCore::V8DOMWindow; using WebCore::V8DOMWrapper; using WebCore::V8Proxy; @@ -80,6 +79,12 @@ void DebuggerAgentImpl::getContextId() m_delegate->setContextId(m_webdevtoolsAgent->hostId()); } +void DebuggerAgentImpl::processDebugCommands() +{ + DebuggerAgentManager::UtilityContextScope utilityScope; + v8::Debug::ProcessDebugMessages(); +} + void DebuggerAgentImpl::debuggerOutput(const String& command) { m_delegate->debuggerOutput(command); @@ -90,13 +95,21 @@ void DebuggerAgentImpl::debuggerOutput(const String& command) void DebuggerAgentImpl::createUtilityContext(Frame* frame, v8::Persistent<v8::Context>* context) { v8::HandleScope scope; + bool canExecuteScripts = frame->script()->canExecuteScripts(); // Set up the DOM window as the prototype of the new global object. v8::Handle<v8::Context> windowContext = V8Proxy::context(frame); - v8::Handle<v8::Object> windowGlobal = windowContext->Global(); - v8::Handle<v8::Object> windowWrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, windowGlobal); - - ASSERT(V8DOMWindow::toNative(windowWrapper) == frame->domWindow()); + v8::Handle<v8::Object> windowGlobal; + v8::Handle<v8::Object> windowWrapper; + if (canExecuteScripts) { + // FIXME: This check prevents renderer from crashing, while providing limited capabilities for + // DOM inspection, Resources tracking, no scripts support, some timeline profiling. Console will + // result in exceptions for each evaluation. There is still some work that needs to be done in + // order to polish the script-less experience. + windowGlobal = windowContext->Global(); + windowWrapper = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), windowGlobal); + ASSERT(V8DOMWindow::toNative(windowWrapper) == frame->domWindow()); + } v8::Handle<v8::ObjectTemplate> globalTemplate = v8::ObjectTemplate::New(); @@ -121,11 +134,13 @@ void DebuggerAgentImpl::createUtilityContext(Frame* frame, v8::Persistent<v8::Co v8::Handle<v8::Object> global = (*context)->Global(); v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__"); - global->Set(implicitProtoString, windowWrapper); + if (canExecuteScripts) + global->Set(implicitProtoString, windowWrapper); // Give the code running in the new context a way to get access to the // original context. - global->Set(v8::String::New("contentWindow"), windowGlobal); + if (canExecuteScripts) + global->Set(v8::String::New("contentWindow"), windowGlobal); } String DebuggerAgentImpl::executeUtilityFunction( @@ -180,22 +195,6 @@ String DebuggerAgentImpl::executeUtilityFunction( return WebCore::toWebCoreStringWithNullCheck(resObj); } -void DebuggerAgentImpl::executeVoidJavaScript(v8::Handle<v8::Context> context) -{ - v8::HandleScope scope; - ASSERT(!context.IsEmpty()); - v8::Context::Scope contextScope(context); - DebuggerAgentManager::UtilityContextScope utilityScope; - - v8::Handle<v8::Value> function = - context->Global()->Get(v8::String::New("devtools$$void")); - ASSERT(function->IsFunction()); - v8::Handle<v8::Value> args[] = { - v8::Local<v8::Value>() - }; - v8::Handle<v8::Function>::Cast(function)->Call(context->Global(), 0, args); -} - WebCore::Page* DebuggerAgentImpl::page() { return m_webViewImpl->page(); diff --git a/WebKit/chromium/src/DebuggerAgentImpl.h b/WebKit/chromium/src/DebuggerAgentImpl.h index 65dc14c..6eaf576 100644 --- a/WebKit/chromium/src/DebuggerAgentImpl.h +++ b/WebKit/chromium/src/DebuggerAgentImpl.h @@ -62,6 +62,7 @@ public: // DebuggerAgent implementation. virtual void getContextId(); + virtual void processDebugCommands(); void debuggerOutput(const WebCore::String& out); @@ -81,10 +82,6 @@ public: bool async, WebCore::String* exception); - // Executes a no-op function in the utility context. We don't use - // executeUtilityFunction for that to avoid script evaluation leading to - // undesirable AfterCompile events. - void executeVoidJavaScript(v8::Handle<v8::Context> context); WebCore::Page* page(); WebDevToolsAgentImpl* webdevtoolsAgent() { return m_webdevtoolsAgent; } diff --git a/WebKit/chromium/src/EditorClientImpl.cpp b/WebKit/chromium/src/EditorClientImpl.cpp index e035e6a..d5bddc5 100644 --- a/WebKit/chromium/src/EditorClientImpl.cpp +++ b/WebKit/chromium/src/EditorClientImpl.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006, 2007 Apple, Inc. All rights reserved. - * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2010 Google, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -654,7 +654,7 @@ void EditorClientImpl::textFieldDidEndEditing(Element* element) m_autofillTimer.stop(); // Hide any showing popup. - m_webView->hideAutoCompletePopup(); + m_webView->hideSuggestionsPopup(); if (!m_webView->client()) return; // The page is getting closed, don't fill the password. @@ -748,7 +748,7 @@ void EditorClientImpl::doAutofill(Timer<EditorClientImpl>* timer) && inputElement->selectionEnd() == static_cast<int>(value.length()); if ((!args->autofillOnEmptyValue && value.isEmpty()) || !isCaretAtEnd) { - m_webView->hideAutoCompletePopup(); + m_webView->hideSuggestionsPopup(); return; } diff --git a/WebKit/chromium/src/GraphicsContext3D.cpp b/WebKit/chromium/src/GraphicsContext3D.cpp index 7fe31b0..83574da 100644 --- a/WebKit/chromium/src/GraphicsContext3D.cpp +++ b/WebKit/chromium/src/GraphicsContext3D.cpp @@ -275,14 +275,6 @@ private: , m_glXGetCurrentContext(getCurrentContext) { } - - static void* tryLoad(const char* libName) - { - // We use RTLD_GLOBAL semantics so that GLEW initialization works; - // GLEW expects to be able to open the current process's handle - // and do dlsym's of GL entry points from there. - return dlopen(libName, RTLD_LAZY | RTLD_GLOBAL); - } }; static GLConnection* s_gl; @@ -304,22 +296,13 @@ GraphicsContext3DInternal::GLConnection* GraphicsContext3DInternal::GLConnection return 0; } - void* libGL = 0; - const char* libNames[] = { - "/usr/lib/libGL.so.1", - "/usr/lib32/libGL.so.1", - "/usr/lib64/libGL.so.1", - }; - for (int i = 0; i < sizeof(libNames) / sizeof(const char*); i++) { - libGL = tryLoad(libNames[i]); - if (libGL) - break; - } + // We use RTLD_GLOBAL semantics so that GLEW initialization works; + // GLEW expects to be able to open the current process's handle + // and do dlsym's of GL entry points from there. + void* libGL = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); if (!libGL) { - printf("GraphicsContext3D: error opening libGL.so.1\n"); - printf("GraphicsContext3D: tried:\n"); - for (int i = 0; i < sizeof(libNames) / sizeof(const char*); i++) - printf(" %s\n", libNames[i]); + XCloseDisplay(dpy); + printf("GraphicsContext3D: error opening libGL.so.1: %s\n", dlerror()); return 0; } @@ -726,7 +709,6 @@ void GraphicsContext3DInternal::reshape(int width, int height) #endif // FLIP_FRAMEBUFFER_VERTICALLY glClear(GL_COLOR_BUFFER_BIT); - viewportImpl(0, 0, width, height); #if PLATFORM(CG) // Need to reallocate the client-side backing store. diff --git a/WebKit/chromium/src/SuggestionsPopupMenuClient.cpp b/WebKit/chromium/src/SuggestionsPopupMenuClient.cpp new file mode 100644 index 0000000..b4a77a3 --- /dev/null +++ b/WebKit/chromium/src/SuggestionsPopupMenuClient.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SuggestionsPopupMenuClient.h" + +#include "CSSStyleSelector.h" +#include "CSSValueKeywords.h" +#include "Chrome.h" +#include "FrameView.h" +#include "HTMLInputElement.h" +#include "RenderTheme.h" +#include "WebViewImpl.h" + +using namespace WebCore; + +namespace WebKit { + +SuggestionsPopupMenuClient::SuggestionsPopupMenuClient() + : m_textField(0) + , m_selectedIndex(0) +{ +} + +SuggestionsPopupMenuClient::~SuggestionsPopupMenuClient() +{ +} + +// FIXME: Implement this per-derived class? +void SuggestionsPopupMenuClient::valueChanged(unsigned listIndex, bool fireEvents) +{ + m_textField->setValue(getSuggestion(listIndex)); + + WebViewImpl* webView = getWebView(); + if (!webView) + return; + + EditorClientImpl* editor = + static_cast<EditorClientImpl*>(webView->page()->editorClient()); + ASSERT(editor); + editor->onAutofillSuggestionAccepted( + static_cast<HTMLInputElement*>(m_textField.get())); +} + +String SuggestionsPopupMenuClient::itemText(unsigned listIndex) const +{ + return getSuggestion(listIndex); +} + +PopupMenuStyle SuggestionsPopupMenuClient::itemStyle(unsigned listIndex) const +{ + return *m_style; +} + +PopupMenuStyle SuggestionsPopupMenuClient::menuStyle() const +{ + return *m_style; +} + +int SuggestionsPopupMenuClient::clientPaddingLeft() const +{ + // Bug http://crbug.com/7708 seems to indicate the style can be 0. + RenderStyle* style = textFieldStyle(); + if (!style) + return 0; + + return RenderTheme::defaultTheme()->popupInternalPaddingLeft(style); +} + +int SuggestionsPopupMenuClient::clientPaddingRight() const +{ + // Bug http://crbug.com/7708 seems to indicate the style can be 0. + RenderStyle* style = textFieldStyle(); + if (!style) + return 0; + + return RenderTheme::defaultTheme()->popupInternalPaddingRight(style); +} + +void SuggestionsPopupMenuClient::popupDidHide() +{ + WebViewImpl* webView = getWebView(); + if (webView) + webView->suggestionsPopupDidHide(); +} + +void SuggestionsPopupMenuClient::setTextFromItem(unsigned listIndex) +{ + m_textField->setValue(getSuggestion(listIndex)); +} + +FontSelector* SuggestionsPopupMenuClient::fontSelector() const +{ + return m_textField->document()->styleSelector()->fontSelector(); +} + +HostWindow* SuggestionsPopupMenuClient::hostWindow() const +{ + return m_textField->document()->view()->hostWindow(); +} + +PassRefPtr<Scrollbar> SuggestionsPopupMenuClient::createScrollbar( + ScrollbarClient* client, + ScrollbarOrientation orientation, + ScrollbarControlSize size) +{ + return Scrollbar::createNativeScrollbar(client, orientation, size); +} + +RenderStyle* SuggestionsPopupMenuClient::textFieldStyle() const +{ + RenderStyle* style = m_textField->computedStyle(); + if (!style) { + // It seems we can only have a 0 style in a TextField if the + // node is detached, in which case we the popup shoud not be + // showing. Please report this in http://crbug.com/7708 and + // include the page you were visiting. + ASSERT_NOT_REACHED(); + } + return style; +} + +void SuggestionsPopupMenuClient::initialize(HTMLInputElement* textField, + int defaultSuggestionIndex) +{ + m_textField = textField; + m_selectedIndex = defaultSuggestionIndex; + + FontDescription fontDescription; + RenderTheme::defaultTheme()->systemFont(CSSValueWebkitControl, + fontDescription); + + // Use a smaller font size to match IE/Firefox. + // FIXME: http://crbug.com/7376 use the system size instead of a + // fixed font size value. + fontDescription.setComputedSize(12.0); + Font font(fontDescription, 0, 0); + font.update(textField->document()->styleSelector()->fontSelector()); + // The direction of text in popup menu is set the same as the direction of + // the input element: textField. + m_style.set(new PopupMenuStyle(Color::black, Color::white, font, true, + Length(WebCore::Fixed), + textField->renderer()->style()->direction())); +} + +WebViewImpl* SuggestionsPopupMenuClient::getWebView() const +{ + Frame* frame = m_textField->document()->frame(); + if (!frame) + return 0; + + Page* page = frame->page(); + if (!page) + return 0; + + return static_cast<ChromeClientImpl*>(page->chrome()->client())->webView(); +} + +} // namespace WebKit diff --git a/WebKit/chromium/src/SuggestionsPopupMenuClient.h b/WebKit/chromium/src/SuggestionsPopupMenuClient.h new file mode 100644 index 0000000..edc4c09 --- /dev/null +++ b/WebKit/chromium/src/SuggestionsPopupMenuClient.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PopupMenuClient.h" + +#ifndef SuggestionsPopupMenuClient_h +#define SuggestionsPopupMenuClient_h + +namespace WebCore { +class HTMLInputElement; +class PopupMenuStyle; +class RenderStyle; +} + +namespace WebKit { +class WebString; +class WebViewImpl; +template <typename T> class WebVector; + +// The Suggestions popup menu client, used to display a list of suggestions. +class SuggestionsPopupMenuClient : public WebCore::PopupMenuClient { +public: + SuggestionsPopupMenuClient(); + virtual ~SuggestionsPopupMenuClient(); + + // Returns the number of suggestions available. + virtual unsigned getSuggestionsCount() const = 0; + + // Returns the suggestion at |listIndex|. + virtual WebString getSuggestion(unsigned listIndex) const = 0; + + // Removes the suggestion at |listIndex| from the list of suggestions. + virtual void removeSuggestionAtIndex(unsigned listIndex) = 0; + + // WebCore::PopupMenuClient methods: + virtual void valueChanged(unsigned listIndex, bool fireEvents = true); + virtual WebCore::String itemText(unsigned listIndex) const; + virtual WebCore::String itemToolTip(unsigned lastIndex) const { return WebCore::String(); } + virtual bool itemIsEnabled(unsigned listIndex) const { return true; } + virtual WebCore::PopupMenuStyle itemStyle(unsigned listIndex) const; + virtual WebCore::PopupMenuStyle menuStyle() const; + virtual int clientInsetLeft() const { return 0; } + virtual int clientInsetRight() const { return 0; } + virtual int clientPaddingLeft() const; + virtual int clientPaddingRight() const; + virtual int listSize() const { return getSuggestionsCount(); } + virtual int selectedIndex() const { return m_selectedIndex; } + virtual void popupDidHide(); + virtual bool itemIsSeparator(unsigned listIndex) const { return false; } + virtual bool itemIsLabel(unsigned listIndex) const { return false; } + virtual bool itemIsSelected(unsigned listIndex) const { return false; } + virtual bool shouldPopOver() const { return false; } + virtual bool valueShouldChangeOnHotTrack() const { return false; } + virtual void setTextFromItem(unsigned listIndex); + virtual WebCore::FontSelector* fontSelector() const; + virtual WebCore::HostWindow* hostWindow() const; + virtual PassRefPtr<WebCore::Scrollbar> createScrollbar( + WebCore::ScrollbarClient* client, + WebCore::ScrollbarOrientation orientation, + WebCore::ScrollbarControlSize size); + +protected: + void initialize(WebCore::HTMLInputElement* textField, + int defaultSuggestionIndex); + + int getSelectedIndex() const { return m_selectedIndex; } + void setSelectedIndex(int index) { m_selectedIndex = index; } + + WebViewImpl* getWebView() const; + WebCore::HTMLInputElement* getTextField() const { return m_textField.get(); } + +private: + WebCore::RenderStyle* textFieldStyle() const; + + RefPtr<WebCore::HTMLInputElement> m_textField; + int m_selectedIndex; + OwnPtr<WebCore::PopupMenuStyle> m_style; +}; + +} // namespace WebKit + +#endif diff --git a/WebKit/chromium/src/ToolsAgent.h b/WebKit/chromium/src/ToolsAgent.h index fd1fcb7..ab48153 100644 --- a/WebKit/chromium/src/ToolsAgent.h +++ b/WebKit/chromium/src/ToolsAgent.h @@ -38,9 +38,6 @@ namespace WebKit { // Tools agent provides API for enabling / disabling other agents as well as // API for auxiliary UI functions such as dom elements highlighting. #define TOOLS_AGENT_STRUCT(METHOD0, METHOD1, METHOD2, METHOD3, METHOD4, METHOD5) \ - /* Request the agent to to run a no-op JavaScript function to trigger v8 execution. */ \ - METHOD0(executeVoidJavaScript) \ - \ /* Dispatches given function on the InspectorController object */ \ METHOD3(dispatchOnInspectorController, int /* call_id */, \ String /* function_name */, String /* json_args */) \ diff --git a/WebKit/chromium/src/WebDatabase.cpp b/WebKit/chromium/src/WebDatabase.cpp index 2cd36b6..50b9220 100644 --- a/WebKit/chromium/src/WebDatabase.cpp +++ b/WebKit/chromium/src/WebDatabase.cpp @@ -32,7 +32,9 @@ #include "WebDatabase.h" #include "Database.h" +#include "DatabaseTask.h" #include "DatabaseThread.h" +#include "DatabaseTracker.h" #include "Document.h" #include "KURL.h" #include "QuotaTracker.h" @@ -106,6 +108,22 @@ void WebDatabase::updateDatabaseSize( originIdentifier, databaseName, databaseSize, spaceAvailable); } +void WebDatabase::closeDatabaseImmediately(const WebString& originIdentifier, const WebString& databaseName) +{ + HashSet<RefPtr<Database> > databaseHandles; + PassRefPtr<SecurityOrigin> originPrp(*WebSecurityOrigin::createFromDatabaseIdentifier(originIdentifier)); + RefPtr<SecurityOrigin> origin = originPrp; + DatabaseTracker::tracker().getOpenDatabases(origin.get(), databaseName, &databaseHandles); + for (HashSet<RefPtr<Database> >::iterator it = databaseHandles.begin(); it != databaseHandles.end(); ++it) { + Database* database = it->get(); + DatabaseThread* databaseThread = database->scriptExecutionContext()->databaseThread(); + if (databaseThread && !databaseThread->terminationRequested()) { + database->stop(); + databaseThread->scheduleTask(DatabaseCloseTask::create(database, 0)); + } + } +} + WebDatabase::WebDatabase(const WTF::PassRefPtr<Database>& database) : m_private(static_cast<WebDatabasePrivate*>(database.releaseRef())) { diff --git a/WebKit/chromium/src/WebDevToolsAgentImpl.cpp b/WebKit/chromium/src/WebDevToolsAgentImpl.cpp index 9d386f3..9ce35b4 100644 --- a/WebKit/chromium/src/WebDevToolsAgentImpl.cpp +++ b/WebKit/chromium/src/WebDevToolsAgentImpl.cpp @@ -52,6 +52,7 @@ #include "ScriptState.h" #include "ScriptValue.h" #include "V8Binding.h" +#include "V8InspectorBackend.h" #include "V8Proxy.h" #include "V8Utilities.h" #include "WebDataSource.h" @@ -87,6 +88,7 @@ using WebCore::ScriptValue; using WebCore::String; using WebCore::V8ClassIndex; using WebCore::V8DOMWrapper; +using WebCore::V8InspectorBackend; using WebCore::V8Proxy; namespace WebKit { @@ -263,11 +265,6 @@ void WebDevToolsAgentImpl::dispatchOnInjectedScript(int callId, int injectedScri async); } -void WebDevToolsAgentImpl::executeVoidJavaScript() -{ - m_debuggerAgentImpl->executeVoidJavaScript(m_utilityContext); -} - void WebDevToolsAgentImpl::dispatchMessageFromFrontend(const WebDevToolsMessageData& data) { if (ToolsAgentDispatch::dispatch(this, data)) @@ -351,7 +348,7 @@ void WebDevToolsAgentImpl::initDevToolsAgentHost() v8::Local<v8::Object> WebDevToolsAgentImpl::createInspectorBackendV8Wrapper() { V8ClassIndex::V8WrapperType descriptorType = V8ClassIndex::INSPECTORBACKEND; - v8::Handle<v8::Function> function = V8DOMWrapper::getTemplate(descriptorType)->GetFunction(); + v8::Handle<v8::Function> function = V8InspectorBackend::GetTemplate()->GetFunction(); if (function.IsEmpty()) { // Return if allocation failed. return v8::Local<v8::Object>(); diff --git a/WebKit/chromium/src/WebDevToolsAgentImpl.h b/WebKit/chromium/src/WebDevToolsAgentImpl.h index 3f5928b..1f81c6d 100644 --- a/WebKit/chromium/src/WebDevToolsAgentImpl.h +++ b/WebKit/chromium/src/WebDevToolsAgentImpl.h @@ -70,7 +70,6 @@ public: // ToolsAgent implementation. virtual void dispatchOnInspectorController(int callId, const WebCore::String& functionName, const WebCore::String& jsonArgs); virtual void dispatchOnInjectedScript(int callId, int injectedScriptId, const WebCore::String& functionName, const WebCore::String& jsonArgs, bool async); - virtual void executeVoidJavaScript(); // WebDevToolsAgentPrivate implementation. virtual void didClearWindowObject(WebFrameImpl* frame); diff --git a/WebKit/chromium/src/WebDevToolsFrontendImpl.cpp b/WebKit/chromium/src/WebDevToolsFrontendImpl.cpp index 0a92319..89fa6e7 100644 --- a/WebKit/chromium/src/WebDevToolsFrontendImpl.cpp +++ b/WebKit/chromium/src/WebDevToolsFrontendImpl.cpp @@ -52,7 +52,6 @@ #include "Settings.h" #include "ToolsAgent.h" #include "V8Binding.h" -#include "V8CustomBinding.h" #include "V8DOMWrapper.h" #include "V8InspectorFrontendHost.h" #include "V8Node.h" @@ -356,7 +355,7 @@ v8::Handle<v8::Value> WebDevToolsFrontendImpl::jsShowContextMenu(const v8::Argum return v8::Undefined(); v8::Local<v8::Object> eventWrapper = v8::Local<v8::Object>::Cast(args[0]); - if (V8DOMWrapper::domWrapperType(eventWrapper) != V8ClassIndex::EVENT) + if (V8DOMWrapper::domWrapperType(eventWrapper) != V8ClassIndex::MOUSEEVENT) return v8::Undefined(); Event* event = V8Event::toNative(eventWrapper); diff --git a/WebKit/chromium/src/WebDragData.cpp b/WebKit/chromium/src/WebDragData.cpp index 3bd4a02..b18ab1b 100644 --- a/WebKit/chromium/src/WebDragData.cpp +++ b/WebKit/chromium/src/WebDragData.cpp @@ -100,6 +100,18 @@ void WebDragData::setDownloadURL(const WebURL& downloadURL) m_private->downloadURL = downloadURL; } +WebString WebDragData::downloadMetadata() const +{ + ASSERT(!isNull()); + return m_private->downloadMetadata; +} + +void WebDragData::setDownloadMetadata(const WebString& downloadMetadata) +{ + ensureMutable(); + m_private->downloadMetadata = downloadMetadata; +} + WebString WebDragData::fileExtension() const { ASSERT(!isNull()); diff --git a/WebKit/chromium/src/WebHTTPBody.cpp b/WebKit/chromium/src/WebHTTPBody.cpp index 335ed5c..3d40869 100644 --- a/WebKit/chromium/src/WebHTTPBody.cpp +++ b/WebKit/chromium/src/WebHTTPBody.cpp @@ -32,6 +32,7 @@ #include "WebHTTPBody.h" #include "FormData.h" +#include "WebFileInfo.h" using namespace WebCore; @@ -78,11 +79,17 @@ bool WebHTTPBody::elementAt(size_t index, Element& result) const result.type = Element::TypeData; result.data.assign(element.m_data.data(), element.m_data.size()); result.filePath.reset(); + result.fileStart = 0; + result.fileLength = 0; + result.fileInfo.modificationTime = 0.0; break; case FormDataElement::encodedFile: result.type = Element::TypeFile; result.data.reset(); result.filePath = element.m_filename; + result.fileStart = 0; // FIXME: to be set from FormData. + result.fileLength = -1; // FIXME: to be set from FormData. + result.fileInfo.modificationTime = 0.0; // FIXME: to be set from FormData. break; default: ASSERT_NOT_REACHED(); @@ -106,6 +113,11 @@ void WebHTTPBody::appendFile(const WebString& filePath) m_private->appendFile(filePath); } +void WebHTTPBody::appendFile(const WebString& filePath, long long fileStart, long long fileLength, const WebFileInfo& fileInfo) +{ + // FIXME: to be implemented. +} + long long WebHTTPBody::identifier() const { ASSERT(!isNull()); diff --git a/WebKit/chromium/src/WebInputElement.cpp b/WebKit/chromium/src/WebInputElement.cpp index ee799f6..9fd317f 100644 --- a/WebKit/chromium/src/WebInputElement.cpp +++ b/WebKit/chromium/src/WebInputElement.cpp @@ -75,7 +75,12 @@ WebString WebInputElement::formControlType() const { return constUnwrap<HTMLInputElement>()->formControlType(); } - + +bool WebInputElement::isActivatedSubmit() const +{ + return constUnwrap<HTMLInputElement>()->isActivatedSubmit(); +} + void WebInputElement::setActivatedSubmit(bool activated) { unwrap<HTMLInputElement>()->setActivatedSubmit(activated); diff --git a/WebKit/chromium/src/WebRuntimeFeatures.cpp b/WebKit/chromium/src/WebRuntimeFeatures.cpp index 0ef8b9b..ad84764 100644 --- a/WebKit/chromium/src/WebRuntimeFeatures.cpp +++ b/WebKit/chromium/src/WebRuntimeFeatures.cpp @@ -123,14 +123,14 @@ bool WebRuntimeFeatures::isSocketsEnabled() void WebRuntimeFeatures::enableNotifications(bool enable) { #if ENABLE(NOTIFICATIONS) - RuntimeEnabledFeatures::setNotificationsEnabled(enable); + RuntimeEnabledFeatures::setWebkitNotificationsEnabled(enable); #endif } bool WebRuntimeFeatures::isNotificationsEnabled() { #if ENABLE(NOTIFICATIONS) - return RuntimeEnabledFeatures::notificationsEnabled(); + return RuntimeEnabledFeatures::webkitNotificationsEnabled(); #else return false; #endif @@ -171,14 +171,14 @@ bool WebRuntimeFeatures::isGeolocationEnabled() void WebRuntimeFeatures::enableIndexedDatabase(bool enable) { #if ENABLE(INDEXED_DATABASE) - RuntimeEnabledFeatures::setIndexedDatabaseEnabled(enable); + RuntimeEnabledFeatures::setIndexedDBEnabled(enable); #endif } bool WebRuntimeFeatures::isIndexedDatabaseEnabled() { #if ENABLE(INDEXED_DATABASE) - return RuntimeEnabledFeatures::indexedDatabaseEnabled(); + return RuntimeEnabledFeatures::indexedDBEnabled(); #else return false; #endif diff --git a/WebKit/chromium/src/WebStorageAreaImpl.cpp b/WebKit/chromium/src/WebStorageAreaImpl.cpp index 92a923a..9a7fd5c 100644 --- a/WebKit/chromium/src/WebStorageAreaImpl.cpp +++ b/WebKit/chromium/src/WebStorageAreaImpl.cpp @@ -66,7 +66,7 @@ WebString WebStorageAreaImpl::getItem(const WebString& key) return m_storageArea->getItem(key); } -void WebStorageAreaImpl::setItem(const WebString& key, const WebString& value, const WebURL& url, bool& quotaException, WebString& oldValue) +void WebStorageAreaImpl::setItem(const WebString& key, const WebString& value, const WebURL& url, Result& result, WebString& oldValue) { int exceptionCode = 0; @@ -75,9 +75,9 @@ void WebStorageAreaImpl::setItem(const WebString& key, const WebString& value, c if (exceptionCode) { ASSERT(exceptionCode == WebCore::QUOTA_EXCEEDED_ERR); - quotaException = true; + result = ResultBlockedByQuota; } else - quotaException = false; + result = ResultOK; } void WebStorageAreaImpl::removeItem(const WebString& key, const WebURL& url, WebString& oldValue) diff --git a/WebKit/chromium/src/WebStorageAreaImpl.h b/WebKit/chromium/src/WebStorageAreaImpl.h index 7e90531..e9a11c2 100644 --- a/WebKit/chromium/src/WebStorageAreaImpl.h +++ b/WebKit/chromium/src/WebStorageAreaImpl.h @@ -45,7 +45,7 @@ public: virtual unsigned length(); virtual WebString key(unsigned index); virtual WebString getItem(const WebString& key); - virtual void setItem(const WebString& key, const WebString& value, const WebURL& url, bool& quotaException, WebString& oldValue); + virtual void setItem(const WebString& key, const WebString& value, const WebURL& url, Result& result, WebString& oldValue); virtual void removeItem(const WebString& key, const WebURL& url, WebString& oldValue); virtual void clear(const WebURL& url, bool& somethingCleared); diff --git a/WebKit/chromium/src/WebViewImpl.cpp b/WebKit/chromium/src/WebViewImpl.cpp index e030d72..ce03523 100644 --- a/WebKit/chromium/src/WebViewImpl.cpp +++ b/WebKit/chromium/src/WebViewImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,6 +31,7 @@ #include "config.h" #include "WebViewImpl.h" +#include "AutoFillPopupMenuClient.h" #include "AutocompletePopupMenuClient.h" #include "AXObjectCache.h" #include "Chrome.h" @@ -148,16 +149,16 @@ COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove); COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete); COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery); -// Note that focusOnShow is false so that the autocomplete popup is shown not +// Note that focusOnShow is false so that the suggestions popup is shown not // activated. We need the page to still have focus so the user can keep typing // while the popup is showing. -static const PopupContainerSettings autocompletePopupSettings = { +static const PopupContainerSettings suggestionsPopupSettings = { false, // focusOnShow false, // setTextOnIndexChange false, // acceptOnAbandon true, // loopSelectionNavigation true, // restrictWidthOfListBox. Same as other browser (Fx, IE, and safari) - // For autocomplete, we use the direction of the input field as the direction + // For suggestions, we use the direction of the input field as the direction // of the popup items. The main reason is to keep the display of items in // drop-down the same as the items in the input field. PopupContainerSettings::DOMElementDirection, @@ -239,7 +240,9 @@ WebViewImpl::WebViewImpl(WebViewClient* client) , m_dropEffect(DropEffectDefault) , m_operationsAllowed(WebDragOperationNone) , m_dragOperation(WebDragOperationNone) - , m_autocompletePopupShowing(false) + , m_suggestionsPopupShowing(false) + , m_suggestionsPopupClient(0) + , m_suggestionsPopup(0) , m_isTransparent(false) , m_tabsToLinks(false) { @@ -326,7 +329,7 @@ void WebViewImpl::mouseDown(const WebMouseEvent& event) m_lastMouseDownPoint = WebPoint(event.x, event.y); // If a text field that has focus is clicked again, we should display the - // autocomplete popup. + // suggestions popup. RefPtr<Node> clickedNode; if (event.button == WebMouseEvent::ButtonLeft) { RefPtr<Node> focusedNode = focusedWebCoreNode(); @@ -348,7 +351,7 @@ void WebViewImpl::mouseDown(const WebMouseEvent& event) PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); if (clickedNode.get() && clickedNode == focusedWebCoreNode()) { - // Focus has not changed, show the autocomplete popup. + // Focus has not changed, show the suggestions popup. static_cast<EditorClientImpl*>(m_page->editorClient())-> showFormAutofillForNode(clickedNode.get()); } @@ -468,7 +471,7 @@ bool WebViewImpl::keyEvent(const WebKeyboardEvent& event) // event. m_suppressNextKeypressEvent = false; - // Give autocomplete a chance to consume the key events it is interested in. + // Give Autocomplete a chance to consume the key events it is interested in. if (autocompleteHandleKeyEvent(event)) return true; @@ -514,7 +517,7 @@ bool WebViewImpl::keyEvent(const WebKeyboardEvent& event) bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event) { - if (!m_autocompletePopupShowing + if (!m_suggestionsPopupShowing // Home and End should be left to the text field to process. || event.windowsKeyCode == VKEY_HOME || event.windowsKeyCode == VKEY_END) @@ -522,7 +525,7 @@ bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event) // Pressing delete triggers the removal of the selected suggestion from the DB. if (event.windowsKeyCode == VKEY_DELETE - && m_autocompletePopup->selectedIndex() != -1) { + && m_suggestionsPopup->selectedIndex() != -1) { Node* node = focusedWebCoreNode(); if (!node || (node->nodeType() != Node::ELEMENT_NODE)) { ASSERT_NOT_REACHED(); @@ -534,22 +537,22 @@ bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event) return false; } - int selectedIndex = m_autocompletePopup->selectedIndex(); + int selectedIndex = m_suggestionsPopup->selectedIndex(); HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element); WebString name = inputElement->name(); WebString value = m_autocompletePopupClient->itemText(selectedIndex); m_client->removeAutofillSuggestions(name, value); // Update the entries in the currently showing popup to reflect the // deletion. - m_autocompletePopupClient->removeItemAtIndex(selectedIndex); - refreshAutofillPopup(); + m_autocompletePopupClient->removeSuggestionAtIndex(selectedIndex); + refreshSuggestionsPopup(); return false; } - if (!m_autocompletePopup->isInterestedInEventForKey(event.windowsKeyCode)) + if (!m_suggestionsPopup->isInterestedInEventForKey(event.windowsKeyCode)) return false; - if (m_autocompletePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) { + if (m_suggestionsPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) { // We need to ignore the next Char event after this otherwise pressing // enter when selecting an item in the menu will go to the page. if (WebInputEvent::RawKeyDown == event.type) @@ -697,6 +700,7 @@ bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event) case WebInputEvent::RawKeyDown: if (event.modifiers == WebInputEvent::ControlKey) { switch (event.windowsKeyCode) { +#if !OS(DARWIN) case 'A': focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll")); return true; @@ -704,6 +708,7 @@ bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event) case 'C': focusedFrame()->executeCommand(WebString::fromUTF8("Copy")); return true; +#endif // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl // key combinations which affect scrolling. Safari is buggy in the // sense that it scrolls the page for all Ctrl+scrolling key @@ -976,7 +981,7 @@ void WebViewImpl::setFocus(bool enable) } m_imeAcceptEvents = true; } else { - hideAutoCompletePopup(); + hideSuggestionsPopup(); // Clear focus on the currently focused frame if any. if (!m_page.get()) @@ -1182,7 +1187,7 @@ bool WebViewImpl::dispatchBeforeUnloadEvent() // FIXME: This should really cause a recursive depth-first walk of all // frames in the tree, calling each frame's onbeforeunload. At the moment, // we're consistent with Safari 3.1, not IE/FF. - Frame* frame = m_page->focusController()->focusedOrMainFrame(); + Frame* frame = m_page->mainFrame(); if (!frame) return true; @@ -1558,64 +1563,132 @@ void WebViewImpl::applyAutofillSuggestions( const WebVector<WebString>& suggestions, int defaultSuggestionIndex) { - if (!m_page.get() || suggestions.isEmpty()) { - hideAutoCompletePopup(); + applyAutocompleteSuggestions(node, suggestions, defaultSuggestionIndex); +} + +void WebViewImpl::applyAutoFillSuggestions( + const WebNode& node, + const WebVector<WebString>& names, + const WebVector<WebString>& labels, + int defaultSuggestionIndex) +{ + ASSERT(names.size() == labels.size()); + ASSERT(defaultSuggestionIndex < static_cast<int>(names.size())); + + if (names.isEmpty()) { + hideSuggestionsPopup(); + return; + } + + RefPtr<Node> focusedNode = focusedWebCoreNode(); + // If the node for which we queried the AutoFill suggestions is not the + // focused node, then we have nothing to do. FIXME: also check the + // caret is at the end and that the text has not changed. + if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) { + hideSuggestionsPopup(); return; } + HTMLInputElement* inputElem = + static_cast<HTMLInputElement*>(focusedNode.get()); + + // The first time the AutoFill popup is shown we'll create the client and + // the popup. + if (!m_autoFillPopupClient.get()) + m_autoFillPopupClient.set(new AutoFillPopupMenuClient); + + m_autoFillPopupClient->initialize(inputElem, names, labels, + defaultSuggestionIndex); + + if (m_suggestionsPopupClient != m_autoFillPopupClient.get()) { + hideSuggestionsPopup(); + m_suggestionsPopupClient = m_autoFillPopupClient.get(); + } + + if (!m_autoFillPopup.get()) { + m_autoFillPopup = PopupContainer::create(m_suggestionsPopupClient, + suggestionsPopupSettings); + } + + if (m_suggestionsPopup != m_autoFillPopup.get()) + m_suggestionsPopup = m_autoFillPopup.get(); + + if (m_suggestionsPopupShowing) { + m_autoFillPopupClient->setSuggestions(names, labels); + refreshSuggestionsPopup(); + } else { + m_suggestionsPopup->show(focusedNode->getRect(), + focusedNode->ownerDocument()->view(), 0); + m_suggestionsPopupShowing = true; + } +} + +void WebViewImpl::applyAutocompleteSuggestions( + const WebNode& node, + const WebVector<WebString>& suggestions, + int defaultSuggestionIndex) +{ ASSERT(defaultSuggestionIndex < static_cast<int>(suggestions.size())); - if (RefPtr<Frame> focused = m_page->focusController()->focusedFrame()) { - RefPtr<Document> document = focused->document(); - if (!document.get()) { - hideAutoCompletePopup(); - return; - } + if (!m_page.get() || suggestions.isEmpty()) { + hideSuggestionsPopup(); + return; + } - RefPtr<Node> focusedNode = document->focusedNode(); - // If the node for which we queried the autofill suggestions is not the - // focused node, then we have nothing to do. FIXME: also check the - // carret is at the end and that the text has not changed. - if (!focusedNode.get() || focusedNode != PassRefPtr<Node>(node)) { - hideAutoCompletePopup(); - return; - } + RefPtr<Node> focusedNode = focusedWebCoreNode(); + // If the node for which we queried the Autocomplete suggestions is not the + // focused node, then we have nothing to do. FIXME: also check the + // caret is at the end and that the text has not changed. + if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) { + hideSuggestionsPopup(); + return; + } - if (!focusedNode->hasTagName(HTMLNames::inputTag)) { - ASSERT_NOT_REACHED(); - return; - } + HTMLInputElement* inputElem = + static_cast<HTMLInputElement*>(focusedNode.get()); - HTMLInputElement* inputElem = - static_cast<HTMLInputElement*>(focusedNode.get()); - - // The first time the autocomplete is shown we'll create the client and the - // popup. - if (!m_autocompletePopupClient.get()) - m_autocompletePopupClient.set(new AutocompletePopupMenuClient(this)); - m_autocompletePopupClient->initialize(inputElem, - suggestions, - defaultSuggestionIndex); - if (!m_autocompletePopup.get()) { - m_autocompletePopup = - PopupContainer::create(m_autocompletePopupClient.get(), - autocompletePopupSettings); - } + // The first time the Autocomplete is shown we'll create the client and the + // popup. + if (!m_autocompletePopupClient.get()) + m_autocompletePopupClient.set(new AutocompletePopupMenuClient); - if (m_autocompletePopupShowing) { - m_autocompletePopupClient->setSuggestions(suggestions); - refreshAutofillPopup(); - } else { - m_autocompletePopup->show(focusedNode->getRect(), - focusedNode->ownerDocument()->view(), 0); - m_autocompletePopupShowing = true; - } + m_autocompletePopupClient->initialize(inputElem, suggestions, + defaultSuggestionIndex); + + if (m_suggestionsPopupClient != m_autocompletePopupClient.get()) { + hideSuggestionsPopup(); + m_suggestionsPopupClient = m_autocompletePopupClient.get(); + } + + if (!m_autocompletePopup.get()) { + m_autocompletePopup = PopupContainer::create(m_suggestionsPopupClient, + suggestionsPopupSettings); + } + + if (m_suggestionsPopup != m_autocompletePopup.get()) + m_suggestionsPopup = m_autocompletePopup.get(); + + if (m_suggestionsPopupShowing) { + m_autocompletePopupClient->setSuggestions(suggestions); + refreshSuggestionsPopup(); + } else { + m_suggestionsPopup->show(focusedNode->getRect(), + focusedNode->ownerDocument()->view(), 0); + m_suggestionsPopupShowing = true; } } void WebViewImpl::hideAutofillPopup() { - hideAutoCompletePopup(); + hideSuggestionsPopup(); +} + +void WebViewImpl::hideSuggestionsPopup() +{ + if (m_suggestionsPopupShowing) { + m_suggestionsPopup->hidePopup(); + m_suggestionsPopupShowing = false; + } } void WebViewImpl::performCustomContextMenuAction(unsigned action) @@ -1778,19 +1851,6 @@ void WebViewImpl::observeNewNavigation() #endif } -void WebViewImpl::hideAutoCompletePopup() -{ - if (m_autocompletePopupShowing) { - m_autocompletePopup->hidePopup(); - autoCompletePopupDidHide(); - } -} - -void WebViewImpl::autoCompletePopupDidHide() -{ - m_autocompletePopupShowing = false; -} - void WebViewImpl::setIgnoreInputEvents(bool newValue) { ASSERT(m_ignoreInputEvents != newValue); @@ -1806,23 +1866,23 @@ NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl() } #endif -void WebViewImpl::refreshAutofillPopup() +void WebViewImpl::refreshSuggestionsPopup() { - ASSERT(m_autocompletePopupShowing); + ASSERT(m_suggestionsPopupShowing); // Hide the popup if it has become empty. if (!m_autocompletePopupClient->listSize()) { - hideAutoCompletePopup(); + hideSuggestionsPopup(); return; } - IntRect oldBounds = m_autocompletePopup->boundsRect(); - m_autocompletePopup->refresh(); - IntRect newBounds = m_autocompletePopup->boundsRect(); + IntRect oldBounds = m_suggestionsPopup->boundsRect(); + m_suggestionsPopup->refresh(); + IntRect newBounds = m_suggestionsPopup->boundsRect(); // Let's resize the backing window if necessary. if (oldBounds != newBounds) { WebPopupMenuImpl* popupMenu = - static_cast<WebPopupMenuImpl*>(m_autocompletePopup->client()); + static_cast<WebPopupMenuImpl*>(m_suggestionsPopup->client()); popupMenu->client()->setWindowRect(newBounds); } } diff --git a/WebKit/chromium/src/WebViewImpl.h b/WebKit/chromium/src/WebViewImpl.h index e2292f4..286ac43 100644 --- a/WebKit/chromium/src/WebViewImpl.h +++ b/WebKit/chromium/src/WebViewImpl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -58,6 +58,7 @@ class KeyboardEvent; class Page; class PlatformKeyboardEvent; class PopupContainer; +class PopupMenuClient; class Range; class RenderTheme; class Widget; @@ -65,7 +66,9 @@ class Widget; namespace WebKit { class AutocompletePopupMenuClient; +class AutoFillPopupMenuClient; class ContextMenuClientImpl; +class SuggestionsPopupMenuClient; class WebAccessibilityObject; class WebDevToolsAgentPrivate; class WebFrameImpl; @@ -153,7 +156,17 @@ public: const WebNode&, const WebVector<WebString>& suggestions, int defaultSuggestionIndex); + virtual void applyAutoFillSuggestions( + const WebNode&, + const WebVector<WebString>& names, + const WebVector<WebString>& labels, + int defaultSuggestionIndex); + virtual void applyAutocompleteSuggestions( + const WebNode&, + const WebVector<WebString>& suggestions, + int defaultSuggestionIndex); virtual void hideAutofillPopup(); + virtual void hideSuggestionsPopup(); virtual void setScrollbarColors(unsigned inactiveColor, unsigned activeColor, unsigned trackColor); @@ -261,9 +274,10 @@ public: const WebDragData& dragData, WebDragOperationsMask dragSourceOperationMask); - // Hides the autocomplete popup if it is showing. - void hideAutoCompletePopup(); - void autoCompletePopupDidHide(); + void suggestionsPopupDidHide() + { + m_suggestionsPopupShowing = false; + } #if ENABLE(NOTIFICATIONS) // Returns the provider of desktop notifications. @@ -295,10 +309,10 @@ private: // Returns true if the autocomple has consumed the event. bool autocompleteHandleKeyEvent(const WebKeyboardEvent&); - // Repaints the autofill popup. Should be called when the suggestions have - // changed. Note that this should only be called when the autofill popup is - // showing. - void refreshAutofillPopup(); + // Repaints the suggestions popup. Should be called when the suggestions + // have changed. Note that this should only be called when the suggestions + // popup is showing. + void refreshSuggestionsPopup(); // Returns true if the view was scrolled. bool scrollViewWithKeyboard(int keyCode, int modifiers); @@ -393,16 +407,29 @@ private: // current drop target in this WebView (the drop target can accept the drop). WebDragOperation m_dragOperation; - // The autocomplete popup. Kept around and reused every-time new suggestions - // should be shown. - RefPtr<WebCore::PopupContainer> m_autocompletePopup; + // Whether a suggestions popup is currently showing. + bool m_suggestionsPopupShowing; + + // A pointer to the current suggestions popup menu client. This can be + // either an AutoFillPopupMenuClient or an AutocompletePopupMenuClient. We + // do not own this pointer. + SuggestionsPopupMenuClient* m_suggestionsPopupClient; - // Whether the autocomplete popup is currently showing. - bool m_autocompletePopupShowing; + // The AutoFill popup client. + OwnPtr<AutoFillPopupMenuClient> m_autoFillPopupClient; - // The autocomplete client. + // The Autocomplete popup client. OwnPtr<AutocompletePopupMenuClient> m_autocompletePopupClient; + // A pointer to the current suggestions popup. We do not own this pointer. + WebCore::PopupContainer* m_suggestionsPopup; + + // The AutoFill suggestions popup. + RefPtr<WebCore::PopupContainer> m_autoFillPopup; + + // The AutoComplete suggestions popup. + RefPtr<WebCore::PopupContainer> m_autocompletePopup; + OwnPtr<WebDevToolsAgentPrivate> m_devToolsAgent; // Whether the webview is rendering transparently. diff --git a/WebKit/chromium/src/WebWorkerBase.cpp b/WebKit/chromium/src/WebWorkerBase.cpp index 7fd3749..40019e8 100644 --- a/WebKit/chromium/src/WebWorkerBase.cpp +++ b/WebKit/chromium/src/WebWorkerBase.cpp @@ -271,6 +271,8 @@ void WebWorkerBase::workerContextClosedTask(ScriptExecutionContext* context, { if (thisPtr->commonClient()) thisPtr->commonClient()->workerContextClosed(); + + thisPtr->stopWorkerThread(); } void WebWorkerBase::workerContextDestroyed() diff --git a/WebKit/chromium/src/js/DebuggerAgent.js b/WebKit/chromium/src/js/DebuggerAgent.js new file mode 100644 index 0000000..301620a --- /dev/null +++ b/WebKit/chromium/src/js/DebuggerAgent.js @@ -0,0 +1,1528 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @fileoverview Provides communication interface to remote v8 debugger. See + * protocol decription at http://code.google.com/p/v8/wiki/DebuggerProtocol + */ + +/** + * FIXME: change field naming style to use trailing underscore. + * @constructor + */ +devtools.DebuggerAgent = function() +{ + RemoteDebuggerAgent.debuggerOutput = this.handleDebuggerOutput_.bind(this); + RemoteDebuggerAgent.setContextId = this.setContextId_.bind(this); + + /** + * Id of the inspected page global context. It is used for filtering scripts. + * @type {number} + */ + this.contextId_ = null; + + /** + * Mapping from script id to script info. + * @type {Object} + */ + this.parsedScripts_ = null; + + /** + * Mapping from the request id to the devtools.BreakpointInfo for the + * breakpoints whose v8 ids are not set yet. These breakpoints are waiting for + * "setbreakpoint" responses to learn their ids in the v8 debugger. + * @see #handleSetBreakpointResponse_ + * @type {Object} + */ + this.requestNumberToBreakpointInfo_ = null; + + /** + * Information on current stack frames. + * @type {Array.<devtools.CallFrame>} + */ + this.callFrames_ = []; + + /** + * Whether to stop in the debugger on the exceptions. + * @type {boolean} + */ + this.pauseOnExceptions_ = false; + + /** + * Mapping: request sequence number->callback. + * @type {Object} + */ + this.requestSeqToCallback_ = null; + + /** + * Whether the scripts panel has been shown and initialilzed. + * @type {boolean} + */ + this.scriptsPanelInitialized_ = false; + + /** + * Whether the scripts list should be requested next time when context id is + * set. + * @type {boolean} + */ + this.requestScriptsWhenContextIdSet_ = false; + + /** + * Whether the agent is waiting for initial scripts response. + * @type {boolean} + */ + this.waitingForInitialScriptsResponse_ = false; + + /** + * If backtrace response is received when initial scripts response + * is not yet processed the backtrace handling will be postponed until + * after the scripts response processing. The handler bound to its arguments + * and this agent will be stored in this field then. + * @type {?function()} + */ + this.pendingBacktraceResponseHandler_ = null; + + /** + * Container of all breakpoints set using resource URL. These breakpoints + * survive page reload. Breakpoints set by script id(for scripts that don't + * have URLs) are stored in ScriptInfo objects. + * @type {Object} + */ + this.urlToBreakpoints_ = {}; + + + /** + * Exception message that is shown to user while on exception break. + * @type {WebInspector.ConsoleMessage} + */ + this.currentExceptionMessage_ = null; +}; + + +/** + * A copy of the scope types from v8/src/mirror-delay.js + * @enum {number} + */ +devtools.DebuggerAgent.ScopeType = { + Global: 0, + Local: 1, + With: 2, + Closure: 3, + Catch: 4 +}; + + +/** + * Resets debugger agent to its initial state. + */ +devtools.DebuggerAgent.prototype.reset = function() +{ + this.contextId_ = null; + // No need to request scripts since they all will be pushed in AfterCompile + // events. + this.requestScriptsWhenContextIdSet_ = false; + this.waitingForInitialScriptsResponse_ = false; + + this.parsedScripts_ = {}; + this.requestNumberToBreakpointInfo_ = {}; + this.callFrames_ = []; + this.requestSeqToCallback_ = {}; +}; + + +/** + * Initializes scripts UI. This method is called every time Scripts panel + * is shown. It will send request for context id if it's not set yet. + */ +devtools.DebuggerAgent.prototype.initUI = function() +{ + // Initialize scripts cache when Scripts panel is shown first time. + if (this.scriptsPanelInitialized_) + return; + this.scriptsPanelInitialized_ = true; + if (this.contextId_) { + // We already have context id. This means that we are here from the + // very beginning of the page load cycle and hence will get all scripts + // via after-compile events. No need to request scripts for this session. + // + // There can be a number of scripts from after-compile events that are + // pending addition into the UI. + for (var scriptId in this.parsedScripts_) { + var script = this.parsedScripts_[scriptId]; + WebInspector.parsedScriptSource(scriptId, script.getUrl(), undefined /* script source */, script.getLineOffset()); + } + return; + } + this.waitingForInitialScriptsResponse_ = true; + // Script list should be requested only when current context id is known. + RemoteDebuggerAgent.getContextId(); + this.requestScriptsWhenContextIdSet_ = true; +}; + + +/** + * Asynchronously requests the debugger for the script source. + * @param {number} scriptId Id of the script whose source should be resolved. + * @param {function(source:?string):void} callback Function that will be called + * when the source resolution is completed. "source" parameter will be null + * if the resolution fails. + */ +devtools.DebuggerAgent.prototype.resolveScriptSource = function(scriptId, callback) +{ + var script = this.parsedScripts_[scriptId]; + if (!script || script.isUnresolved()) { + callback(null); + return; + } + + var cmd = new devtools.DebugCommand("scripts", { + "ids": [scriptId], + "includeSource": true + }); + devtools.DebuggerAgent.sendCommand_(cmd); + // Force v8 execution so that it gets to processing the requested command. + RemoteDebuggerAgent.processDebugCommands(); + + this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) { + if (msg.isSuccess()) { + var scriptJson = msg.getBody()[0]; + if (scriptJson) + callback(scriptJson.source); + else + callback(null); + } else + callback(null); + }; +}; + + +/** + * Tells the v8 debugger to stop on as soon as possible. + */ +devtools.DebuggerAgent.prototype.pauseExecution = function() +{ + RemoteDebuggerCommandExecutor.DebuggerPauseScript(); +}; + + +/** + * @param {number} sourceId Id of the script fot the breakpoint. + * @param {number} line Number of the line for the breakpoint. + * @param {?string} condition The breakpoint condition. + */ +devtools.DebuggerAgent.prototype.addBreakpoint = function(sourceId, line, condition) +{ + var script = this.parsedScripts_[sourceId]; + if (!script) + return; + + line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); + + var commandArguments; + if (script.getUrl()) { + var breakpoints = this.urlToBreakpoints_[script.getUrl()]; + if (breakpoints && breakpoints[line]) + return; + if (!breakpoints) { + breakpoints = {}; + this.urlToBreakpoints_[script.getUrl()] = breakpoints; + } + + var breakpointInfo = new devtools.BreakpointInfo(line); + breakpoints[line] = breakpointInfo; + + commandArguments = { + "groupId": this.contextId_, + "type": "script", + "target": script.getUrl(), + "line": line, + "condition": condition + }; + } else { + var breakpointInfo = script.getBreakpointInfo(line); + if (breakpointInfo) + return; + + breakpointInfo = new devtools.BreakpointInfo(line); + script.addBreakpointInfo(breakpointInfo); + + commandArguments = { + "groupId": this.contextId_, + "type": "scriptId", + "target": sourceId, + "line": line, + "condition": condition + }; + } + + var cmd = new devtools.DebugCommand("setbreakpoint", commandArguments); + + this.requestNumberToBreakpointInfo_[cmd.getSequenceNumber()] = breakpointInfo; + + devtools.DebuggerAgent.sendCommand_(cmd); + // Force v8 execution so that it gets to processing the requested command. + // It is necessary for being able to change a breakpoint just after it + // has been created (since we need an existing breakpoint id for that). + RemoteDebuggerAgent.processDebugCommands(); +}; + + +/** + * @param {number} sourceId Id of the script for the breakpoint. + * @param {number} line Number of the line for the breakpoint. + */ +devtools.DebuggerAgent.prototype.removeBreakpoint = function(sourceId, line) +{ + var script = this.parsedScripts_[sourceId]; + if (!script) + return; + + line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); + + var breakpointInfo; + if (script.getUrl()) { + var breakpoints = this.urlToBreakpoints_[script.getUrl()]; + breakpointInfo = breakpoints[line]; + delete breakpoints[line]; + } else { + breakpointInfo = script.getBreakpointInfo(line); + if (breakpointInfo) + script.removeBreakpointInfo(breakpointInfo); + } + + if (!breakpointInfo) + return; + + breakpointInfo.markAsRemoved(); + + var id = breakpointInfo.getV8Id(); + + // If we don't know id of this breakpoint in the v8 debugger we cannot send + // "clearbreakpoint" request. In that case it will be removed in + // "setbreakpoint" response handler when we learn the id. + if (id !== -1) { + this.requestClearBreakpoint_(id); + } +}; + + +/** + * @param {number} sourceId Id of the script for the breakpoint. + * @param {number} line Number of the line for the breakpoint. + * @param {?string} condition New breakpoint condition. + */ +devtools.DebuggerAgent.prototype.updateBreakpoint = function(sourceId, line, condition) +{ + var script = this.parsedScripts_[sourceId]; + if (!script) + return; + + line = devtools.DebuggerAgent.webkitToV8LineNumber_(line); + + var breakpointInfo; + if (script.getUrl()) { + var breakpoints = this.urlToBreakpoints_[script.getUrl()]; + breakpointInfo = breakpoints[line]; + } else + breakpointInfo = script.getBreakpointInfo(line); + + var id = breakpointInfo.getV8Id(); + + // If we don't know id of this breakpoint in the v8 debugger we cannot send + // the "changebreakpoint" request. + if (id !== -1) { + // TODO(apavlov): make use of the real values for "enabled" and + // "ignoreCount" when appropriate. + this.requestChangeBreakpoint_(id, true, condition, null); + } +}; + + +/** + * Tells the v8 debugger to step into the next statement. + */ +devtools.DebuggerAgent.prototype.stepIntoStatement = function() +{ + this.stepCommand_("in"); +}; + + +/** + * Tells the v8 debugger to step out of current function. + */ +devtools.DebuggerAgent.prototype.stepOutOfFunction = function() +{ + this.stepCommand_("out"); +}; + + +/** + * Tells the v8 debugger to step over the next statement. + */ +devtools.DebuggerAgent.prototype.stepOverStatement = function() +{ + this.stepCommand_("next"); +}; + + +/** + * Tells the v8 debugger to continue execution after it has been stopped on a + * breakpoint or an exception. + */ +devtools.DebuggerAgent.prototype.resumeExecution = function() +{ + this.clearExceptionMessage_(); + var cmd = new devtools.DebugCommand("continue"); + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * Creates exception message and schedules it for addition to the resource upon + * backtrace availability. + * @param {string} url Resource url. + * @param {number} line Resource line number. + * @param {string} message Exception text. + */ +devtools.DebuggerAgent.prototype.createExceptionMessage_ = function(url, line, message) +{ + this.currentExceptionMessage_ = new WebInspector.ConsoleMessage( + WebInspector.ConsoleMessage.MessageSource.JS, + WebInspector.ConsoleMessage.MessageType.Log, + WebInspector.ConsoleMessage.MessageLevel.Error, + line, + url, + 0 /* group level */, + 1 /* repeat count */, + "[Exception] " + message); +}; + + +/** + * Shows pending exception message that is created with createExceptionMessage_ + * earlier. + */ +devtools.DebuggerAgent.prototype.showPendingExceptionMessage_ = function() +{ + if (!this.currentExceptionMessage_) + return; + var msg = this.currentExceptionMessage_; + var resource = WebInspector.resourceURLMap[msg.url]; + if (resource) { + msg.resource = resource; + WebInspector.panels.resources.addMessageToResource(resource, msg); + } else + this.currentExceptionMessage_ = null; +}; + + +/** + * Clears exception message from the resource. + */ +devtools.DebuggerAgent.prototype.clearExceptionMessage_ = function() +{ + if (this.currentExceptionMessage_) { + var messageElement = this.currentExceptionMessage_._resourceMessageLineElement; + var bubble = messageElement.parentElement; + bubble.removeChild(messageElement); + if (!bubble.firstChild) { + // Last message in bubble removed. + bubble.parentElement.removeChild(bubble); + } + this.currentExceptionMessage_ = null; + } +}; + + +/** + * @return {boolean} True iff the debugger will pause execution on the + * exceptions. + */ +devtools.DebuggerAgent.prototype.pauseOnExceptions = function() +{ + return this.pauseOnExceptions_; +}; + + +/** + * Tells whether to pause in the debugger on the exceptions or not. + * @param {boolean} value True iff execution should be stopped in the debugger + * on the exceptions. + */ +devtools.DebuggerAgent.prototype.setPauseOnExceptions = function(value) +{ + this.pauseOnExceptions_ = value; +}; + + +/** + * Sends "evaluate" request to the debugger. + * @param {Object} arguments Request arguments map. + * @param {function(devtools.DebuggerMessage)} callback Callback to be called + * when response is received. + */ +devtools.DebuggerAgent.prototype.requestEvaluate = function(arguments, callback) +{ + var cmd = new devtools.DebugCommand("evaluate", arguments); + devtools.DebuggerAgent.sendCommand_(cmd); + this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback; +}; + + +/** + * Sends "lookup" request for each unresolved property of the object. When + * response is received the properties will be changed with their resolved + * values. + * @param {Object} object Object whose properties should be resolved. + * @param {function(devtools.DebuggerMessage)} Callback to be called when all + * children are resolved. + * @param {boolean} noIntrinsic Whether intrinsic properties should be included. + */ +devtools.DebuggerAgent.prototype.resolveChildren = function(object, callback, noIntrinsic) +{ + if ("handle" in object) { + var result = []; + devtools.DebuggerAgent.formatObjectProperties_(object, result, noIntrinsic); + callback(result); + } else { + this.requestLookup_([object.ref], function(msg) { + var result = []; + if (msg.isSuccess()) { + var handleToObject = msg.getBody(); + var resolved = handleToObject[object.ref]; + devtools.DebuggerAgent.formatObjectProperties_(resolved, result, noIntrinsic); + callback(result); + } else + callback([]); + }); + } +}; + + +/** + * Sends "scope" request for the scope object to resolve its variables. + * @param {Object} scope Scope to be resolved. + * @param {function(Array.<WebInspector.ObjectPropertyProxy>)} callback + * Callback to be called when all scope variables are resolved. + */ +devtools.DebuggerAgent.prototype.resolveScope = function(scope, callback) +{ + var cmd = new devtools.DebugCommand("scope", { + "frameNumber": scope.frameNumber, + "number": scope.index, + "compactFormat": true + }); + devtools.DebuggerAgent.sendCommand_(cmd); + this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) { + var result = []; + if (msg.isSuccess()) { + var scopeObjectJson = msg.getBody().object; + devtools.DebuggerAgent.formatObjectProperties_(scopeObjectJson, result, true /* no intrinsic */); + } + callback(result); + }; +}; + + +/** + * Sends "scopes" request for the frame object to resolve all variables + * available in the frame. + * @param {number} callFrameId Id of call frame whose variables need to + * be resolved. + * @param {function(Object)} callback Callback to be called when all frame + * variables are resolved. + */ +devtools.DebuggerAgent.prototype.resolveFrameVariables_ = function(callFrameId, callback) +{ + var result = {}; + + var frame = this.callFrames_[callFrameId]; + if (!frame) { + callback(result); + return; + } + + var waitingResponses = 0; + function scopeResponseHandler(msg) { + waitingResponses--; + + if (msg.isSuccess()) { + var properties = msg.getBody().object.properties; + for (var j = 0; j < properties.length; j++) + result[properties[j].name] = true; + } + + // When all scopes are resolved invoke the callback. + if (waitingResponses === 0) + callback(result); + }; + + for (var i = 0; i < frame.scopeChain.length; i++) { + var scope = frame.scopeChain[i].objectId; + if (scope.type === devtools.DebuggerAgent.ScopeType.Global) { + // Do not resolve global scope since it takes for too long. + // TODO(yurys): allow to send only property names in the response. + continue; + } + var cmd = new devtools.DebugCommand("scope", { + "frameNumber": scope.frameNumber, + "number": scope.index, + "compactFormat": true + }); + devtools.DebuggerAgent.sendCommand_(cmd); + this.requestSeqToCallback_[cmd.getSequenceNumber()] = scopeResponseHandler; + waitingResponses++; + } +}; + +/** + * Evaluates the expressionString to an object in the call frame and reports + * all its properties. + * @param{string} expressionString Expression whose properties should be + * collected. + * @param{number} callFrameId The frame id. + * @param{function(Object result,bool isException)} reportCompletions Callback + * function. + */ +devtools.DebuggerAgent.prototype.resolveCompletionsOnFrame = function(expressionString, callFrameId, reportCompletions) +{ + if (expressionString) { + expressionString = "var obj = " + expressionString + + "; var names = {}; for (var n in obj) { names[n] = true; };" + + "names;"; + this.evaluateInCallFrame( + callFrameId, + expressionString, + function(result) { + var names = {}; + if (!result.isException) { + var props = result.value.objectId.properties; + // Put all object properties into the map. + for (var i = 0; i < props.length; i++) + names[props[i].name] = true; + } + reportCompletions(names, result.isException); + }); + } else { + this.resolveFrameVariables_(callFrameId, + function(result) { + reportCompletions(result, false /* isException */); + }); + } +}; + + +/** + * @param{number} scriptId + * @return {string} Type of the context of the script with specified id. + */ +devtools.DebuggerAgent.prototype.getScriptContextType = function(scriptId) +{ + return this.parsedScripts_[scriptId].getContextType(); +}; + + +/** + * Removes specified breakpoint from the v8 debugger. + * @param {number} breakpointId Id of the breakpoint in the v8 debugger. + */ +devtools.DebuggerAgent.prototype.requestClearBreakpoint_ = function(breakpointId) +{ + var cmd = new devtools.DebugCommand("clearbreakpoint", { + "breakpoint": breakpointId + }); + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * Changes breakpoint parameters in the v8 debugger. + * @param {number} breakpointId Id of the breakpoint in the v8 debugger. + * @param {boolean} enabled Whether to enable the breakpoint. + * @param {?string} condition New breakpoint condition. + * @param {number} ignoreCount New ignore count for the breakpoint. + */ +devtools.DebuggerAgent.prototype.requestChangeBreakpoint_ = function(breakpointId, enabled, condition, ignoreCount) +{ + var cmd = new devtools.DebugCommand("changebreakpoint", { + "breakpoint": breakpointId, + "enabled": enabled, + "condition": condition, + "ignoreCount": ignoreCount + }); + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * Sends "backtrace" request to v8. + */ +devtools.DebuggerAgent.prototype.requestBacktrace_ = function() +{ + var cmd = new devtools.DebugCommand("backtrace", { + "compactFormat":true + }); + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * Sends command to v8 debugger. + * @param {devtools.DebugCommand} cmd Command to execute. + */ +devtools.DebuggerAgent.sendCommand_ = function(cmd) +{ + RemoteDebuggerCommandExecutor.DebuggerCommand(cmd.toJSONProtocol()); +}; + + +/** + * Tells the v8 debugger to make the next execution step. + * @param {string} action "in", "out" or "next" action. + */ +devtools.DebuggerAgent.prototype.stepCommand_ = function(action) +{ + this.clearExceptionMessage_(); + var cmd = new devtools.DebugCommand("continue", { + "stepaction": action, + "stepcount": 1 + }); + devtools.DebuggerAgent.sendCommand_(cmd); +}; + + +/** + * Sends "lookup" request to v8. + * @param {number} handle Handle to the object to lookup. + */ +devtools.DebuggerAgent.prototype.requestLookup_ = function(handles, callback) +{ + var cmd = new devtools.DebugCommand("lookup", { + "compactFormat":true, + "handles": handles + }); + devtools.DebuggerAgent.sendCommand_(cmd); + this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback; +}; + + +/** + * Sets debugger context id for scripts filtering. + * @param {number} contextId Id of the inspected page global context. + */ +devtools.DebuggerAgent.prototype.setContextId_ = function(contextId) +{ + this.contextId_ = contextId; + + // If it's the first time context id is set request scripts list. + if (this.requestScriptsWhenContextIdSet_) { + this.requestScriptsWhenContextIdSet_ = false; + var cmd = new devtools.DebugCommand("scripts", { + "includeSource": false + }); + devtools.DebuggerAgent.sendCommand_(cmd); + // Force v8 execution so that it gets to processing the requested command. + RemoteDebuggerAgent.processDebugCommands(); + + var debuggerAgent = this; + this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) { + // Handle the response iff the context id hasn't changed since the request + // was issued. Otherwise if the context id did change all up-to-date + // scripts will be pushed in after compile events and there is no need to + // handle the response. + if (contextId === debuggerAgent.contextId_) + debuggerAgent.handleScriptsResponse_(msg); + + // We received initial scripts response so flush the flag and + // see if there is an unhandled backtrace response. + debuggerAgent.waitingForInitialScriptsResponse_ = false; + if (debuggerAgent.pendingBacktraceResponseHandler_) { + debuggerAgent.pendingBacktraceResponseHandler_(); + debuggerAgent.pendingBacktraceResponseHandler_ = null; + } + }; + } +}; + + +/** + * Handles output sent by v8 debugger. The output is either asynchronous event + * or response to a previously sent request. See protocol definitioun for more + * details on the output format. + * @param {string} output + */ +devtools.DebuggerAgent.prototype.handleDebuggerOutput_ = function(output) +{ + var msg; + try { + msg = new devtools.DebuggerMessage(output); + } catch(e) { + debugPrint("Failed to handle debugger response:\n" + e); + throw e; + } + + if (msg.getType() === "event") { + if (msg.getEvent() === "break") + this.handleBreakEvent_(msg); + else if (msg.getEvent() === "exception") + this.handleExceptionEvent_(msg); + else if (msg.getEvent() === "afterCompile") + this.handleAfterCompileEvent_(msg); + } else if (msg.getType() === "response") { + if (msg.getCommand() === "scripts") + this.invokeCallbackForResponse_(msg); + else if (msg.getCommand() === "setbreakpoint") + this.handleSetBreakpointResponse_(msg); + else if (msg.getCommand() === "clearbreakpoint") + this.handleClearBreakpointResponse_(msg); + else if (msg.getCommand() === "backtrace") + this.handleBacktraceResponse_(msg); + else if (msg.getCommand() === "lookup") + this.invokeCallbackForResponse_(msg); + else if (msg.getCommand() === "evaluate") + this.invokeCallbackForResponse_(msg); + else if (msg.getCommand() === "scope") + this.invokeCallbackForResponse_(msg); + } +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleBreakEvent_ = function(msg) +{ + // Force scrips panel to be shown first. + WebInspector.currentPanel = WebInspector.panels.scripts; + + var body = msg.getBody(); + + var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine); + this.requestBacktrace_(); +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleExceptionEvent_ = function(msg) +{ + // Force scrips panel to be shown first. + WebInspector.currentPanel = WebInspector.panels.scripts; + + var body = msg.getBody(); + // No script field in the body means that v8 failed to parse the script. We + // resume execution on parser errors automatically. + if (this.pauseOnExceptions_ && body.script) { + var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine); + this.createExceptionMessage_(body.script.name, line, body.exception.text); + this.requestBacktrace_(); + } else + this.resumeExecution(); +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleScriptsResponse_ = function(msg) +{ + var scripts = msg.getBody(); + for (var i = 0; i < scripts.length; i++) { + var script = scripts[i]; + + // Skip scripts from other tabs. + if (!this.isScriptFromInspectedContext_(script, msg)) + continue; + + // We may already have received the info in an afterCompile event. + if (script.id in this.parsedScripts_) + continue; + this.addScriptInfo_(script, msg); + } +}; + + +/** + * @param {Object} script Json object representing script. + * @param {devtools.DebuggerMessage} msg Debugger response. + */ +devtools.DebuggerAgent.prototype.isScriptFromInspectedContext_ = function(script, msg) +{ + if (!script.context) { + // Always ignore scripts from the utility context. + return false; + } + var context = msg.lookup(script.context.ref); + var scriptContextId = context.data; + if (typeof scriptContextId === "undefined") + return false; // Always ignore scripts from the utility context. + if (this.contextId_ === null) + return true; + // Find the id from context data. The context data has the format "type,id". + var comma = context.data.indexOf(","); + if (comma < 0) + return false; + return (context.data.substring(comma + 1) == this.contextId_); +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_ = function(msg) +{ + var requestSeq = msg.getRequestSeq(); + var breakpointInfo = this.requestNumberToBreakpointInfo_[requestSeq]; + if (!breakpointInfo) { + // TODO(yurys): handle this case + return; + } + delete this.requestNumberToBreakpointInfo_[requestSeq]; + if (!msg.isSuccess()) { + // TODO(yurys): handle this case + return; + } + var idInV8 = msg.getBody().breakpoint; + breakpointInfo.setV8Id(idInV8); + + if (breakpointInfo.isRemoved()) + this.requestClearBreakpoint_(idInV8); +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleAfterCompileEvent_ = function(msg) +{ + if (!this.contextId_) { + // Ignore scripts delta if main request has not been issued yet. + return; + } + var script = msg.getBody().script; + + // Ignore scripts from other tabs. + if (!this.isScriptFromInspectedContext_(script, msg)) + return; + this.addScriptInfo_(script, msg); +}; + + +/** + * Adds the script info to the local cache. This method assumes that the script + * is not in the cache yet. + * @param {Object} script Script json object from the debugger message. + * @param {devtools.DebuggerMessage} msg Debugger message containing the script + * data. + */ +devtools.DebuggerAgent.prototype.addScriptInfo_ = function(script, msg) +{ + var context = msg.lookup(script.context.ref); + var contextType; + // Find the type from context data. The context data has the format + // "type,id". + var comma = context.data.indexOf(","); + if (comma < 0) + return + contextType = context.data.substring(0, comma); + this.parsedScripts_[script.id] = new devtools.ScriptInfo(script.id, script.name, script.lineOffset, contextType); + if (this.scriptsPanelInitialized_) { + // Only report script as parsed after scripts panel has been shown. + WebInspector.parsedScriptSource(script.id, script.name, script.source, script.lineOffset); + } +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleClearBreakpointResponse_ = function(msg) +{ + // Do nothing. +}; + + +/** + * Handles response to "backtrace" command. + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg) +{ + if (this.waitingForInitialScriptsResponse_) + this.pendingBacktraceResponseHandler_ = this.doHandleBacktraceResponse_.bind(this, msg); + else + this.doHandleBacktraceResponse_(msg); +}; + + +/** + * @param {devtools.DebuggerMessage} msg + */ +devtools.DebuggerAgent.prototype.doHandleBacktraceResponse_ = function(msg) +{ + var frames = msg.getBody().frames; + this.callFrames_ = []; + for (var i = 0; i < frames.length; ++i) + this.callFrames_.push(this.formatCallFrame_(frames[i])); + WebInspector.pausedScript(this.callFrames_); + this.showPendingExceptionMessage_(); + InspectorFrontendHost.activateWindow(); +}; + + +/** + * Evaluates code on given callframe. + */ +devtools.DebuggerAgent.prototype.evaluateInCallFrame = function(callFrameId, code, callback) +{ + var callFrame = this.callFrames_[callFrameId]; + callFrame.evaluate_(code, callback); +}; + + +/** + * Handles response to a command by invoking its callback (if any). + * @param {devtools.DebuggerMessage} msg + * @return {boolean} Whether a callback for the given message was found and + * excuted. + */ +devtools.DebuggerAgent.prototype.invokeCallbackForResponse_ = function(msg) +{ + var callback = this.requestSeqToCallback_[msg.getRequestSeq()]; + if (!callback) { + // It may happend if reset was called. + return false; + } + delete this.requestSeqToCallback_[msg.getRequestSeq()]; + callback(msg); + return true; +}; + + +/** + * @param {Object} stackFrame Frame json object from "backtrace" response. + * @return {!devtools.CallFrame} Object containing information related to the + * call frame in the format expected by ScriptsPanel and its panes. + */ +devtools.DebuggerAgent.prototype.formatCallFrame_ = function(stackFrame) +{ + var func = stackFrame.func; + var sourceId = func.scriptId; + + // Add service script if it does not exist. + var existingScript = this.parsedScripts_[sourceId]; + if (!existingScript) { + this.parsedScripts_[sourceId] = new devtools.ScriptInfo(sourceId, null /* name */, 0 /* line */, "unknown" /* type */, true /* unresolved */); + WebInspector.parsedScriptSource(sourceId, null, null, 0); + } + + var funcName = func.name || func.inferredName || "(anonymous function)"; + var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(stackFrame.line); + + // Add basic scope chain info with scope variables. + var scopeChain = []; + var ScopeType = devtools.DebuggerAgent.ScopeType; + for (var i = 0; i < stackFrame.scopes.length; i++) { + var scope = stackFrame.scopes[i]; + scope.frameNumber = stackFrame.index; + var scopeObjectProxy = new WebInspector.ObjectProxy(0, scope, [], 0, "", true); + scopeObjectProxy.isScope = true; + switch(scope.type) { + case ScopeType.Global: + scopeObjectProxy.isDocument = true; + break; + case ScopeType.Local: + scopeObjectProxy.isLocal = true; + scopeObjectProxy.thisObject = devtools.DebuggerAgent.formatObjectProxy_(stackFrame.receiver); + break; + case ScopeType.With: + // Catch scope is treated as a regular with scope by WebKit so we + // also treat it this way. + case ScopeType.Catch: + scopeObjectProxy.isWithBlock = true; + break; + case ScopeType.Closure: + scopeObjectProxy.isClosure = true; + break; + } + scopeChain.push(scopeObjectProxy); + } + return new devtools.CallFrame(stackFrame.index, "function", funcName, sourceId, line, scopeChain); +}; + + +/** + * Collects properties for an object from the debugger response. + * @param {Object} object An object from the debugger protocol response. + * @param {Array.<WebInspector.ObjectPropertyProxy>} result An array to put the + * properties into. + * @param {boolean} noIntrinsic Whether intrinsic properties should be + * included. + */ +devtools.DebuggerAgent.formatObjectProperties_ = function(object, result, noIntrinsic) +{ + devtools.DebuggerAgent.propertiesToProxies_(object.properties, result); + if (noIntrinsic) + return; + + result.push(new WebInspector.ObjectPropertyProxy("__proto__", devtools.DebuggerAgent.formatObjectProxy_(object.protoObject))); + result.push(new WebInspector.ObjectPropertyProxy("constructor", devtools.DebuggerAgent.formatObjectProxy_(object.constructorFunction))); + // Don't add 'prototype' property since it is one of the regualar properties. +}; + + +/** + * For each property in "properties" creates its proxy representative. + * @param {Array.<Object>} properties Receiver properties or locals array from + * "backtrace" response. + * @param {Array.<WebInspector.ObjectPropertyProxy>} Results holder. + */ +devtools.DebuggerAgent.propertiesToProxies_ = function(properties, result) +{ + var map = {}; + for (var i = 0; i < properties.length; ++i) { + var property = properties[i]; + var name = String(property.name); + if (name in map) + continue; + map[name] = true; + var value = devtools.DebuggerAgent.formatObjectProxy_(property.value); + var propertyProxy = new WebInspector.ObjectPropertyProxy(name, value); + result.push(propertyProxy); + } +}; + + +/** + * @param {Object} v An object reference from the debugger response. + * @return {*} The value representation expected by ScriptsPanel. + */ +devtools.DebuggerAgent.formatObjectProxy_ = function(v) +{ + var description; + var hasChildren = false; + if (v.type === "object") { + description = v.className; + hasChildren = true; + } else if (v.type === "function") { + if (v.source) + description = v.source; + else + description = "function " + v.name + "()"; + hasChildren = true; + } else if (v.type === "undefined") + description = "undefined"; + else if (v.type === "null") + description = "null"; + else if (typeof v.value !== "undefined") { + // Check for undefined and null types before checking the value, otherwise + // null/undefined may have blank value. + description = v.value; + } else + description = "<unresolved ref: " + v.ref + ", type: " + v.type + ">"; + + var proxy = new WebInspector.ObjectProxy(0, v, [], 0, description, hasChildren); + proxy.type = v.type; + proxy.isV8Ref = true; + return proxy; +}; + + +/** + * Converts line number from Web Inspector UI(1-based) to v8(0-based). + * @param {number} line Resource line number in Web Inspector UI. + * @return {number} The line number in v8. + */ +devtools.DebuggerAgent.webkitToV8LineNumber_ = function(line) +{ + return line - 1; +}; + + +/** + * Converts line number from v8(0-based) to Web Inspector UI(1-based). + * @param {number} line Resource line number in v8. + * @return {number} The line number in Web Inspector. + */ +devtools.DebuggerAgent.v8ToWwebkitLineNumber_ = function(line) +{ + return line + 1; +}; + + +/** + * @param {number} scriptId Id of the script. + * @param {?string} url Script resource URL if any. + * @param {number} lineOffset First line 0-based offset in the containing + * document. + * @param {string} contextType Type of the script's context: + * "page" - regular script from html page + * "injected" - extension content script + * @param {bool} opt_isUnresolved If true, script will not be resolved. + * @constructor + */ +devtools.ScriptInfo = function(scriptId, url, lineOffset, contextType, opt_isUnresolved) +{ + this.scriptId_ = scriptId; + this.lineOffset_ = lineOffset; + this.contextType_ = contextType; + this.url_ = url; + this.isUnresolved_ = opt_isUnresolved; + + this.lineToBreakpointInfo_ = {}; +}; + + +/** + * @return {number} + */ +devtools.ScriptInfo.prototype.getLineOffset = function() +{ + return this.lineOffset_; +}; + + +/** + * @return {string} + */ +devtools.ScriptInfo.prototype.getContextType = function() +{ + return this.contextType_; +}; + + +/** + * @return {?string} + */ +devtools.ScriptInfo.prototype.getUrl = function() +{ + return this.url_; +}; + + +/** + * @return {?bool} + */ +devtools.ScriptInfo.prototype.isUnresolved = function() +{ + return this.isUnresolved_; +}; + + +/** + * @param {number} line 0-based line number in the script. + * @return {?devtools.BreakpointInfo} Information on a breakpoint at the + * specified line in the script or undefined if there is no breakpoint at + * that line. + */ +devtools.ScriptInfo.prototype.getBreakpointInfo = function(line) +{ + return this.lineToBreakpointInfo_[line]; +}; + + +/** + * Adds breakpoint info to the script. + * @param {devtools.BreakpointInfo} breakpoint + */ +devtools.ScriptInfo.prototype.addBreakpointInfo = function(breakpoint) +{ + this.lineToBreakpointInfo_[breakpoint.getLine()] = breakpoint; +}; + + +/** + * @param {devtools.BreakpointInfo} breakpoint Breakpoint info to be removed. + */ +devtools.ScriptInfo.prototype.removeBreakpointInfo = function(breakpoint) +{ + var line = breakpoint.getLine(); + delete this.lineToBreakpointInfo_[line]; +}; + + + +/** + * @param {number} line Breakpoint 0-based line number in the containing script. + * @constructor + */ +devtools.BreakpointInfo = function(line) +{ + this.line_ = line; + this.v8id_ = -1; + this.removed_ = false; +}; + + +/** + * @return {number} + */ +devtools.BreakpointInfo.prototype.getLine = function(n) +{ + return this.line_; +}; + + +/** + * @return {number} Unique identifier of this breakpoint in the v8 debugger. + */ +devtools.BreakpointInfo.prototype.getV8Id = function(n) +{ + return this.v8id_; +}; + + +/** + * Sets id of this breakpoint in the v8 debugger. + * @param {number} id + */ +devtools.BreakpointInfo.prototype.setV8Id = function(id) +{ + this.v8id_ = id; +}; + + +/** + * Marks this breakpoint as removed from the front-end. + */ +devtools.BreakpointInfo.prototype.markAsRemoved = function() +{ + this.removed_ = true; +}; + + +/** + * @return {boolean} Whether this breakpoint has been removed from the + * front-end. + */ +devtools.BreakpointInfo.prototype.isRemoved = function() +{ + return this.removed_; +}; + + +/** + * Call stack frame data. + * @param {string} id CallFrame id. + * @param {string} type CallFrame type. + * @param {string} functionName CallFrame type. + * @param {string} sourceID Source id. + * @param {number} line Source line. + * @param {Array.<Object>} scopeChain Array of scoped objects. + * @construnctor + */ +devtools.CallFrame = function(id, type, functionName, sourceID, line, scopeChain) +{ + this.id = id; + this.type = type; + this.functionName = functionName; + this.sourceID = sourceID; + this.line = line; + this.scopeChain = scopeChain; +}; + + +/** + * This method issues asynchronous evaluate request, reports result to the + * callback. + * @param {string} expression An expression to be evaluated in the context of + * this call frame. + * @param {function(Object):undefined} callback Callback to report result to. + */ +devtools.CallFrame.prototype.evaluate_ = function(expression, callback) +{ + devtools.tools.getDebuggerAgent().requestEvaluate({ + "expression": expression, + "frame": this.id, + "global": false, + "disable_break": false, + "compactFormat": true + }, + function(response) { + var result = {}; + if (response.isSuccess()) + result.value = devtools.DebuggerAgent.formatObjectProxy_(response.getBody()); + else { + result.value = response.getMessage(); + result.isException = true; + } + callback(result); + }); +}; + + +/** + * JSON based commands sent to v8 debugger. + * @param {string} command Name of the command to execute. + * @param {Object} opt_arguments Command-specific arguments map. + * @constructor + */ +devtools.DebugCommand = function(command, opt_arguments) +{ + this.command_ = command; + this.type_ = "request"; + this.seq_ = ++devtools.DebugCommand.nextSeq_; + if (opt_arguments) + this.arguments_ = opt_arguments; +}; + + +/** + * Next unique number to be used as debugger request sequence number. + * @type {number} + */ +devtools.DebugCommand.nextSeq_ = 1; + + +/** + * @return {number} + */ +devtools.DebugCommand.prototype.getSequenceNumber = function() +{ + return this.seq_; +}; + + +/** + * @return {string} + */ +devtools.DebugCommand.prototype.toJSONProtocol = function() +{ + var json = { + "seq": this.seq_, + "type": this.type_, + "command": this.command_ + } + if (this.arguments_) + json.arguments = this.arguments_; + return JSON.stringify(json); +}; + + +/** + * JSON messages sent from v8 debugger. See protocol definition for more + * details: http://code.google.com/p/v8/wiki/DebuggerProtocol + * @param {string} msg Raw protocol packet as JSON string. + * @constructor + */ +devtools.DebuggerMessage = function(msg) +{ + this.packet_ = JSON.parse(msg); + this.refs_ = []; + if (this.packet_.refs) { + for (var i = 0; i < this.packet_.refs.length; i++) + this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i]; + } +}; + + +/** + * @return {string} The packet type. + */ +devtools.DebuggerMessage.prototype.getType = function() +{ + return this.packet_.type; +}; + + +/** + * @return {?string} The packet event if the message is an event. + */ +devtools.DebuggerMessage.prototype.getEvent = function() +{ + return this.packet_.event; +}; + + +/** + * @return {?string} The packet command if the message is a response to a + * command. + */ +devtools.DebuggerMessage.prototype.getCommand = function() +{ + return this.packet_.command; +}; + + +/** + * @return {number} The packet request sequence. + */ +devtools.DebuggerMessage.prototype.getRequestSeq = function() +{ + return this.packet_.request_seq; +}; + + +/** + * @return {number} Whether the v8 is running after processing the request. + */ +devtools.DebuggerMessage.prototype.isRunning = function() +{ + return this.packet_.running ? true : false; +}; + + +/** + * @return {boolean} Whether the request succeeded. + */ +devtools.DebuggerMessage.prototype.isSuccess = function() +{ + return this.packet_.success ? true : false; +}; + + +/** + * @return {string} + */ +devtools.DebuggerMessage.prototype.getMessage = function() +{ + return this.packet_.message; +}; + + +/** + * @return {Object} Parsed message body json. + */ +devtools.DebuggerMessage.prototype.getBody = function() +{ + return this.packet_.body; +}; + + +/** + * @param {number} handle Object handle. + * @return {?Object} Returns the object with the handle if it was sent in this + * message(some objects referenced by handles may be missing in the message). + */ +devtools.DebuggerMessage.prototype.lookup = function(handle) +{ + return this.refs_[handle]; +}; diff --git a/WebKit/chromium/src/js/DevTools.js b/WebKit/chromium/src/js/DevTools.js new file mode 100644 index 0000000..dcb181b --- /dev/null +++ b/WebKit/chromium/src/js/DevTools.js @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * FIXME: change field naming style to use trailing underscore. + * @fileoverview Tools is a main class that wires all components of the + * DevTools frontend together. It is also responsible for overriding existing + * WebInspector functionality while it is getting upstreamed into WebCore. + */ + +/** + * Dispatches raw message from the host. + * @param {string} remoteName + * @prama {string} methodName + * @param {string} param1, param2, param3 Arguments to dispatch. + */ +devtools$$dispatch = function(remoteName, methodName, param1, param2, param3) +{ + remoteName = "Remote" + remoteName.substring(0, remoteName.length - 8); + var agent = window[remoteName]; + if (!agent) { + debugPrint("No remote agent '" + remoteName + "' found."); + return; + } + var method = agent[methodName]; + if (!method) { + debugPrint("No method '" + remoteName + "." + methodName + "' found."); + return; + } + method.call(this, param1, param2, param3); +}; + + +devtools.ToolsAgent = function() +{ + RemoteToolsAgent.didDispatchOn = WebInspector.Callback.processCallback; + RemoteToolsAgent.frameNavigate = this.frameNavigate_.bind(this); + RemoteToolsAgent.dispatchOnClient = this.dispatchOnClient_.bind(this); + this.debuggerAgent_ = new devtools.DebuggerAgent(); + this.profilerAgent_ = new devtools.ProfilerAgent(); +}; + + +/** + * Resets tools agent to its initial state. + */ +devtools.ToolsAgent.prototype.reset = function() +{ + this.debuggerAgent_.reset(); +}; + + +/** + * @param {string} script Script exression to be evaluated in the context of the + * inspected page. + * @param {function(Object|string, boolean):undefined} opt_callback Function to + * call with the result. + */ +devtools.ToolsAgent.prototype.evaluateJavaScript = function(script, opt_callback) +{ + InspectorBackend.evaluate(script, opt_callback || function() {}); +}; + + +/** + * @return {devtools.DebuggerAgent} Debugger agent instance. + */ +devtools.ToolsAgent.prototype.getDebuggerAgent = function() +{ + return this.debuggerAgent_; +}; + + +/** + * @return {devtools.ProfilerAgent} Profiler agent instance. + */ +devtools.ToolsAgent.prototype.getProfilerAgent = function() +{ + return this.profilerAgent_; +}; + + +/** + * @param {string} url Url frame navigated to. + * @see tools_agent.h + * @private + */ +devtools.ToolsAgent.prototype.frameNavigate_ = function(url) +{ + this.reset(); + // Do not reset Profiles panel. + var profiles = null; + if ("profiles" in WebInspector.panels) { + profiles = WebInspector.panels["profiles"]; + delete WebInspector.panels["profiles"]; + } + WebInspector.reset(); + if (profiles !== null) + WebInspector.panels["profiles"] = profiles; +}; + + +/** + * @param {string} message Serialized call to be dispatched on WebInspector. + * @private + */ +devtools.ToolsAgent.prototype.dispatchOnClient_ = function(message) +{ + var args = JSON.parse(message); + var methodName = args[0]; + var parameters = args.slice(1); + WebInspector[methodName].apply(WebInspector, parameters); +}; + + +/** + * Evaluates js expression. + * @param {string} expr + */ +devtools.ToolsAgent.prototype.evaluate = function(expr) +{ + RemoteToolsAgent.evaluate(expr); +}; + + +/** + * Enables / disables resources panel in the ui. + * @param {boolean} enabled New panel status. + */ +WebInspector.setResourcesPanelEnabled = function(enabled) +{ + InspectorBackend._resourceTrackingEnabled = enabled; + WebInspector.panels.resources.reset(); +}; + + +/** + * Prints string to the inspector console or shows alert if the console doesn't + * exist. + * @param {string} text + */ +function debugPrint(text) { + var console = WebInspector.console; + if (console) { + console.addMessage(new WebInspector.ConsoleMessage( + WebInspector.ConsoleMessage.MessageSource.JS, + WebInspector.ConsoleMessage.MessageType.Log, + WebInspector.ConsoleMessage.MessageLevel.Log, + 1, "chrome://devtools/<internal>", undefined, -1, text)); + } else + alert(text); +} + + +/** + * Global instance of the tools agent. + * @type {devtools.ToolsAgent} + */ +devtools.tools = null; + + +var context = {}; // Used by WebCore's inspector routines. + +/////////////////////////////////////////////////////////////////////////////// +// Here and below are overrides to existing WebInspector methods only. +// TODO(pfeldman): Patch WebCore and upstream changes. +var oldLoaded = WebInspector.loaded; +WebInspector.loaded = function() +{ + devtools.tools = new devtools.ToolsAgent(); + devtools.tools.reset(); + + Preferences.ignoreWhitespace = false; + Preferences.samplingCPUProfiler = true; + Preferences.heapProfilerPresent = true; + oldLoaded.call(this); + + InspectorFrontendHost.loaded(); +}; + + +(function() +{ + + /** + * Handles an F3 keydown event to focus the Inspector search box. + * @param {KeyboardEvent} event Event to optionally handle + * @return {boolean} whether the event has been handled + */ + function handleF3Keydown(event) { + if (event.keyIdentifier === "F3" && !event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) { + var searchField = document.getElementById("search"); + searchField.focus(); + searchField.select(); + event.preventDefault(); + return true; + } + return false; + } + + + var oldKeyDown = WebInspector.documentKeyDown; + /** + * This override allows to intercept keydown events we want to handle in a + * custom way. Some nested documents (iframes) delegate keydown handling to + * WebInspector.documentKeyDown (e.g. SourceFrame). + * @param {KeyboardEvent} event + * @override + */ + WebInspector.documentKeyDown = function(event) { + var isHandled = handleF3Keydown(event); + if (!isHandled) { + // Mute refresh action. + if (event.keyIdentifier === "F5") + event.preventDefault(); + else if (event.keyIdentifier === "U+0052" /* "R" */ && (event.ctrlKey || event.metaKey)) + event.preventDefault(); + else + oldKeyDown.call(this, event); + } + }; +})(); + + +/** + * This override is necessary for adding script source asynchronously. + * @override + */ +WebInspector.ScriptView.prototype.setupSourceFrameIfNeeded = function() +{ + if (!this._frameNeedsSetup) + return; + + this.attach(); + + if (this.script.source) + this.didResolveScriptSource_(); + else { + var self = this; + devtools.tools.getDebuggerAgent().resolveScriptSource( + this.script.sourceID, + function(source) { + self.script.source = source || WebInspector.UIString("<source is not available>"); + self.didResolveScriptSource_(); + }); + } +}; + + +/** + * Performs source frame setup when script source is aready resolved. + */ +WebInspector.ScriptView.prototype.didResolveScriptSource_ = function() +{ + this.sourceFrame.setContent("text/javascript", this.script.source); + this._sourceFrameSetup = true; + delete this._frameNeedsSetup; +}; + + +/** + * @param {string} type Type of the the property value("object" or "function"). + * @param {string} className Class name of the property value. + * @constructor + */ +WebInspector.UnresolvedPropertyValue = function(type, className) +{ + this.type = type; + this.className = className; +}; + + +(function() +{ + var oldShow = WebInspector.ScriptsPanel.prototype.show; + WebInspector.ScriptsPanel.prototype.show = function() + { + devtools.tools.getDebuggerAgent().initUI(); + this.enableToggleButton.visible = false; + oldShow.call(this); + }; +})(); + + +(function InterceptProfilesPanelEvents() +{ + var oldShow = WebInspector.ProfilesPanel.prototype.show; + WebInspector.ProfilesPanel.prototype.show = function() + { + devtools.tools.getProfilerAgent().initializeProfiling(); + this.enableToggleButton.visible = false; + oldShow.call(this); + // Show is called on every show event of a panel, so + // we only need to intercept it once. + WebInspector.ProfilesPanel.prototype.show = oldShow; + }; +})(); + + +/* + * @override + * TODO(mnaganov): Restore l10n when it will be agreed that it is needed. + */ +WebInspector.UIString = function(string) +{ + return String.vsprintf(string, Array.prototype.slice.call(arguments, 1)); +}; + + +// There is no clear way of setting frame title yet. So sniffing main resource +// load. +(function OverrideUpdateResource() { + var originalUpdateResource = WebInspector.updateResource; + WebInspector.updateResource = function(identifier, payload) + { + originalUpdateResource.call(this, identifier, payload); + var resource = this.resources[identifier]; + if (resource && resource.mainResource && resource.finished) + document.title = WebInspector.UIString("Developer Tools - %s", resource.url); + }; +})(); + + +// Highlight extension content scripts in the scripts list. +(function () { + var original = WebInspector.ScriptsPanel.prototype._addScriptToFilesMenu; + WebInspector.ScriptsPanel.prototype._addScriptToFilesMenu = function(script) + { + var result = original.apply(this, arguments); + var debuggerAgent = devtools.tools.getDebuggerAgent(); + var type = debuggerAgent.getScriptContextType(script.sourceID); + var option = script.filesSelectOption; + if (type === "injected" && option) + option.addStyleClass("injected"); + return result; + }; +})(); + + +/** Pending WebKit upstream by apavlov). Fixes iframe vs drag problem. */ +(function() +{ + var originalDragStart = WebInspector.elementDragStart; + WebInspector.elementDragStart = function(element) + { + if (element) { + var glassPane = document.createElement("div"); + glassPane.style.cssText = "position:absolute;width:100%;height:100%;opacity:0;z-index:1"; + glassPane.id = "glass-pane-for-drag"; + element.parentElement.appendChild(glassPane); + } + + originalDragStart.apply(this, arguments); + }; + + var originalDragEnd = WebInspector.elementDragEnd; + WebInspector.elementDragEnd = function() + { + originalDragEnd.apply(this, arguments); + + var glassPane = document.getElementById("glass-pane-for-drag"); + if (glassPane) + glassPane.parentElement.removeChild(glassPane); + }; +})(); + + +(function () { +var orig = InjectedScriptAccess.prototype.getProperties; +InjectedScriptAccess.prototype.getProperties = function(objectProxy, ignoreHasOwnProperty, abbreviate, callback) +{ + if (objectProxy.isScope) + devtools.tools.getDebuggerAgent().resolveScope(objectProxy.objectId, callback); + else if (objectProxy.isV8Ref) + devtools.tools.getDebuggerAgent().resolveChildren(objectProxy.objectId, callback, false); + else + orig.apply(this, arguments); +}; +})(); + + +(function() +{ +InjectedScriptAccess.prototype.evaluateInCallFrame = function(callFrameId, code, objectGroup, callback) +{ + //TODO(pfeldman): remove once 49084 is rolled. + if (!callback) + callback = objectGroup; + devtools.tools.getDebuggerAgent().evaluateInCallFrame(callFrameId, code, callback); +}; +})(); + + +WebInspector.resourceTrackingWasEnabled = function() +{ + InspectorBackend._resourceTrackingEnabled = true; + this.panels.resources.resourceTrackingWasEnabled(); +}; + +WebInspector.resourceTrackingWasDisabled = function() +{ + InspectorBackend._resourceTrackingEnabled = false; + this.panels.resources.resourceTrackingWasDisabled(); +}; + +(function() +{ +var orig = WebInspector.ConsoleMessage.prototype.setMessageBody; +WebInspector.ConsoleMessage.prototype.setMessageBody = function(args) +{ + for (var i = 0; i < args.length; ++i) { + if (typeof args[i] === "string") + args[i] = WebInspector.ObjectProxy.wrapPrimitiveValue(args[i]); + } + orig.call(this, args); +}; +})(); + + +(function() +{ +var orig = InjectedScriptAccess.prototype.getCompletions; +InjectedScriptAccess.prototype.getCompletions = function(expressionString, includeInspectorCommandLineAPI, callFrameId, reportCompletions) +{ + if (typeof callFrameId === "number") + devtools.tools.getDebuggerAgent().resolveCompletionsOnFrame(expressionString, callFrameId, reportCompletions); + else + return orig.apply(this, arguments); +}; +})(); + + +(function() +{ +WebInspector.ElementsPanel.prototype._nodeSearchButtonClicked = function( event) +{ + InspectorBackend.toggleNodeSearch(); + this.nodeSearchButton.toggled = !this.nodeSearchButton.toggled; +}; +})(); + + +// We need to have a place for postponed tasks +// which should be executed when all the messages between agent and frontend +// are processed. + +WebInspector.runAfterPendingDispatchesQueue = []; + +WebInspector.TestController.prototype.runAfterPendingDispatches = function(callback) +{ + WebInspector.runAfterPendingDispatchesQueue.push(callback); +}; + +WebInspector.queuesAreEmpty = function() +{ + var copy = this.runAfterPendingDispatchesQueue.slice(); + this.runAfterPendingDispatchesQueue = []; + for (var i = 0; i < copy.length; ++i) + copy[i].call(this); +}; + +(function() +{ +var originalAddToFrame = InspectorFrontendHost.addResourceSourceToFrame; +InspectorFrontendHost.addResourceSourceToFrame = function(identifier, element) +{ + var resource = WebInspector.resources[identifier]; + if (!resource) + return; + originalAddToFrame.call(this, identifier, resource.mimeType, element); +}; +})(); + +WebInspector.pausedScript = function(callFrames) +{ + this.panels.scripts.debuggerPaused(callFrames); +}; diff --git a/WebKit/chromium/src/js/DevToolsHostStub.js b/WebKit/chromium/src/js/DevToolsHostStub.js new file mode 100644 index 0000000..8b2f46b --- /dev/null +++ b/WebKit/chromium/src/js/DevToolsHostStub.js @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @fileoverview These stubs emulate backend functionality and allows + * DevTools frontend to function as a standalone web app. + */ + +if (!window["RemoteDebuggerAgent"]) { + +/** + * FIXME: change field naming style to use trailing underscore. + * @constructor + */ +RemoteDebuggerAgentStub = function() +{ +}; + + +RemoteDebuggerAgentStub.prototype.getContextId = function() +{ + RemoteDebuggerAgent.setContextId(3); +}; + + +RemoteDebuggerAgentStub.prototype.processDebugCommands = function() +{ +}; + + +/** + * @constructor + */ +RemoteProfilerAgentStub = function() +{ +}; + + +RemoteProfilerAgentStub.prototype.getActiveProfilerModules = function() +{ + ProfilerStubHelper.GetInstance().getActiveProfilerModules(); +}; + + +RemoteProfilerAgentStub.prototype.getLogLines = function(pos) +{ + ProfilerStubHelper.GetInstance().getLogLines(pos); +}; + + +/** + * @constructor + */ +RemoteToolsAgentStub = function() +{ +}; + + +RemoteToolsAgentStub.prototype.dispatchOnInjectedScript = function() +{ +}; + + +RemoteToolsAgentStub.prototype.dispatchOnInspectorController = function() +{ +}; + + +/** + * @constructor + */ +ProfilerStubHelper = function() +{ + this.activeProfilerModules_ = devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_NONE; + this.heapProfSample_ = 0; + this.log_ = ''; +}; + + +ProfilerStubHelper.GetInstance = function() +{ + if (!ProfilerStubHelper.instance_) + ProfilerStubHelper.instance_ = new ProfilerStubHelper(); + return ProfilerStubHelper.instance_; +}; + + +ProfilerStubHelper.prototype.StopProfiling = function(modules) +{ + this.activeProfilerModules_ &= ~modules; +}; + + +ProfilerStubHelper.prototype.StartProfiling = function(modules) +{ + var profModules = devtools.ProfilerAgent.ProfilerModules; + if (modules & profModules.PROFILER_MODULE_HEAP_SNAPSHOT) { + if (modules & profModules.PROFILER_MODULE_HEAP_STATS) { + this.log_ += + 'heap-sample-begin,"Heap","allocated",' + + (new Date()).getTime() + '\n' + + 'heap-sample-stats,"Heap","allocated",10000,1000\n'; + this.log_ += + 'heap-sample-item,STRING_TYPE,100,1000\n' + + 'heap-sample-item,CODE_TYPE,10,200\n' + + 'heap-sample-item,MAP_TYPE,20,350\n'; + this.log_ += ProfilerStubHelper.HeapSamples[this.heapProfSample_++]; + this.heapProfSample_ %= ProfilerStubHelper.HeapSamples.length; + this.log_ += 'heap-sample-end,"Heap","allocated"\n'; + } + } else { + if (modules & profModules.PROFILER_MODULE_CPU) + this.log_ += ProfilerStubHelper.ProfilerLogBuffer; + this.activeProfilerModules_ |= modules; + } +}; + + +ProfilerStubHelper.prototype.getActiveProfilerModules = function() +{ + var self = this; + setTimeout(function() { + RemoteProfilerAgent.didGetActiveProfilerModules(self.activeProfilerModules_); + }, 100); +}; + + +ProfilerStubHelper.prototype.getLogLines = function(pos) +{ + var profModules = devtools.ProfilerAgent.ProfilerModules; + var logLines = this.log_.substr(pos); + setTimeout(function() { + RemoteProfilerAgent.didGetLogLines(pos + logLines.length, logLines); + }, 100); +}; + + +ProfilerStubHelper.ProfilerLogBuffer = + 'profiler,begin,1\n' + + 'profiler,resume\n' + + 'code-creation,LazyCompile,0x1000,256,"test1 http://aaa.js:1"\n' + + 'code-creation,LazyCompile,0x2000,256,"test2 http://bbb.js:2"\n' + + 'code-creation,LazyCompile,0x3000,256,"test3 http://ccc.js:3"\n' + + 'tick,0x1010,0x0,3\n' + + 'tick,0x2020,0x0,3,0x1010\n' + + 'tick,0x2020,0x0,3,0x1010\n' + + 'tick,0x3010,0x0,3,0x2020, 0x1010\n' + + 'tick,0x2020,0x0,3,0x1010\n' + + 'tick,0x2030,0x0,3,0x2020, 0x1010\n' + + 'tick,0x2020,0x0,3,0x1010\n' + + 'tick,0x1010,0x0,3\n' + + 'profiler,pause\n'; + + +ProfilerStubHelper.HeapSamples = [ + 'heap-js-cons-item,foo,1,100\n' + + 'heap-js-cons-item,bar,20,2000\n' + + 'heap-js-cons-item,Object,5,100\n' + + 'heap-js-ret-item,foo,bar;3\n' + + 'heap-js-ret-item,bar,foo;5\n' + + 'heap-js-ret-item,Object:0x1234,(roots);1\n', + + 'heap-js-cons-item,foo,2000,200000\n' + + 'heap-js-cons-item,bar,10,1000\n' + + 'heap-js-cons-item,Object,6,120\n' + + 'heap-js-ret-item,foo,bar;7,Object:0x1234;10\n' + + 'heap-js-ret-item,bar,foo;10,Object:0x1234;10\n' + + 'heap-js-ret-item,Object:0x1234,(roots);1\n', + + 'heap-js-cons-item,foo,15,1500\n' + + 'heap-js-cons-item,bar,15,1500\n' + + 'heap-js-cons-item,Object,5,100\n' + + 'heap-js-cons-item,Array,3,1000\n' + + 'heap-js-ret-item,foo,bar;3,Array:0x5678;1\n' + + 'heap-js-ret-item,bar,foo;5,Object:0x1234;8,Object:0x5678;2\n' + + 'heap-js-ret-item,Object:0x1234,(roots);1,Object:0x5678;2\n' + + 'heap-js-ret-item,Object:0x5678,(global property);3,Object:0x1234;5\n' + + 'heap-js-ret-item,Array:0x5678,(global property);3,Array:0x5678;2\n', + + 'heap-js-cons-item,bar,20,2000\n' + + 'heap-js-cons-item,Object,6,120\n' + + 'heap-js-ret-item,bar,foo;5,Object:0x1234;1,Object:0x1235;3\n' + + 'heap-js-ret-item,Object:0x1234,(global property);3\n' + + 'heap-js-ret-item,Object:0x1235,(global property);5\n', + + 'heap-js-cons-item,foo,15,1500\n' + + 'heap-js-cons-item,bar,15,1500\n' + + 'heap-js-cons-item,Array,10,1000\n' + + 'heap-js-ret-item,foo,bar;1,Array:0x5678;1\n' + + 'heap-js-ret-item,bar,foo;5\n' + + 'heap-js-ret-item,Array:0x5678,(roots);3\n', + + 'heap-js-cons-item,bar,20,2000\n' + + 'heap-js-cons-item,baz,15,1500\n' + + 'heap-js-ret-item,bar,baz;3\n' + + 'heap-js-ret-item,baz,bar;3\n' +]; + + +/** + * @constructor + */ +RemoteDebuggerCommandExecutorStub = function() +{ +}; + + +RemoteDebuggerCommandExecutorStub.prototype.DebuggerCommand = function(cmd) +{ + if ('{"seq":2,"type":"request","command":"scripts","arguments":{"includeSource":false}}' === cmd) { + var response1 = + '{"seq":5,"request_seq":2,"type":"response","command":"scripts","' + + 'success":true,"body":[{"handle":61,"type":"script","name":"' + + 'http://www/~test/t.js","id":59,"lineOffset":0,"columnOffset":0,' + + '"lineCount":1,"sourceStart":"function fib(n) {","sourceLength":300,' + + '"scriptType":2,"compilationType":0,"context":{"ref":60}}],"refs":[{' + + '"handle":60,"type":"context","data":"page,3"}],"running":false}'; + this.sendResponse_(response1); + } else if ('{"seq":3,"type":"request","command":"scripts","arguments":{"ids":[59],"includeSource":true}}' === cmd) { + this.sendResponse_( + '{"seq":8,"request_seq":3,"type":"response","command":"scripts",' + + '"success":true,"body":[{"handle":1,"type":"script","name":' + + '"http://www/~test/t.js","id":59,"lineOffset":0,"columnOffset":0,' + + '"lineCount":1,"source":"function fib(n) {return n+1;}",' + + '"sourceLength":244,"scriptType":2,"compilationType":0,"context":{' + + '"ref":0}}],"refs":[{"handle":0,"type":"context","data":"page,3}],"' + + '"running":false}'); + } else if (cmd.indexOf('"command":"profile"') !== -1) { + var cmdObj = JSON.parse(cmd); + if (cmdObj.arguments.command === "resume") + ProfilerStubHelper.GetInstance().StartProfiling(parseInt(cmdObj.arguments.modules)); + else if (cmdObj.arguments.command === "pause") + ProfilerStubHelper.GetInstance().StopProfiling(parseInt(cmdObj.arguments.modules)); + else + debugPrint("Unexpected profile command: " + cmdObj.arguments.command); + } else + debugPrint("Unexpected command: " + cmd); +}; + + +RemoteDebuggerCommandExecutorStub.prototype.DebuggerPauseScript = function() +{ +}; + + +RemoteDebuggerCommandExecutorStub.prototype.sendResponse_ = function(response) +{ + setTimeout(function() { + RemoteDebuggerAgent.debuggerOutput(response); + }, 0); +}; + + +DevToolsHostStub = function() +{ + this.isStub = true; +}; +DevToolsHostStub.prototype.__proto__ = WebInspector.InspectorFrontendHostStub.prototype; + + +DevToolsHostStub.prototype.reset = function() +{ +}; + + +DevToolsHostStub.prototype.setting = function() +{ +}; + + +DevToolsHostStub.prototype.setSetting = function() +{ +}; + + +window["RemoteDebuggerAgent"] = new RemoteDebuggerAgentStub(); +window["RemoteDebuggerCommandExecutor"] = new RemoteDebuggerCommandExecutorStub(); +window["RemoteProfilerAgent"] = new RemoteProfilerAgentStub(); +window["RemoteToolsAgent"] = new RemoteToolsAgentStub(); +InspectorFrontendHost = new DevToolsHostStub(); + +} diff --git a/WebKit/chromium/src/js/HeapProfilerPanel.js b/WebKit/chromium/src/js/HeapProfilerPanel.js new file mode 100644 index 0000000..abbf580 --- /dev/null +++ b/WebKit/chromium/src/js/HeapProfilerPanel.js @@ -0,0 +1,966 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @fileoverview Heap profiler panel implementation. + */ + +WebInspector.ProfilesPanel.prototype.addSnapshot = function(snapshot) { + snapshot.title = WebInspector.UIString("Snapshot %d", snapshot.number); + snapshot.typeId = WebInspector.HeapSnapshotProfileType.TypeId; + + var snapshots = WebInspector.HeapSnapshotProfileType.snapshots; + snapshots.push(snapshot); + + snapshot.listIndex = snapshots.length - 1; + + if (WebInspector.CPUProfile) + this.addProfileHeader(WebInspector.HeapSnapshotProfileType.TypeId, snapshot); + else + this.addProfileHeader(snapshot); + + this.dispatchEventToListeners("snapshot added"); +} + + +WebInspector.HeapSnapshotView = function(parent, profile) +{ + WebInspector.View.call(this); + + this.element.addStyleClass("heap-snapshot-view"); + + this.parent = parent; + this.parent.addEventListener("snapshot added", this._updateBaseOptions, this); + + this.showCountAsPercent = false; + this.showSizeAsPercent = false; + this.showCountDeltaAsPercent = false; + this.showSizeDeltaAsPercent = false; + + this.categories = { + code: new WebInspector.ResourceCategory("code", WebInspector.UIString("Code"), "rgb(255,121,0)"), + data: new WebInspector.ResourceCategory("data", WebInspector.UIString("Objects"), "rgb(47,102,236)") + }; + + var summaryContainer = document.createElement("div"); + summaryContainer.id = "heap-snapshot-summary-container"; + + this.countsSummaryBar = new WebInspector.SummaryBar(this.categories); + this.countsSummaryBar.element.className = "heap-snapshot-summary"; + this.countsSummaryBar.calculator = new WebInspector.HeapSummaryCountCalculator(); + var countsLabel = document.createElement("div"); + countsLabel.className = "heap-snapshot-summary-label"; + countsLabel.textContent = WebInspector.UIString("Count"); + this.countsSummaryBar.element.appendChild(countsLabel); + summaryContainer.appendChild(this.countsSummaryBar.element); + + this.sizesSummaryBar = new WebInspector.SummaryBar(this.categories); + this.sizesSummaryBar.element.className = "heap-snapshot-summary"; + this.sizesSummaryBar.calculator = new WebInspector.HeapSummarySizeCalculator(); + var sizesLabel = document.createElement("label"); + sizesLabel.className = "heap-snapshot-summary-label"; + sizesLabel.textContent = WebInspector.UIString("Size"); + this.sizesSummaryBar.element.appendChild(sizesLabel); + summaryContainer.appendChild(this.sizesSummaryBar.element); + + this.element.appendChild(summaryContainer); + + var columns = { "cons": { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true }, + "count": { title: WebInspector.UIString("Count"), width: "54px", sortable: true }, + "size": { title: WebInspector.UIString("Size"), width: "72px", sort: "descending", sortable: true }, + "countDelta": { title: WebInspector.UIString("\xb1 Count"), width: "72px", sortable: true }, + "sizeDelta": { title: WebInspector.UIString("\xb1 Size"), width: "72px", sortable: true } }; + + this.dataGrid = new WebInspector.DataGrid(columns); + this.dataGrid.addEventListener("sorting changed", this._sortData, this); + this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true); + this.element.appendChild(this.dataGrid.element); + + this.profile = profile; + + this.baseSelectElement = document.createElement("select"); + this.baseSelectElement.className = "status-bar-item"; + this.baseSelectElement.addEventListener("change", this._changeBase.bind(this), false); + this._updateBaseOptions(); + if (this.profile.listIndex > 0) + this.baseSelectElement.selectedIndex = this.profile.listIndex - 1; + else + this.baseSelectElement.selectedIndex = this.profile.listIndex; + this._resetDataGridList(); + + this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item status-bar-item"); + this.percentButton.addEventListener("click", this._percentClicked.bind(this), false); + + this.refresh(); + + this._updatePercentButton(); +}; + +WebInspector.HeapSnapshotView.prototype = { + + get statusBarItems() + { + return [this.baseSelectElement, this.percentButton.element]; + }, + + get profile() + { + return this._profile; + }, + + set profile(profile) + { + this._profile = profile; + }, + + show: function(parentElement) + { + WebInspector.View.prototype.show.call(this, parentElement); + this.dataGrid.updateWidths(); + }, + + hide: function() + { + WebInspector.View.prototype.hide.call(this); + this._currentSearchResultIndex = -1; + }, + + resize: function() + { + if (this.dataGrid) + this.dataGrid.updateWidths(); + }, + + refresh: function() + { + this.dataGrid.removeChildren(); + + var children = this.snapshotDataGridList.children; + var count = children.length; + for (var index = 0; index < count; ++index) + this.dataGrid.appendChild(children[index]); + + this._updateSummaryGraph(); + }, + + refreshShowAsPercents: function() + { + this._updatePercentButton(); + this.refreshVisibleData(); + }, + + _deleteSearchMatchedFlags: function(node) + { + delete node._searchMatchedConsColumn; + delete node._searchMatchedCountColumn; + delete node._searchMatchedSizeColumn; + delete node._searchMatchedCountDeltaColumn; + delete node._searchMatchedSizeDeltaColumn; + }, + + searchCanceled: function() + { + if (this._searchResults) { + for (var i = 0; i < this._searchResults.length; ++i) { + var profileNode = this._searchResults[i].profileNode; + this._deleteSearchMatchedFlags(profileNode); + profileNode.refresh(); + } + } + + delete this._searchFinishedCallback; + this._currentSearchResultIndex = -1; + this._searchResults = []; + }, + + performSearch: function(query, finishedCallback) + { + // Call searchCanceled since it will reset everything we need before doing a new search. + this.searchCanceled(); + + query = query.trimWhitespace(); + + if (!query.length) + return; + + this._searchFinishedCallback = finishedCallback; + + var helper = WebInspector.HeapSnapshotView.SearchHelper; + + var operationAndNumber = helper.parseOperationAndNumber(query); + var operation = operationAndNumber[0]; + var queryNumber = operationAndNumber[1]; + + var percentUnits = helper.percents.test(query); + var megaBytesUnits = helper.megaBytes.test(query); + var kiloBytesUnits = helper.kiloBytes.test(query); + var bytesUnits = helper.bytes.test(query); + + var queryNumberBytes = (megaBytesUnits ? (queryNumber * 1024 * 1024) : (kiloBytesUnits ? (queryNumber * 1024) : queryNumber)); + + function matchesQuery(heapSnapshotDataGridNode) + { + WebInspector.HeapSnapshotView.prototype._deleteSearchMatchedFlags(heapSnapshotDataGridNode); + + if (percentUnits) { + heapSnapshotDataGridNode._searchMatchedCountColumn = operation(heapSnapshotDataGridNode.countPercent, queryNumber); + heapSnapshotDataGridNode._searchMatchedSizeColumn = operation(heapSnapshotDataGridNode.sizePercent, queryNumber); + heapSnapshotDataGridNode._searchMatchedCountDeltaColumn = operation(heapSnapshotDataGridNode.countDeltaPercent, queryNumber); + heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn = operation(heapSnapshotDataGridNode.sizeDeltaPercent, queryNumber); + } else if (megaBytesUnits || kiloBytesUnits || bytesUnits) { + heapSnapshotDataGridNode._searchMatchedSizeColumn = operation(heapSnapshotDataGridNode.size, queryNumberBytes); + heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn = operation(heapSnapshotDataGridNode.sizeDelta, queryNumberBytes); + } else { + heapSnapshotDataGridNode._searchMatchedCountColumn = operation(heapSnapshotDataGridNode.count, queryNumber); + heapSnapshotDataGridNode._searchMatchedCountDeltaColumn = operation(heapSnapshotDataGridNode.countDelta, queryNumber); + } + + if (heapSnapshotDataGridNode.constructorName.hasSubstring(query, true)) + heapSnapshotDataGridNode._searchMatchedConsColumn = true; + + if (heapSnapshotDataGridNode._searchMatchedConsColumn || + heapSnapshotDataGridNode._searchMatchedCountColumn || + heapSnapshotDataGridNode._searchMatchedSizeColumn || + heapSnapshotDataGridNode._searchMatchedCountDeltaColumn || + heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn) { + heapSnapshotDataGridNode.refresh(); + return true; + } + + return false; + } + + var current = this.snapshotDataGridList.children[0]; + var depth = 0; + var info = {}; + + // The second and subsequent levels of heap snapshot nodes represent retainers, + // so recursive expansion will be infinite, since a graph is being traversed. + // So default to a recursion cap of 2 levels. + var maxDepth = 2; + + while (current) { + if (matchesQuery(current)) + this._searchResults.push({ profileNode: current }); + current = current.traverseNextNode(false, null, (depth >= maxDepth), info); + depth += info.depthChange; + } + + finishedCallback(this, this._searchResults.length); + }, + + jumpToFirstSearchResult: WebInspector.CPUProfileView.prototype.jumpToFirstSearchResult, + jumpToLastSearchResult: WebInspector.CPUProfileView.prototype.jumpToLastSearchResult, + jumpToNextSearchResult: WebInspector.CPUProfileView.prototype.jumpToNextSearchResult, + jumpToPreviousSearchResult: WebInspector.CPUProfileView.prototype.jumpToPreviousSearchResult, + showingFirstSearchResult: WebInspector.CPUProfileView.prototype.showingFirstSearchResult, + showingLastSearchResult: WebInspector.CPUProfileView.prototype.showingLastSearchResult, + _jumpToSearchResult: WebInspector.CPUProfileView.prototype._jumpToSearchResult, + + refreshVisibleData: function() + { + var child = this.dataGrid.children[0]; + while (child) { + child.refresh(); + child = child.traverseNextNode(false, null, true); + } + this._updateSummaryGraph(); + }, + + _changeBase: function() { + if (this.baseSnapshot === WebInspector.HeapSnapshotProfileType.snapshots[this.baseSelectElement.selectedIndex]) + return; + + this._resetDataGridList(); + this.refresh(); + + if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults) + return; + + // The current search needs to be performed again. First negate out previous match + // count by calling the search finished callback with a negative number of matches. + // Then perform the search again with the same query and callback. + this._searchFinishedCallback(this, -this._searchResults.length); + this.performSearch(this.currentQuery, this._searchFinishedCallback); + }, + + _createSnapshotDataGridList: function() + { + if (this._snapshotDataGridList) + delete this._snapshotDataGridList; + + this._snapshotDataGridList = new WebInspector.HeapSnapshotDataGridList(this, this.baseSnapshot.entries, this.profile.entries); + return this._snapshotDataGridList; + }, + + _mouseDownInDataGrid: function(event) + { + if (event.detail < 2) + return; + + var cell = event.target.enclosingNodeOrSelfWithNodeName("td"); + if (!cell || (!cell.hasStyleClass("count-column") && !cell.hasStyleClass("size-column") && !cell.hasStyleClass("countDelta-column") && !cell.hasStyleClass("sizeDelta-column"))) + return; + + if (cell.hasStyleClass("count-column")) + this.showCountAsPercent = !this.showCountAsPercent; + else if (cell.hasStyleClass("size-column")) + this.showSizeAsPercent = !this.showSizeAsPercent; + else if (cell.hasStyleClass("countDelta-column")) + this.showCountDeltaAsPercent = !this.showCountDeltaAsPercent; + else if (cell.hasStyleClass("sizeDelta-column")) + this.showSizeDeltaAsPercent = !this.showSizeDeltaAsPercent; + + this.refreshShowAsPercents(); + + event.preventDefault(); + event.stopPropagation(); + }, + + get _isShowingAsPercent() + { + return this.showCountAsPercent && this.showSizeAsPercent && this.showCountDeltaAsPercent && this.showSizeDeltaAsPercent; + }, + + _percentClicked: function(event) + { + var currentState = this._isShowingAsPercent; + this.showCountAsPercent = !currentState; + this.showSizeAsPercent = !currentState; + this.showCountDeltaAsPercent = !currentState; + this.showSizeDeltaAsPercent = !currentState; + this.refreshShowAsPercents(); + }, + + _resetDataGridList: function() + { + this.baseSnapshot = WebInspector.HeapSnapshotProfileType.snapshots[this.baseSelectElement.selectedIndex]; + var lastComparator = WebInspector.HeapSnapshotDataGridList.propertyComparator("size", false); + if (this.snapshotDataGridList) + lastComparator = this.snapshotDataGridList.lastComparator; + this.snapshotDataGridList = this._createSnapshotDataGridList(); + this.snapshotDataGridList.sort(lastComparator, true); + }, + + _sortData: function() + { + var sortAscending = this.dataGrid.sortOrder === "ascending"; + var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; + var sortProperty = { + "cons": ["constructorName", null], + "count": ["count", null], + "size": ["size", "count"], + "countDelta": this.showCountDeltaAsPercent ? ["countDeltaPercent", null] : ["countDelta", null], + "sizeDelta": this.showSizeDeltaAsPercent ? ["sizeDeltaPercent", "countDeltaPercent"] : ["sizeDelta", "sizeDeltaPercent"] + }[sortColumnIdentifier]; + + this.snapshotDataGridList.sort(WebInspector.HeapSnapshotDataGridList.propertyComparator(sortProperty[0], sortProperty[1], sortAscending)); + + this.refresh(); + }, + + _updateBaseOptions: function() + { + var list = WebInspector.HeapSnapshotProfileType.snapshots; + // We're assuming that snapshots can only be added. + if (this.baseSelectElement.length === list.length) + return; + + for (var i = this.baseSelectElement.length, n = list.length; i < n; ++i) { + var baseOption = document.createElement("option"); + baseOption.label = WebInspector.UIString("Compared to %s", list[i].title); + this.baseSelectElement.appendChild(baseOption); + } + }, + + _updatePercentButton: function() + { + if (this._isShowingAsPercent) { + this.percentButton.title = WebInspector.UIString("Show absolute counts and sizes."); + this.percentButton.toggled = true; + } else { + this.percentButton.title = WebInspector.UIString("Show counts and sizes as percentages."); + this.percentButton.toggled = false; + } + }, + + _updateSummaryGraph: function() + { + this.countsSummaryBar.calculator.showAsPercent = this._isShowingAsPercent; + this.countsSummaryBar.update(this.profile.lowlevels); + + this.sizesSummaryBar.calculator.showAsPercent = this._isShowingAsPercent; + this.sizesSummaryBar.update(this.profile.lowlevels); + } +}; + +WebInspector.HeapSnapshotView.prototype.__proto__ = WebInspector.View.prototype; + +WebInspector.HeapSnapshotView.SearchHelper = { + // In comparators, we assume that a value from a node is passed as the first parameter. + operations: { LESS: function (a, b) { return a !== null && a < b; }, + LESS_OR_EQUAL: function (a, b) { return a !== null && a <= b; }, + EQUAL: function (a, b) { return a !== null && a === b; }, + GREATER_OR_EQUAL: function (a, b) { return a !== null && a >= b; }, + GREATER: function (a, b) { return a !== null && a > b; } }, + + operationParsers: { LESS: /^<(\d+)/, + LESS_OR_EQUAL: /^<=(\d+)/, + GREATER_OR_EQUAL: /^>=(\d+)/, + GREATER: /^>(\d+)/ }, + + parseOperationAndNumber: function(query) + { + var operations = WebInspector.HeapSnapshotView.SearchHelper.operations; + var parsers = WebInspector.HeapSnapshotView.SearchHelper.operationParsers; + for (var operation in parsers) { + var match = query.match(parsers[operation]); + if (match !== null) + return [operations[operation], parseFloat(match[1])]; + } + return [operations.EQUAL, parseFloat(query)]; + }, + + percents: /%$/, + + megaBytes: /MB$/i, + + kiloBytes: /KB$/i, + + bytes: /B$/i +} + +WebInspector.HeapSummaryCalculator = function(lowLevelField) +{ + this.total = 1; + this.lowLevelField = lowLevelField; +} + +WebInspector.HeapSummaryCalculator.prototype = { + computeSummaryValues: function(lowLevels) + { + var highLevels = {data: 0, code: 0}; + this.total = 0; + for (var item in lowLevels) { + var highItem = this._highFromLow(item); + if (highItem) { + var value = lowLevels[item][this.lowLevelField]; + highLevels[highItem] += value; + this.total += value; + } + } + var result = {categoryValues: highLevels}; + if (!this.showAsPercent) + result.total = this.total; + return result; + }, + + formatValue: function(value) + { + if (this.showAsPercent) + return WebInspector.UIString("%.2f%%", value / this.total * 100.0); + else + return this._valueToString(value); + }, + + get showAsPercent() + { + return this._showAsPercent; + }, + + set showAsPercent(x) + { + this._showAsPercent = x; + } +} + +WebInspector.HeapSummaryCountCalculator = function() +{ + WebInspector.HeapSummaryCalculator.call(this, "count"); +} + +WebInspector.HeapSummaryCountCalculator.prototype = { + _highFromLow: function(type) { + if (type === "CODE_TYPE" || type === "SHARED_FUNCTION_INFO_TYPE" || type === "SCRIPT_TYPE") return "code"; + if (type === "STRING_TYPE" || type === "HEAP_NUMBER_TYPE" || type.match(/^JS_/)) return "data"; + return null; + }, + + _valueToString: function(value) { + return value.toString(); + } +} + +WebInspector.HeapSummaryCountCalculator.prototype.__proto__ = WebInspector.HeapSummaryCalculator.prototype; + +WebInspector.HeapSummarySizeCalculator = function() +{ + WebInspector.HeapSummaryCalculator.call(this, "size"); +} + +WebInspector.HeapSummarySizeCalculator.prototype = { + _highFromLow: function(type) { + if (type === "CODE_TYPE" || type === "SHARED_FUNCTION_INFO_TYPE" || type === "SCRIPT_TYPE") return "code"; + if (type === "STRING_TYPE" || type === "HEAP_NUMBER_TYPE" || type.match(/^JS_/) || type.match(/_ARRAY_TYPE$/)) return "data"; + return null; + }, + + _valueToString: Number.bytesToString +} + +WebInspector.HeapSummarySizeCalculator.prototype.__proto__ = WebInspector.HeapSummaryCalculator.prototype; + +WebInspector.HeapSnapshotSidebarTreeElement = function(snapshot) +{ + this.profile = snapshot; + + WebInspector.SidebarTreeElement.call(this, "heap-snapshot-sidebar-tree-item", "", "", snapshot, false); + + this.refreshTitles(); +}; + +WebInspector.HeapSnapshotSidebarTreeElement.prototype = { + get mainTitle() + { + if (this._mainTitle) + return this._mainTitle; + return this.profile.title; + }, + + set mainTitle(x) + { + this._mainTitle = x; + this.refreshTitles(); + } +}; + +WebInspector.HeapSnapshotSidebarTreeElement.prototype.__proto__ = WebInspector.ProfileSidebarTreeElement.prototype; + +WebInspector.HeapSnapshotDataGridNodeWithRetainers = function(owningTree) +{ + this.tree = owningTree; + + WebInspector.DataGridNode.call(this, null, this._hasRetainers); + + this.addEventListener("populate", this._populate, this); +}; + +WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype = { + isEmptySet: function(set) + { + for (var x in set) + return false; + return true; + }, + + get _hasRetainers() + { + return !this.isEmptySet(this.retainers); + }, + + get _parent() + { + // For top-level nodes, return owning tree as a parent, not data grid. + return this.parent !== this.dataGrid ? this.parent : this.tree; + }, + + _populate: function(event) + { + var self = this; + this.produceDiff(this.baseRetainers, this.retainers, function(baseItem, snapshotItem) { + self.appendChild(new WebInspector.HeapSnapshotDataGridRetainerNode(self.snapshotView, baseItem, snapshotItem, self.tree)); + }); + + if (this._parent) { + var currentComparator = this._parent.lastComparator; + if (currentComparator) + this.sort(currentComparator, true); + } + + this.removeEventListener("populate", this._populate, this); + }, + + produceDiff: function(baseEntries, currentEntries, callback) + { + for (var item in currentEntries) + callback(baseEntries[item], currentEntries[item]); + + for (item in baseEntries) { + if (!(item in currentEntries)) + callback(baseEntries[item], null); + } + }, + + sort: function(comparator, force) { + if (!force && this.lastComparator === comparator) + return; + + this.children.sort(comparator); + var childCount = this.children.length; + for (var childIndex = 0; childIndex < childCount; ++childIndex) + this.children[childIndex]._recalculateSiblings(childIndex); + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i]; + if (!force && (!child.expanded || child.lastComparator === comparator)) + continue; + child.sort(comparator, force); + } + this.lastComparator = comparator; + }, + + signForDelta: function(delta) { + if (delta === 0) + return ""; + if (delta > 0) + return "+"; + else + // Math minus sign, same width as plus. + return "\u2212"; + }, + + showDeltaAsPercent: function(value) { + if (value === Number.POSITIVE_INFINITY) + return WebInspector.UIString("new"); + else if (value === Number.NEGATIVE_INFINITY) + return WebInspector.UIString("deleted"); + if (value > 1000.0) + return WebInspector.UIString("%s >1000%%", this.signForDelta(value)); + return WebInspector.UIString("%s%.2f%%", this.signForDelta(value), Math.abs(value)); + }, + + getTotalCount: function() { + if (!this._count) { + this._count = 0; + for (var i = 0, n = this.children.length; i < n; ++i) + this._count += this.children[i].count; + } + return this._count; + }, + + getTotalSize: function() { + if (!this._size) { + this._size = 0; + for (var i = 0, n = this.children.length; i < n; ++i) + this._size += this.children[i].size; + } + return this._size; + }, + + get countPercent() + { + return this.count / this._parent.getTotalCount() * 100.0; + }, + + get sizePercent() + { + return this.size / this._parent.getTotalSize() * 100.0; + }, + + get countDeltaPercent() + { + if (this.baseCount > 0) { + if (this.count > 0) + return this.countDelta / this.baseCount * 100.0; + else + return Number.NEGATIVE_INFINITY; + } else + return Number.POSITIVE_INFINITY; + }, + + get sizeDeltaPercent() + { + if (this.baseSize > 0) { + if (this.size > 0) + return this.sizeDelta / this.baseSize * 100.0; + else + return Number.NEGATIVE_INFINITY; + } else + return Number.POSITIVE_INFINITY; + }, + + get data() + { + var data = {}; + + data["cons"] = this.constructorName; + + if (this.snapshotView.showCountAsPercent) + data["count"] = WebInspector.UIString("%.2f%%", this.countPercent); + else + data["count"] = this.count; + + if (this.size !== null) { + if (this.snapshotView.showSizeAsPercent) + data["size"] = WebInspector.UIString("%.2f%%", this.sizePercent); + else + data["size"] = Number.bytesToString(this.size); + } else + data["size"] = ""; + + if (this.snapshotView.showCountDeltaAsPercent) + data["countDelta"] = this.showDeltaAsPercent(this.countDeltaPercent); + else + data["countDelta"] = WebInspector.UIString("%s%d", this.signForDelta(this.countDelta), Math.abs(this.countDelta)); + + if (this.sizeDelta !== null) { + if (this.snapshotView.showSizeDeltaAsPercent) + data["sizeDelta"] = this.showDeltaAsPercent(this.sizeDeltaPercent); + else + data["sizeDelta"] = WebInspector.UIString("%s%s", this.signForDelta(this.sizeDelta), Number.bytesToString(Math.abs(this.sizeDelta))); + } else + data["sizeDelta"] = ""; + + return data; + }, + + createCell: function(columnIdentifier) + { + var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier); + + if ((columnIdentifier === "cons" && this._searchMatchedConsColumn) || + (columnIdentifier === "count" && this._searchMatchedCountColumn) || + (columnIdentifier === "size" && this._searchMatchedSizeColumn) || + (columnIdentifier === "countDelta" && this._searchMatchedCountDeltaColumn) || + (columnIdentifier === "sizeDelta" && this._searchMatchedSizeDeltaColumn)) + cell.addStyleClass("highlight"); + + return cell; + } +}; + +WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.__proto__ = WebInspector.DataGridNode.prototype; + +WebInspector.HeapSnapshotDataGridNode = function(snapshotView, baseEntry, snapshotEntry, owningTree) +{ + this.snapshotView = snapshotView; + + if (!snapshotEntry) + snapshotEntry = { cons: baseEntry.cons, count: 0, size: 0, retainers: {} }; + this.constructorName = snapshotEntry.cons; + this.count = snapshotEntry.count; + this.size = snapshotEntry.size; + this.retainers = snapshotEntry.retainers; + + if (!baseEntry) + baseEntry = { count: 0, size: 0, retainers: {} }; + this.baseCount = baseEntry.count; + this.countDelta = this.count - this.baseCount; + this.baseSize = baseEntry.size; + this.sizeDelta = this.size - this.baseSize; + this.baseRetainers = baseEntry.retainers; + + WebInspector.HeapSnapshotDataGridNodeWithRetainers.call(this, owningTree); +}; + +WebInspector.HeapSnapshotDataGridNode.prototype.__proto__ = WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype; + +WebInspector.HeapSnapshotDataGridList = function(snapshotView, baseEntries, snapshotEntries) +{ + this.tree = this; + this.snapshotView = snapshotView; + this.children = []; + this.lastComparator = null; + this.populateChildren(baseEntries, snapshotEntries); +}; + +WebInspector.HeapSnapshotDataGridList.prototype = { + appendChild: function(child) + { + this.insertChild(child, this.children.length); + }, + + insertChild: function(child, index) + { + this.children.splice(index, 0, child); + }, + + removeChildren: function() + { + this.children = []; + }, + + populateChildren: function(baseEntries, snapshotEntries) + { + var self = this; + this.produceDiff(baseEntries, snapshotEntries, function(baseItem, snapshotItem) { + self.appendChild(new WebInspector.HeapSnapshotDataGridNode(self.snapshotView, baseItem, snapshotItem, self)); + }); + }, + + produceDiff: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.produceDiff, + sort: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.sort, + getTotalCount: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalCount, + getTotalSize: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalSize +}; + +WebInspector.HeapSnapshotDataGridList.propertyComparators = [{}, {}]; + +WebInspector.HeapSnapshotDataGridList.propertyComparator = function(property, property2, isAscending) +{ + var propertyHash = property + "#" + property2; + var comparator = this.propertyComparators[(isAscending ? 1 : 0)][propertyHash]; + if (!comparator) { + comparator = function(lhs, rhs) { + var l = lhs[property], r = rhs[property]; + if ((l === null || r === null) && property2 !== null) + l = lhs[property2], r = rhs[property2]; + var result = l < r ? -1 : (l > r ? 1 : 0); + return isAscending ? result : -result; + }; + this.propertyComparators[(isAscending ? 1 : 0)][propertyHash] = comparator; + } + return comparator; +}; + +WebInspector.HeapSnapshotDataGridRetainerNode = function(snapshotView, baseEntry, snapshotEntry, owningTree) +{ + this.snapshotView = snapshotView; + + if (!snapshotEntry) + snapshotEntry = { cons: baseEntry.cons, count: 0, clusters: {} }; + this.constructorName = snapshotEntry.cons; + this.count = snapshotEntry.count; + this.retainers = this._calculateRetainers(this.snapshotView.profile, snapshotEntry.clusters); + + if (!baseEntry) + baseEntry = { count: 0, clusters: {} }; + this.baseCount = baseEntry.count; + this.countDelta = this.count - this.baseCount; + this.baseRetainers = this._calculateRetainers(this.snapshotView.baseSnapshot, baseEntry.clusters); + + this.size = null; + this.sizeDelta = null; + + WebInspector.HeapSnapshotDataGridNodeWithRetainers.call(this, owningTree); +} + +WebInspector.HeapSnapshotDataGridRetainerNode.prototype = { + get sizePercent() + { + return null; + }, + + get sizeDeltaPercent() + { + return null; + }, + + _calculateRetainers: function(snapshot, clusters) { + var retainers = {}; + if (this.isEmptySet(clusters)) { + if (this.constructorName in snapshot.entries) + return snapshot.entries[this.constructorName].retainers; + } else { + // In case when an entry is retained by clusters, we need to gather up the list + // of retainers by merging retainers of every cluster. + // E.g. having such a tree: + // A + // Object:1 10 + // X 3 + // Y 4 + // Object:2 5 + // X 6 + // + // will result in a following retainers list: X 9, Y 4. + for (var clusterName in clusters) { + if (clusterName in snapshot.clusters) { + var clusterRetainers = snapshot.clusters[clusterName].retainers; + for (var clusterRetainer in clusterRetainers) { + var clusterRetainerEntry = clusterRetainers[clusterRetainer]; + if (!(clusterRetainer in retainers)) + retainers[clusterRetainer] = { cons: clusterRetainerEntry.cons, count: 0, clusters: {} }; + retainers[clusterRetainer].count += clusterRetainerEntry.count; + for (var clusterRetainerCluster in clusterRetainerEntry.clusters) + retainers[clusterRetainer].clusters[clusterRetainerCluster] = true; + } + } + } + } + return retainers; + } +}; + +WebInspector.HeapSnapshotDataGridRetainerNode.prototype.__proto__ = WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype; + + +WebInspector.HeapSnapshotProfileType = function() +{ + WebInspector.ProfileType.call(this, WebInspector.HeapSnapshotProfileType.TypeId, WebInspector.UIString("HEAP SNAPSHOTS")); +} + +WebInspector.HeapSnapshotProfileType.TypeId = "HEAP"; + +WebInspector.HeapSnapshotProfileType.snapshots = []; + +WebInspector.HeapSnapshotProfileType.prototype = { + get buttonTooltip() + { + return WebInspector.UIString("Take heap snapshot."); + }, + + get buttonStyle() + { + return "heap-snapshot-status-bar-item status-bar-item"; + }, + + buttonClicked: function() + { + InspectorBackend.takeHeapSnapshot(); + }, + + get welcomeMessage() + { + return WebInspector.UIString("Get a heap snapshot by pressing<br>the %s button on the status bar."); + }, + + createSidebarTreeElementForProfile: function(profile) + { + var element = new WebInspector.HeapSnapshotSidebarTreeElement(profile); + element.small = false; + return element; + }, + + createView: function(profile) + { + return new WebInspector.HeapSnapshotView(WebInspector.panels.profiles, profile); + } +} + +WebInspector.HeapSnapshotProfileType.prototype.__proto__ = WebInspector.ProfileType.prototype; + + +(function() { + var originalCreatePanels = WebInspector._createPanels; + WebInspector._createPanels = function() { + originalCreatePanels.apply(this, arguments); + if (WebInspector.panels.profiles) + WebInspector.panels.profiles.registerProfileType(new WebInspector.HeapSnapshotProfileType()); + } +})(); diff --git a/WebKit/chromium/src/js/Images/segmentChromium.png b/WebKit/chromium/src/js/Images/segmentChromium.png Binary files differnew file mode 100755 index 0000000..607559b --- /dev/null +++ b/WebKit/chromium/src/js/Images/segmentChromium.png diff --git a/WebKit/chromium/src/js/Images/segmentHoverChromium.png b/WebKit/chromium/src/js/Images/segmentHoverChromium.png Binary files differnew file mode 100755 index 0000000..0a743d9 --- /dev/null +++ b/WebKit/chromium/src/js/Images/segmentHoverChromium.png diff --git a/WebKit/chromium/src/js/Images/segmentHoverEndChromium.png b/WebKit/chromium/src/js/Images/segmentHoverEndChromium.png Binary files differnew file mode 100755 index 0000000..cf62072 --- /dev/null +++ b/WebKit/chromium/src/js/Images/segmentHoverEndChromium.png diff --git a/WebKit/chromium/src/js/Images/segmentSelectedChromium.png b/WebKit/chromium/src/js/Images/segmentSelectedChromium.png Binary files differnew file mode 100755 index 0000000..a1f7251 --- /dev/null +++ b/WebKit/chromium/src/js/Images/segmentSelectedChromium.png diff --git a/WebKit/chromium/src/js/Images/segmentSelectedEndChromium.png b/WebKit/chromium/src/js/Images/segmentSelectedEndChromium.png Binary files differnew file mode 100755 index 0000000..07641db --- /dev/null +++ b/WebKit/chromium/src/js/Images/segmentSelectedEndChromium.png diff --git a/WebKit/chromium/src/js/Images/statusbarBackgroundChromium.png b/WebKit/chromium/src/js/Images/statusbarBackgroundChromium.png Binary files differnew file mode 100755 index 0000000..9d326ac --- /dev/null +++ b/WebKit/chromium/src/js/Images/statusbarBackgroundChromium.png diff --git a/WebKit/chromium/src/js/Images/statusbarBottomBackgroundChromium.png b/WebKit/chromium/src/js/Images/statusbarBottomBackgroundChromium.png Binary files differnew file mode 100755 index 0000000..7c7db0a --- /dev/null +++ b/WebKit/chromium/src/js/Images/statusbarBottomBackgroundChromium.png diff --git a/WebKit/chromium/src/js/Images/statusbarButtonsChromium.png b/WebKit/chromium/src/js/Images/statusbarButtonsChromium.png Binary files differnew file mode 100755 index 0000000..0c6635d --- /dev/null +++ b/WebKit/chromium/src/js/Images/statusbarButtonsChromium.png diff --git a/WebKit/chromium/src/js/Images/statusbarMenuButtonChromium.png b/WebKit/chromium/src/js/Images/statusbarMenuButtonChromium.png Binary files differnew file mode 100755 index 0000000..bf26684 --- /dev/null +++ b/WebKit/chromium/src/js/Images/statusbarMenuButtonChromium.png diff --git a/WebKit/chromium/src/js/Images/statusbarMenuButtonSelectedChromium.png b/WebKit/chromium/src/js/Images/statusbarMenuButtonSelectedChromium.png Binary files differnew file mode 100755 index 0000000..3c0aeec --- /dev/null +++ b/WebKit/chromium/src/js/Images/statusbarMenuButtonSelectedChromium.png diff --git a/WebKit/chromium/src/js/InjectDispatch.js b/WebKit/chromium/src/js/InjectDispatch.js new file mode 100644 index 0000000..e070c42 --- /dev/null +++ b/WebKit/chromium/src/js/InjectDispatch.js @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @fileoverview Injects "injected" object into the inspectable page. + */ + + +var InspectorControllerDispatcher = {}; + +/** + * Main dispatch method, all calls from the host to InspectorController go + * through this one. + * @param {string} functionName Function to call + * @param {string} json_args JSON-serialized call parameters. + * @return {string} JSON-serialized result of the dispatched call. + */ +InspectorControllerDispatcher.dispatch = function(functionName, json_args) +{ + var params = JSON.parse(json_args); + InspectorBackend[functionName].apply(InspectorBackend, params); +}; + +/** + * Special controller object for APU related messages. Outgoing messages + * are sent to this object if the ApuAgentDispatcher is enabled. + **/ +var ApuAgentDispatcher = { enabled : false }; + +/** + * Dispatches messages to APU. This filters and transforms + * outgoing messages that are used by APU. + * @param {string} method name of the dispatch method. + **/ +ApuAgentDispatcher.dispatchToApu = function(method, args) +{ + if (method !== "addRecordToTimeline" && method !== "updateResource" && method !== "addResource") + return; + // TODO(knorton): Transform args so they can be used + // by APU. + DevToolsAgentHost.dispatchToApu(JSON.stringify(args)); +}; + +/** + * This is called by the InspectorFrontend for serialization. + * We serialize the call and send it to the client over the IPC + * using dispatchOut bound method. + */ +function dispatch(method, var_args) { + // Handle all messages with non-primitieve arguments here. + var args = Array.prototype.slice.call(arguments); + + if (method === "inspectedWindowCleared" || method === "reset" || method === "setAttachedWindow") { + // Filter out messages we don't need here. + // We do it on the sender side since they may have non-serializable + // parameters. + return; + } + + // Sniff some inspector controller state changes in order to support + // cross-navigation instrumentation. Keep names in sync with + // webdevtoolsagent_impl. + if (method === "timelineProfilerWasStarted") + DevToolsAgentHost.runtimeFeatureStateChanged("timeline-profiler", true); + else if (method === "timelineProfilerWasStopped") + DevToolsAgentHost.runtimeFeatureStateChanged("timeline-profiler", false); + else if (method === "resourceTrackingWasEnabled") + DevToolsAgentHost.runtimeFeatureStateChanged("resource-tracking", true); + else if (method === "resourceTrackingWasDisabled") + DevToolsAgentHost.runtimeFeatureStateChanged("resource-tracking", false); + + if (ApuAgentDispatcher.enabled) { + ApuAgentDispatcher.dispatchToApu(method, args); + return; + } + + var call = JSON.stringify(args); + DevToolsAgentHost.dispatch(call); +}; diff --git a/WebKit/chromium/src/js/InspectorControllerImpl.js b/WebKit/chromium/src/js/InspectorControllerImpl.js new file mode 100644 index 0000000..c92a94c --- /dev/null +++ b/WebKit/chromium/src/js/InspectorControllerImpl.js @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @fileoverview DevTools' implementation of the InspectorController API. + */ + +if (!this.devtools) + devtools = {}; + +devtools.InspectorBackendImpl = function() +{ + WebInspector.InspectorBackendStub.call(this); + this.installInspectorControllerDelegate_("clearMessages"); + this.installInspectorControllerDelegate_("copyNode"); + this.installInspectorControllerDelegate_("deleteCookie"); + this.installInspectorControllerDelegate_("didEvaluateForTestInFrontend"); + this.installInspectorControllerDelegate_("disableResourceTracking"); + this.installInspectorControllerDelegate_("disableTimeline"); + this.installInspectorControllerDelegate_("enableResourceTracking"); + this.installInspectorControllerDelegate_("enableTimeline"); + this.installInspectorControllerDelegate_("getChildNodes"); + this.installInspectorControllerDelegate_("getCookies"); + this.installInspectorControllerDelegate_("getDatabaseTableNames"); + this.installInspectorControllerDelegate_("getDOMStorageEntries"); + this.installInspectorControllerDelegate_("getEventListenersForNode"); + this.installInspectorControllerDelegate_("getResourceContent"); + this.installInspectorControllerDelegate_("highlightDOMNode"); + this.installInspectorControllerDelegate_("hideDOMNodeHighlight"); + this.installInspectorControllerDelegate_("releaseWrapperObjectGroup"); + this.installInspectorControllerDelegate_("removeAttribute"); + this.installInspectorControllerDelegate_("removeDOMStorageItem"); + this.installInspectorControllerDelegate_("removeNode"); + this.installInspectorControllerDelegate_("saveFrontendSettings"); + this.installInspectorControllerDelegate_("setAttribute"); + this.installInspectorControllerDelegate_("setDOMStorageItem"); + this.installInspectorControllerDelegate_("setInjectedScriptSource"); + this.installInspectorControllerDelegate_("setTextNodeValue"); + this.installInspectorControllerDelegate_("startTimelineProfiler"); + this.installInspectorControllerDelegate_("stopTimelineProfiler"); + this.installInspectorControllerDelegate_("storeLastActivePanel"); +}; +devtools.InspectorBackendImpl.prototype.__proto__ = WebInspector.InspectorBackendStub.prototype; + + +/** + * {@inheritDoc}. + */ +devtools.InspectorBackendImpl.prototype.toggleNodeSearch = function() +{ + WebInspector.InspectorBackendStub.prototype.toggleNodeSearch.call(this); + this.callInspectorController_.call(this, "toggleNodeSearch"); + if (!this.searchingForNode()) { + // This is called from ElementsPanel treeOutline's focusNodeChanged(). + DevToolsHost.activateWindow(); + } +}; + + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.debuggerEnabled = function() +{ + return true; +}; + + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.profilerEnabled = function() +{ + return true; +}; + + +devtools.InspectorBackendImpl.prototype.addBreakpoint = function(sourceID, line, condition) +{ + devtools.tools.getDebuggerAgent().addBreakpoint(sourceID, line, condition); +}; + + +devtools.InspectorBackendImpl.prototype.removeBreakpoint = function(sourceID, line) +{ + devtools.tools.getDebuggerAgent().removeBreakpoint(sourceID, line); +}; + +devtools.InspectorBackendImpl.prototype.updateBreakpoint = function(sourceID, line, condition) +{ + devtools.tools.getDebuggerAgent().updateBreakpoint(sourceID, line, condition); +}; + +devtools.InspectorBackendImpl.prototype.pauseInDebugger = function() +{ + devtools.tools.getDebuggerAgent().pauseExecution(); +}; + + +devtools.InspectorBackendImpl.prototype.resumeDebugger = function() +{ + devtools.tools.getDebuggerAgent().resumeExecution(); +}; + + +devtools.InspectorBackendImpl.prototype.stepIntoStatementInDebugger = function() +{ + devtools.tools.getDebuggerAgent().stepIntoStatement(); +}; + + +devtools.InspectorBackendImpl.prototype.stepOutOfFunctionInDebugger = function() +{ + devtools.tools.getDebuggerAgent().stepOutOfFunction(); +}; + + +devtools.InspectorBackendImpl.prototype.stepOverStatementInDebugger = function() +{ + devtools.tools.getDebuggerAgent().stepOverStatement(); +}; + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.setPauseOnExceptionsState = function(state) +{ + this._setPauseOnExceptionsState = state; + // TODO(yurys): support all three states. See http://crbug.com/32877 + var enabled = (state !== WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions); + return devtools.tools.getDebuggerAgent().setPauseOnExceptions(enabled); +}; + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.pauseOnExceptionsState = function() +{ + return (this._setPauseOnExceptionsState || WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions); +}; + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.pauseOnExceptions = function() +{ + return devtools.tools.getDebuggerAgent().pauseOnExceptions(); +}; + + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.setPauseOnExceptions = function(value) +{ + return devtools.tools.getDebuggerAgent().setPauseOnExceptions(value); +}; + + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.startProfiling = function() +{ + devtools.tools.getProfilerAgent().startProfiling(devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_CPU); +}; + + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.stopProfiling = function() +{ + devtools.tools.getProfilerAgent().stopProfiling( devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_CPU); +}; + + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.getProfileHeaders = function(callId) +{ + WebInspector.didGetProfileHeaders(callId, []); +}; + + +/** + * Emulate WebKit InspectorController behavior. It stores profiles on renderer side, + * and is able to retrieve them by uid using "getProfile". + */ +devtools.InspectorBackendImpl.prototype.addFullProfile = function(profile) +{ + WebInspector.__fullProfiles = WebInspector.__fullProfiles || {}; + WebInspector.__fullProfiles[profile.uid] = profile; +}; + + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.getProfile = function(callId, uid) +{ + if (WebInspector.__fullProfiles && (uid in WebInspector.__fullProfiles)) + WebInspector.didGetProfile(callId, WebInspector.__fullProfiles[uid]); +}; + + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.takeHeapSnapshot = function() +{ + devtools.tools.getProfilerAgent().startProfiling(devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_HEAP_SNAPSHOT + | devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_HEAP_STATS + | devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_JS_CONSTRUCTORS); +}; + + +/** + * @override + */ +devtools.InspectorBackendImpl.prototype.dispatchOnInjectedScript = function(callId, injectedScriptId, methodName, argsString, async) +{ + // Encode injectedScriptId into callId + if (typeof injectedScriptId !== "number") + injectedScriptId = 0; + RemoteToolsAgent.dispatchOnInjectedScript(callId, injectedScriptId, methodName, argsString, async); +}; + + +/** + * Installs delegating handler into the inspector controller. + * @param {string} methodName Method to install delegating handler for. + */ +devtools.InspectorBackendImpl.prototype.installInspectorControllerDelegate_ = function(methodName) +{ + this[methodName] = this.callInspectorController_.bind(this, methodName); +}; + + +/** + * Bound function with the installInjectedScriptDelegate_ actual + * implementation. + */ +devtools.InspectorBackendImpl.prototype.callInspectorController_ = function(methodName, var_arg) +{ + var args = Array.prototype.slice.call(arguments, 1); + RemoteToolsAgent.dispatchOnInspectorController(WebInspector.Callback.wrap(function(){}), methodName, JSON.stringify(args)); +}; + + +InspectorBackend = new devtools.InspectorBackendImpl(); diff --git a/WebKit/chromium/src/js/ProfilerAgent.js b/WebKit/chromium/src/js/ProfilerAgent.js new file mode 100644 index 0000000..e08c5d2 --- /dev/null +++ b/WebKit/chromium/src/js/ProfilerAgent.js @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @fileoverview Provides communication interface to remote v8 profiler. + */ + +/** + * @constructor + */ +devtools.ProfilerAgent = function() +{ + RemoteProfilerAgent.didGetActiveProfilerModules = this._didGetActiveProfilerModules.bind(this); + RemoteProfilerAgent.didGetLogLines = this._didGetLogLines.bind(this); + + /** + * Active profiler modules flags. + * @type {number} + */ + this._activeProfilerModules = devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_NONE; + + /** + * Interval for polling profiler state. + * @type {number} + */ + this._getActiveProfilerModulesInterval = null; + + /** + * Profiler log position. + * @type {number} + */ + this._logPosition = 0; + + /** + * Last requested log position. + * @type {number} + */ + this._lastRequestedLogPosition = -1; + + /** + * Whether log contents retrieval must be forced next time. + * @type {boolean} + */ + this._forceGetLogLines = false; + + /** + * Profiler processor instance. + * @type {devtools.profiler.Processor} + */ + this._profilerProcessor = new devtools.profiler.Processor(); +}; + + +/** + * A copy of enum from include/v8.h + * @enum {number} + */ +devtools.ProfilerAgent.ProfilerModules = { + PROFILER_MODULE_NONE: 0, + PROFILER_MODULE_CPU: 1, + PROFILER_MODULE_HEAP_STATS: 1 << 1, + PROFILER_MODULE_JS_CONSTRUCTORS: 1 << 2, + PROFILER_MODULE_HEAP_SNAPSHOT: 1 << 16 +}; + + +/** + * Sets up callbacks that deal with profiles processing. + */ +devtools.ProfilerAgent.prototype.setupProfilerProcessorCallbacks = function() +{ + // A temporary icon indicating that the profile is being processed. + var processingIcon = new WebInspector.SidebarTreeElement( + "profile-sidebar-tree-item", + WebInspector.UIString("Processing..."), + '', null, false); + var profilesSidebar = WebInspector.panels.profiles.getProfileType(WebInspector.CPUProfileType.TypeId).treeElement; + + this._profilerProcessor.setCallbacks( + function onProfileProcessingStarted() { + // Set visually empty string. Subtitle hiding is done via styles + // manipulation which doesn't play well with dynamic append / removal. + processingIcon.subtitle = " "; + profilesSidebar.appendChild(processingIcon); + }, + function onProfileProcessingStatus(ticksCount) { + processingIcon.subtitle = WebInspector.UIString("%d ticks processed", ticksCount); + }, + function onProfileProcessingFinished(profile) { + profilesSidebar.removeChild(processingIcon); + profile.typeId = WebInspector.CPUProfileType.TypeId; + InspectorBackend.addFullProfile(profile); + WebInspector.addProfileHeader(profile); + // If no profile is currently shown, show the new one. + var profilesPanel = WebInspector.panels.profiles; + if (!profilesPanel.visibleView) { + profilesPanel.showProfile(profile); + } + } + ); +}; + + +/** + * Initializes profiling state. + */ +devtools.ProfilerAgent.prototype.initializeProfiling = function() +{ + this.setupProfilerProcessorCallbacks(); + this._forceGetLogLines = true; + this._getActiveProfilerModulesInterval = setInterval(function() { RemoteProfilerAgent.getActiveProfilerModules(); }, 1000); +}; + + +/** + * Requests the next chunk of log lines. + * @param {boolean} immediately Do not postpone the request. + * @private + */ +devtools.ProfilerAgent.prototype._getNextLogLines = function(immediately) +{ + if (this._lastRequestedLogPosition == this._logPosition) + return; + var pos = this._lastRequestedLogPosition = this._logPosition; + if (immediately) + RemoteProfilerAgent.getLogLines(pos); + else + setTimeout(function() { RemoteProfilerAgent.getLogLines(pos); }, 500); +}; + + +/** + * Starts profiling. + * @param {number} modules List of modules to enable. + */ +devtools.ProfilerAgent.prototype.startProfiling = function(modules) +{ + var cmd = new devtools.DebugCommand("profile", { + "modules": modules, + "command": "resume"}); + devtools.DebuggerAgent.sendCommand_(cmd); + RemoteDebuggerAgent.processDebugCommands(); + if (modules & devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_HEAP_SNAPSHOT) { + // Active modules will not change, instead, a snapshot will be logged. + this._getNextLogLines(); + } +}; + + +/** + * Stops profiling. + */ +devtools.ProfilerAgent.prototype.stopProfiling = function(modules) +{ + var cmd = new devtools.DebugCommand("profile", { + "modules": modules, + "command": "pause"}); + devtools.DebuggerAgent.sendCommand_(cmd); + RemoteDebuggerAgent.processDebugCommands(); +}; + + +/** + * Handles current profiler status. + * @param {number} modules List of active (started) modules. + */ +devtools.ProfilerAgent.prototype._didGetActiveProfilerModules = function(modules) +{ + var profModules = devtools.ProfilerAgent.ProfilerModules; + var profModuleNone = profModules.PROFILER_MODULE_NONE; + if (this._forceGetLogLines || (modules !== profModuleNone && this._activeProfilerModules === profModuleNone)) { + this._forceGetLogLines = false; + // Start to query log data. + this._getNextLogLines(true); + } + this._activeProfilerModules = modules; + // Update buttons. + WebInspector.setRecordingProfile(modules & profModules.PROFILER_MODULE_CPU); +}; + + +/** + * Handles a portion of a profiler log retrieved by getLogLines call. + * @param {number} pos Current position in log. + * @param {string} log A portion of profiler log. + */ +devtools.ProfilerAgent.prototype._didGetLogLines = function(pos, log) +{ + this._logPosition = pos; + if (log.length > 0) + this._profilerProcessor.processLogChunk(log); + else { + // Allow re-reading from the last position. + this._lastRequestedLogPosition = this._logPosition - 1; + if (this._activeProfilerModules === devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_NONE) + // No new data and profiling is stopped---suspend log reading. + return; + } + this._getNextLogLines(); +}; diff --git a/WebKit/chromium/src/js/ProfilerProcessor.js b/WebKit/chromium/src/js/ProfilerProcessor.js new file mode 100644 index 0000000..f678d2c --- /dev/null +++ b/WebKit/chromium/src/js/ProfilerProcessor.js @@ -0,0 +1,543 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @fileoverview Profiler processor is used to process log file produced + * by V8 and produce an internal profile representation which is used + * for building profile views in "Profiles" tab. + */ + + +/** + * Creates a Profile View builder object compatible with WebKit Profiler UI. + * + * @param {number} samplingRate Number of ms between profiler ticks. + * @constructor + */ +devtools.profiler.WebKitViewBuilder = function(samplingRate) +{ + devtools.profiler.ViewBuilder.call(this, samplingRate); +}; +devtools.profiler.WebKitViewBuilder.prototype.__proto__ = devtools.profiler.ViewBuilder.prototype; + + +/** + * @override + */ +devtools.profiler.WebKitViewBuilder.prototype.createViewNode = function(funcName, totalTime, selfTime, head) +{ + return new devtools.profiler.WebKitViewNode(funcName, totalTime, selfTime, head); +}; + + +/** + * Constructs a Profile View node object for displaying in WebKit Profiler UI. + * + * @param {string} internalFuncName A fully qualified function name. + * @param {number} totalTime Amount of time that application spent in the + * corresponding function and its descendants (not that depending on + * profile they can be either callees or callers.) + * @param {number} selfTime Amount of time that application spent in the + * corresponding function only. + * @param {devtools.profiler.ProfileView.Node} head Profile view head. + * @constructor + */ +devtools.profiler.WebKitViewNode = function(internalFuncName, totalTime, selfTime, head) +{ + devtools.profiler.ProfileView.Node.call(this, internalFuncName, totalTime, selfTime, head); + this.initFuncInfo_(); + this.callUID = internalFuncName; +}; +devtools.profiler.WebKitViewNode.prototype.__proto__ = devtools.profiler.ProfileView.Node.prototype; + + +/** + * RegEx for stripping V8's prefixes of compiled functions. + */ +devtools.profiler.WebKitViewNode.FUNC_NAME_STRIP_RE = /^(?:LazyCompile|Function|Callback): (.*)$/; + + +/** + * RegEx for extracting script source URL and line number. + */ +devtools.profiler.WebKitViewNode.FUNC_NAME_PARSE_RE = /^((?:get | set )?[^ ]+) (.*):(\d+)( \{\d+\})?$/; + + +/** + * Inits "functionName", "url", and "lineNumber" fields using "internalFuncName" + * field. + * @private + */ +devtools.profiler.WebKitViewNode.prototype.initFuncInfo_ = function() +{ + var nodeAlias = devtools.profiler.WebKitViewNode; + this.functionName = this.internalFuncName; + + var strippedName = nodeAlias.FUNC_NAME_STRIP_RE.exec(this.functionName); + if (strippedName) + this.functionName = strippedName[1]; + + var parsedName = nodeAlias.FUNC_NAME_PARSE_RE.exec(this.functionName); + if (parsedName) { + this.functionName = parsedName[1]; + if (parsedName[4]) + this.functionName += parsedName[4]; + this.url = parsedName[2]; + this.lineNumber = parsedName[3]; + } else { + this.url = ''; + this.lineNumber = 0; + } +}; + + +/** + * Ancestor of a profile object that leaves out only JS-related functions. + * @constructor + */ +devtools.profiler.JsProfile = function() +{ + devtools.profiler.Profile.call(this); +}; +devtools.profiler.JsProfile.prototype.__proto__ = devtools.profiler.Profile.prototype; + + +/** + * RegExp that leaves only non-native JS functions. + * @type {RegExp} + */ +devtools.profiler.JsProfile.JS_NON_NATIVE_RE = new RegExp( + "^" + + "(?:Callback:)|" + + "(?:Script: (?!native))|" + + "(?:(?:LazyCompile|Function): [^ ]*(?: (?!native )[^ ]+:\\d+)?$)"); + + +/** + * @override + */ +devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) +{ + return !devtools.profiler.JsProfile.JS_NON_NATIVE_RE.test(name); +}; + + +/** + * Profiler processor. Consumes profiler log and builds profile views. + * FIXME: change field naming style to use trailing underscore. + * + * @param {function(devtools.profiler.ProfileView)} newProfileCallback Callback + * that receives a new processed profile. + * @constructor + */ +devtools.profiler.Processor = function() +{ + var dispatches = { + "code-creation": { + parsers: [null, this.createAddressParser("code"), parseInt, null], + processor: this.processCodeCreation_, backrefs: true, + needsProfile: true }, + "code-move": { parsers: [this.createAddressParser("code"), + this.createAddressParser("code-move-to")], + processor: this.processCodeMove_, backrefs: true, + needsProfile: true }, + "code-delete": { parsers: [this.createAddressParser("code")], + processor: this.processCodeDelete_, backrefs: true, + needsProfile: true }, + "function-creation": { parsers: [this.createAddressParser("code"), + this.createAddressParser("function-obj")], + processor: this.processFunctionCreation_, backrefs: true }, + "function-move": { parsers: [this.createAddressParser("code"), + this.createAddressParser("code-move-to")], + processor: this.processFunctionMove_, backrefs: true }, + "function-delete": { parsers: [this.createAddressParser("code")], + processor: this.processFunctionDelete_, backrefs: true }, + "tick": { parsers: [this.createAddressParser("code"), + this.createAddressParser("stack"), parseInt, "var-args"], + processor: this.processTick_, backrefs: true, needProfile: true }, + "profiler": { parsers: [null, "var-args"], + processor: this.processProfiler_, needsProfile: false }, + "heap-sample-begin": { parsers: [null, null, parseInt], + processor: this.processHeapSampleBegin_ }, + "heap-sample-stats": { parsers: [null, null, parseInt, parseInt], + processor: this.processHeapSampleStats_ }, + "heap-sample-item": { parsers: [null, parseInt, parseInt], + processor: this.processHeapSampleItem_ }, + "heap-js-cons-item": { parsers: [null, parseInt, parseInt], + processor: this.processHeapJsConsItem_ }, + "heap-js-ret-item": { parsers: [null, "var-args"], + processor: this.processHeapJsRetItem_ }, + "heap-sample-end": { parsers: [null, null], + processor: this.processHeapSampleEnd_ }, + // Not used in DevTools Profiler. + "shared-library": null, + // Obsolete row types. + "code-allocate": null, + "begin-code-region": null, + "end-code-region": null}; + + if (devtools.profiler.Profile.VERSION === 2) { + dispatches["tick"] = { parsers: [this.createAddressParser("code"), + this.createAddressParser("stack"), + this.createAddressParser("func"), parseInt, "var-args"], + processor: this.processTickV2_, backrefs: true }; + } + + devtools.profiler.LogReader.call(this, dispatches); + + /** + * Callback that is called when a new profile is encountered in the log. + * @type {function()} + */ + this.startedProfileProcessing_ = null; + + /** + * Callback that is called periodically to display processing status. + * @type {function()} + */ + this.profileProcessingStatus_ = null; + + /** + * Callback that is called when a profile has been processed and is ready + * to be shown. + * @type {function(devtools.profiler.ProfileView)} + */ + this.finishedProfileProcessing_ = null; + + /** + * The current profile. + * @type {devtools.profiler.JsProfile} + */ + this.currentProfile_ = null; + + /** + * Builder of profile views. Created during "profiler,begin" event processing. + * @type {devtools.profiler.WebKitViewBuilder} + */ + this.viewBuilder_ = null; + + /** + * Next profile id. + * @type {number} + */ + this.profileId_ = 1; + + /** + * Counter for processed ticks. + * @type {number} + */ + this.ticksCount_ = 0; + + /** + * Interval id for updating processing status. + * @type {number} + */ + this.processingInterval_ = null; + + /** + * The current heap snapshot. + * @type {string} + */ + this.currentHeapSnapshot_ = null; + + /** + * Next heap snapshot id. + * @type {number} + */ + this.heapSnapshotId_ = 1; +}; +devtools.profiler.Processor.prototype.__proto__ = devtools.profiler.LogReader.prototype; + + +/** + * @override + */ +devtools.profiler.Processor.prototype.printError = function(str) +{ + debugPrint(str); +}; + + +/** + * @override + */ +devtools.profiler.Processor.prototype.skipDispatch = function(dispatch) +{ + return dispatch.needsProfile && this.currentProfile_ === null; +}; + + +/** + * Sets profile processing callbacks. + * + * @param {function()} started Started processing callback. + * @param {function(devtools.profiler.ProfileView)} finished Finished + * processing callback. + */ +devtools.profiler.Processor.prototype.setCallbacks = function(started, processing, finished) +{ + this.startedProfileProcessing_ = started; + this.profileProcessingStatus_ = processing; + this.finishedProfileProcessing_ = finished; +}; + + +/** + * An address for the fake "(program)" entry. WebKit's visualisation + * has assumptions on how the top of the call tree should look like, + * and we need to add a fake entry as the topmost function. This + * address is chosen because it's the end address of the first memory + * page, which is never used for code or data, but only as a guard + * page for catching AV errors. + * + * @type {number} + */ +devtools.profiler.Processor.PROGRAM_ENTRY = 0xffff; +/** + * @type {string} + */ +devtools.profiler.Processor.PROGRAM_ENTRY_STR = "0xffff"; + + +/** + * Sets new profile callback. + * @param {function(devtools.profiler.ProfileView)} callback Callback function. + */ +devtools.profiler.Processor.prototype.setNewProfileCallback = function(callback) +{ + this.newProfileCallback_ = callback; +}; + + +devtools.profiler.Processor.prototype.processProfiler_ = function(state, params) +{ + switch (state) { + case "resume": + if (this.currentProfile_ === null) { + this.currentProfile_ = new devtools.profiler.JsProfile(); + // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY + this.currentProfile_.addCode("Function", "(program)", devtools.profiler.Processor.PROGRAM_ENTRY, 1); + if (this.startedProfileProcessing_) + this.startedProfileProcessing_(); + this.ticksCount_ = 0; + var self = this; + if (this.profileProcessingStatus_) { + this.processingInterval_ = window.setInterval( + function() { self.profileProcessingStatus_(self.ticksCount_); }, + 1000); + } + } + break; + case "pause": + if (this.currentProfile_ !== null) { + window.clearInterval(this.processingInterval_); + this.processingInterval_ = null; + if (this.finishedProfileProcessing_) + this.finishedProfileProcessing_(this.createProfileForView()); + this.currentProfile_ = null; + } + break; + case "begin": + var samplingRate = NaN; + if (params.length > 0) + samplingRate = parseInt(params[0]); + if (isNaN(samplingRate)) + samplingRate = 1; + this.viewBuilder_ = new devtools.profiler.WebKitViewBuilder(samplingRate); + break; + // These events are valid but aren't used. + case "compression": + case "end": break; + default: + throw new Error("unknown profiler state: " + state); + } +}; + + +devtools.profiler.Processor.prototype.processCodeCreation_ = function(type, start, size, name) +{ + this.currentProfile_.addCode(this.expandAlias(type), name, start, size); +}; + + +devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) +{ + this.currentProfile_.moveCode(from, to); +}; + + +devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) +{ + this.currentProfile_.deleteCode(start); +}; + + +devtools.profiler.Processor.prototype.processFunctionCreation_ = function(functionAddr, codeAddr) +{ + this.currentProfile_.addCodeAlias(functionAddr, codeAddr); +}; + + +devtools.profiler.Processor.prototype.processFunctionMove_ = function(from, to) +{ + this.currentProfile_.safeMoveDynamicCode(from, to); +}; + + +devtools.profiler.Processor.prototype.processFunctionDelete_ = function(start) +{ + this.currentProfile_.safeDeleteDynamicCode(start); +}; + + +// TODO(mnaganov): Remove after next V8 roll. +devtools.profiler.Processor.prototype.processTick_ = function(pc, sp, vmState, stack) +{ + // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY + stack.push(devtools.profiler.Processor.PROGRAM_ENTRY_STR); + this.currentProfile_.recordTick(this.processStack(pc, stack)); + this.ticksCount_++; +}; + + +devtools.profiler.Processor.prototype.processTickV2_ = function(pc, sp, func, vmState, stack) +{ + // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY + stack.push(devtools.profiler.Processor.PROGRAM_ENTRY_STR); + + + if (func) { + var funcEntry = this.currentProfile_.findEntry(func); + if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction()) + func = 0; + else { + var currEntry = this.currentProfile_.findEntry(pc); + if (!currEntry || !currEntry.isJSFunction || currEntry.isJSFunction()) { + func = 0; + } + } + } + + this.currentProfile_.recordTick(this.processStack(pc, func, stack)); + this.ticksCount_++; +}; + + +devtools.profiler.Processor.prototype.processHeapSampleBegin_ = function(space, state, ticks) +{ + if (space !== "Heap") return; + this.currentHeapSnapshot_ = { + number: this.heapSnapshotId_++, + entries: {}, + clusters: {}, + lowlevels: {}, + ticks: ticks + }; +}; + + +devtools.profiler.Processor.prototype.processHeapSampleStats_ = function(space, state, capacity, used) +{ + if (space !== "Heap") return; +}; + + +devtools.profiler.Processor.prototype.processHeapSampleItem_ = function(item, number, size) +{ + if (!this.currentHeapSnapshot_) return; + this.currentHeapSnapshot_.lowlevels[item] = { + type: item, count: number, size: size + }; +}; + + +devtools.profiler.Processor.prototype.processHeapJsConsItem_ = function(item, number, size) +{ + if (!this.currentHeapSnapshot_) return; + this.currentHeapSnapshot_.entries[item] = { + cons: item, count: number, size: size, retainers: {} + }; +}; + + +devtools.profiler.Processor.prototype.processHeapJsRetItem_ = function(item, retainersArray) +{ + if (!this.currentHeapSnapshot_) return; + var rawRetainers = {}; + for (var i = 0, n = retainersArray.length; i < n; ++i) { + var entry = retainersArray[i].split(";"); + rawRetainers[entry[0]] = parseInt(entry[1], 10); + } + + function mergeRetainers(entry) { + for (var rawRetainer in rawRetainers) { + var consName = rawRetainer.indexOf(":") !== -1 ? rawRetainer.split(":")[0] : rawRetainer; + if (!(consName in entry.retainers)) + entry.retainers[consName] = { cons: consName, count: 0, clusters: {} }; + var retainer = entry.retainers[consName]; + retainer.count += rawRetainers[rawRetainer]; + if (consName !== rawRetainer) + retainer.clusters[rawRetainer] = true; + } + } + + if (item.indexOf(":") !== -1) { + // Array, Function, or Object instances cluster case. + if (!(item in this.currentHeapSnapshot_.clusters)) { + this.currentHeapSnapshot_.clusters[item] = { + cons: item, retainers: {} + }; + } + mergeRetainers(this.currentHeapSnapshot_.clusters[item]); + item = item.split(":")[0]; + } + mergeRetainers(this.currentHeapSnapshot_.entries[item]); +}; + + +devtools.profiler.Processor.prototype.processHeapSampleEnd_ = function(space, state) +{ + if (space !== "Heap") return; + var snapshot = this.currentHeapSnapshot_; + this.currentHeapSnapshot_ = null; + WebInspector.panels.profiles.addSnapshot(snapshot); +}; + + +/** + * Creates a profile for further displaying in ProfileView. + */ +devtools.profiler.Processor.prototype.createProfileForView = function() +{ + var profile = this.viewBuilder_.buildView(this.currentProfile_.getTopDownProfile()); + profile.uid = this.profileId_++; + profile.title = UserInitiatedProfileName + "." + profile.uid; + return profile; +}; diff --git a/WebKit/chromium/src/js/Tests.js b/WebKit/chromium/src/js/Tests.js new file mode 100644 index 0000000..fa0c99f --- /dev/null +++ b/WebKit/chromium/src/js/Tests.js @@ -0,0 +1,1862 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file contains small testing framework along with the + * test suite for the frontend. These tests are a part of the continues build + * and are executed by the devtools_sanity_unittest.cc as a part of the + * Interactive UI Test suite. + * FIXME: change field naming style to use trailing underscore. + */ + +if (window.domAutomationController) { + +var ___interactiveUiTestsMode = true; + +/** + * Test suite for interactive UI tests. + * @constructor + */ +TestSuite = function() +{ + this.controlTaken_ = false; + this.timerId_ = -1; +}; + + +/** + * Reports test failure. + * @param {string} message Failure description. + */ +TestSuite.prototype.fail = function(message) +{ + if (this.controlTaken_) + this.reportFailure_(message); + else + throw message; +}; + + +/** + * Equals assertion tests that expected === actual. + * @param {Object} expected Expected object. + * @param {Object} actual Actual object. + * @param {string} opt_message User message to print if the test fails. + */ +TestSuite.prototype.assertEquals = function(expected, actual, opt_message) +{ + if (expected !== actual) { + var message = "Expected: '" + expected + "', but was '" + actual + "'"; + if (opt_message) + message = opt_message + "(" + message + ")"; + this.fail(message); + } +}; + + +/** + * True assertion tests that value == true. + * @param {Object} value Actual object. + * @param {string} opt_message User message to print if the test fails. + */ +TestSuite.prototype.assertTrue = function(value, opt_message) +{ + this.assertEquals(true, !!value, opt_message); +}; + + +/** + * Contains assertion tests that string contains substring. + * @param {string} string Outer. + * @param {string} substring Inner. + */ +TestSuite.prototype.assertContains = function(string, substring) +{ + if (string.indexOf(substring) === -1) + this.fail("Expected to: '" + string + "' to contain '" + substring + "'"); +}; + + +/** + * Takes control over execution. + */ +TestSuite.prototype.takeControl = function() +{ + this.controlTaken_ = true; + // Set up guard timer. + var self = this; + this.timerId_ = setTimeout(function() { + self.reportFailure_("Timeout exceeded: 20 sec"); + }, 20000); +}; + + +/** + * Releases control over execution. + */ +TestSuite.prototype.releaseControl = function() +{ + if (this.timerId_ !== -1) { + clearTimeout(this.timerId_); + this.timerId_ = -1; + } + this.reportOk_(); +}; + + +/** + * Async tests use this one to report that they are completed. + */ +TestSuite.prototype.reportOk_ = function() +{ + window.domAutomationController.send("[OK]"); +}; + + +/** + * Async tests use this one to report failures. + */ +TestSuite.prototype.reportFailure_ = function(error) +{ + if (this.timerId_ !== -1) { + clearTimeout(this.timerId_); + this.timerId_ = -1; + } + window.domAutomationController.send("[FAILED] " + error); +}; + + +/** + * Runs all global functions starting with "test" as unit tests. + */ +TestSuite.prototype.runTest = function(testName) +{ + try { + this[testName](); + if (!this.controlTaken_) + this.reportOk_(); + } catch (e) { + this.reportFailure_(e); + } +}; + + +/** + * @param {string} panelName Name of the panel to show. + */ +TestSuite.prototype.showPanel = function(panelName) +{ + // Open Scripts panel. + var toolbar = document.getElementById("toolbar"); + var button = toolbar.getElementsByClassName(panelName)[0]; + button.click(); + this.assertEquals(WebInspector.panels[panelName], WebInspector.currentPanel); +}; + + +/** + * Overrides the method with specified name until it's called first time. + * @param {Object} receiver An object whose method to override. + * @param {string} methodName Name of the method to override. + * @param {Function} override A function that should be called right after the + * overriden method returns. + * @param {boolean} opt_sticky Whether restore original method after first run + * or not. + */ +TestSuite.prototype.addSniffer = function(receiver, methodName, override, opt_sticky) +{ + var orig = receiver[methodName]; + if (typeof orig !== "function") + this.fail("Cannot find method to override: " + methodName); + var test = this; + receiver[methodName] = function(var_args) { + try { + var result = orig.apply(this, arguments); + } finally { + if (!opt_sticky) + receiver[methodName] = orig; + } + // In case of exception the override won't be called. + try { + override.apply(this, arguments); + } catch (e) { + test.fail("Exception in overriden method '" + methodName + "': " + e); + } + return result; + }; +}; + + +// UI Tests + + +/** + * Tests that the real injected host is present in the context. + */ +TestSuite.prototype.testHostIsPresent = function() +{ + this.assertTrue(typeof InspectorFrontendHost === "object" && !InspectorFrontendHost.isStub); +}; + + +/** + * Tests elements tree has an "HTML" root. + */ +TestSuite.prototype.testElementsTreeRoot = function() +{ + var doc = WebInspector.domAgent.document; + this.assertEquals("HTML", doc.documentElement.nodeName); + this.assertTrue(doc.documentElement.hasChildNodes()); +}; + + +/** + * Tests that main resource is present in the system and that it is + * the only resource. + */ +TestSuite.prototype.testMainResource = function() +{ + var tokens = []; + var resources = WebInspector.resources; + for (var id in resources) + tokens.push(resources[id].lastPathComponent); + this.assertEquals("simple_page.html", tokens.join(",")); +}; + + +/** + * Tests that resources tab is enabled when corresponding item is selected. + */ +TestSuite.prototype.testEnableResourcesTab = function() +{ + this.showPanel("resources"); + + var test = this; + this.addSniffer(WebInspector, "updateResource", + function(identifier, payload) { + test.assertEquals("simple_page.html", payload.lastPathComponent); + WebInspector.panels.resources.refresh(); + WebInspector.panels.resources.revealAndSelectItem(WebInspector.resources[identifier]); + + test.releaseControl(); + }); + + // Following call should lead to reload that we capture in the + // addResource override. + WebInspector.panels.resources._enableResourceTracking(); + + // We now have some time to report results to controller. + this.takeControl(); +}; + + +/** + * Tests that correct content length is reported for resources. + */ +TestSuite.prototype.testResourceContentLength = function() +{ + this.showPanel("resources"); + var test = this; + + var png = false; + var html = false; + this.addSniffer(WebInspector, "updateResource", + function(identifier, payload) { + if (!payload.didLengthChange) + return; + var resource = WebInspector.resources[identifier]; + if (!resource || !resource.url) + return; + if (resource.url.search("image.html$") !== -1) { + var expectedLength = 87; + test.assertTrue( + resource.contentLength <= expectedLength, + "image.html content length is greater thatn expected."); + if (expectedLength === resource.contentLength) + html = true; + } else if (resource.url.search("image.png") !== -1) { + var expectedLength = 257796; + test.assertTrue( + resource.contentLength <= expectedLength, + "image.png content length is greater than expected."); + if (expectedLength === resource.contentLength) + png = true; + } + if (html && png) { + // Wait 1 second before releasing control to check that the content + // lengths are not updated anymore. + setTimeout(function() { + test.releaseControl(); + }, 1000); + } + }, true); + + // Make sure resource tracking is on. + WebInspector.panels.resources._enableResourceTracking(); + // Reload inspected page to update all resources. + test.evaluateInConsole_( + "window.location.reload(true);", + function(resultText) { + test.assertEquals("undefined", resultText, "Unexpected result of reload()."); + }); + + // We now have some time to report results to controller. + this.takeControl(); +}; + + +/** + * Tests resource headers. + */ +TestSuite.prototype.testResourceHeaders = function() +{ + this.showPanel("resources"); + + var test = this; + + var responseOk = false; + var timingOk = false; + + this.addSniffer(WebInspector, "updateResource", + function(identifier, payload) { + var resource = this.resources[identifier]; + if (!resource || resource.mainResource) { + // We are only interested in secondary resources in this test. + return; + } + + var requestHeaders = JSON.stringify(resource.requestHeaders); + test.assertContains(requestHeaders, "Accept"); + + if (payload.didResponseChange) { + var responseHeaders = JSON.stringify(resource.responseHeaders); + test.assertContains(responseHeaders, "Content-type"); + test.assertContains(responseHeaders, "Content-Length"); + test.assertTrue(typeof resource.responseReceivedTime !== "undefined"); + responseOk = true; + } + + if (payload.didTimingChange) { + test.assertTrue(typeof resource.startTime !== "undefined"); + timingOk = true; + } + + if (payload.didCompletionChange) { + test.assertTrue(responseOk); + test.assertTrue(timingOk); + test.assertTrue(typeof resource.endTime !== "undefined"); + test.releaseControl(); + } + }, true); + + WebInspector.panels.resources._enableResourceTracking(); + this.takeControl(); +}; + + +/** + * Tests the mime type of a cached (HTTP 304) resource. + */ +TestSuite.prototype.testCachedResourceMimeType = function() +{ + this.showPanel("resources"); + + var test = this; + var hasReloaded = false; + + this.addSniffer(WebInspector, "updateResource", + function(identifier, payload) { + var resource = this.resources[identifier]; + if (!resource || resource.mainResource) { + // We are only interested in secondary resources in this test. + return; + } + + if (payload.didResponseChange) { + // Test server uses a default mime type for JavaScript files. + test.assertEquals("text/html", payload.mimeType); + if (!hasReloaded) { + hasReloaded = true; + // Reload inspected page to update all resources. + test.evaluateInConsole_("window.location.reload(true);", function() {}); + } else + test.releaseControl(); + } + + }, true); + + WebInspector.panels.resources._enableResourceTracking(); + this.takeControl(); +}; + + +/** + * Tests that profiler works. + */ +TestSuite.prototype.testProfilerTab = function() +{ + this.showPanel("profiles"); + + var test = this; + this.addSniffer(WebInspector.panels.profiles, "addProfileHeader", + function(typeOrProfile, profile) { + if (!profile) + profile = typeOrProfile; + var panel = WebInspector.panels.profiles; + panel.showProfile(profile); + var node = panel.visibleView.profileDataGridTree.children[0]; + // Iterate over displayed functions and search for a function + // that is called "fib" or "eternal_fib". If found, it will mean + // that we actually have profiled page's code. + while (node) { + if (node.functionName.indexOf("fib") !== -1) + test.releaseControl(); + node = node.traverseNextNode(true, null, true); + } + + test.fail(); + }); + var ticksCount = 0; + var tickRecord = "\nt,"; + this.addSniffer(RemoteProfilerAgent, "didGetLogLines", + function(posIgnored, log) { + var pos = 0; + while ((pos = log.indexOf(tickRecord, pos)) !== -1) { + pos += tickRecord.length; + ticksCount++; + } + if (ticksCount > 100) + InspectorBackend.stopProfiling(); + }, true); + + InspectorBackend.startProfiling(); + this.takeControl(); +}; + + +/** + * Tests that scripts tab can be open and populated with inspected scripts. + */ +TestSuite.prototype.testShowScriptsTab = function() +{ + this.showPanel("scripts"); + var test = this; + // There should be at least main page script. + this._waitUntilScriptsAreParsed(["debugger_test_page.html$"], + function() { + test.releaseControl(); + }); + // Wait until all scripts are added to the debugger. + this.takeControl(); +}; + + +/** + * Tests that scripts tab is populated with inspected scripts even if it + * hadn't been shown by the moment inspected paged refreshed. + * @see http://crbug.com/26312 + */ +TestSuite.prototype.testScriptsTabIsPopulatedOnInspectedPageRefresh = function() +{ + var test = this; + this.assertEquals(WebInspector.panels.elements, WebInspector.currentPanel, "Elements panel should be current one."); + + this.addSniffer(devtools.DebuggerAgent.prototype, "reset", waitUntilScriptIsParsed); + + // Reload inspected page. It will reset the debugger agent. + test.evaluateInConsole_( + "window.location.reload(true);", + function(resultText) { + test.assertEquals("undefined", resultText, "Unexpected result of reload()."); + }); + + function waitUntilScriptIsParsed() { + var parsed = devtools.tools.getDebuggerAgent().parsedScripts_; + for (var id in parsed) { + var url = parsed[id].getUrl(); + if (url && url.search("debugger_test_page.html$") !== -1) { + checkScriptsPanel(); + return; + } + } + test.addSniffer(devtools.DebuggerAgent.prototype, "addScriptInfo_", waitUntilScriptIsParsed); + } + + function checkScriptsPanel() { + test.showPanel("scripts"); + test.assertTrue(test._scriptsAreParsed(["debugger_test_page.html$"]), "Inspected script not found in the scripts list"); + test.releaseControl(); + } + + // Wait until all scripts are added to the debugger. + this.takeControl(); +}; + + +/** + * Tests that scripts list contains content scripts. + */ +TestSuite.prototype.testContentScriptIsPresent = function() +{ + this.showPanel("scripts"); + var test = this; + + test._waitUntilScriptsAreParsed( + ["page_with_content_script.html$", "simple_content_script.js$"], + function() { + test.releaseControl(); + }); + + // Wait until all scripts are added to the debugger. + this.takeControl(); +}; + + +/** + * Tests that scripts are not duplicaed on Scripts tab switch. + */ +TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch = function() +{ + var test = this; + + // There should be two scripts: one for the main page and another + // one which is source of console API(see + // InjectedScript._ensureCommandLineAPIInstalled). + var expectedScriptsCount = 2; + var parsedScripts = []; + + this.showPanel("scripts"); + + + function switchToElementsTab() { + test.showPanel("elements"); + setTimeout(switchToScriptsTab, 0); + } + + function switchToScriptsTab() { + test.showPanel("scripts"); + setTimeout(checkScriptsPanel, 0); + } + + function checkScriptsPanel() { + test.assertTrue(!!WebInspector.panels.scripts.visibleView, "No visible script view."); + test.assertTrue(test._scriptsAreParsed(["debugger_test_page.html$"]), "Some scripts are missing."); + checkNoDuplicates(); + test.releaseControl(); + } + + function checkNoDuplicates() { + var scriptSelect = document.getElementById("scripts-files"); + var options = scriptSelect.options; + for (var i = 0; i < options.length; i++) { + var scriptName = options[i].text; + for (var j = i + 1; j < options.length; j++) + test.assertTrue(scriptName !== options[j].text, "Found script duplicates: " + test.optionsToString_(options)); + } + } + + test._waitUntilScriptsAreParsed( + ["debugger_test_page.html$"], + function() { + checkNoDuplicates(); + setTimeout(switchToElementsTab, 0); + }); + + + // Wait until all scripts are added to the debugger. + this.takeControl(); +}; + + +/** + * Tests that a breakpoint can be set. + */ +TestSuite.prototype.testSetBreakpoint = function() +{ + var test = this; + this.showPanel("scripts"); + + var breakpointLine = 12; + + this._waitUntilScriptsAreParsed(["debugger_test_page.html"], + function() { + test.showMainPageScriptSource_( + "debugger_test_page.html", + function(view, url) { + view._addBreakpoint(breakpointLine); + // Force v8 execution. + RemoteDebuggerAgent.processDebugCommands(); + test.waitForSetBreakpointResponse_(url, breakpointLine, + function() { + test.releaseControl(); + }); + }); + }); + + this.takeControl(); +}; + + +/** + * Tests that pause on exception works. + */ +TestSuite.prototype.testPauseOnException = function() +{ + this.showPanel("scripts"); + var test = this; + + // TODO(yurys): remove else branch once the states are supported. + if (WebInspector.ScriptsPanel.PauseOnExceptionsState) { + while (WebInspector.currentPanel.pauseOnExceptionButton.state !== WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions) + WebInspector.currentPanel.pauseOnExceptionButton.element.click(); + } else { + // Make sure pause on exceptions is on. + if (!WebInspector.currentPanel.pauseOnExceptionButton.toggled) + WebInspector.currentPanel.pauseOnExceptionButton.element.click(); + } + + this._executeCodeWhenScriptsAreParsed("handleClick()", ["pause_on_exception.html$"]); + + this._waitForScriptPause( + { + functionsOnStack: ["throwAnException", "handleClick", "(anonymous function)"], + lineNumber: 6, + lineText: " return unknown_var;" + }, + function() { + test.releaseControl(); + }); + + this.takeControl(); +}; + + +// Tests that debugger works correctly if pause event occurs when DevTools +// frontend is being loaded. +TestSuite.prototype.testPauseWhenLoadingDevTools = function() +{ + this.showPanel("scripts"); + var test = this; + + var expectations = { + functionsOnStack: ["callDebugger"], + lineNumber: 8, + lineText: " debugger;" + }; + + + // Script execution can already be paused. + if (WebInspector.currentPanel.paused) { + var callFrame = WebInspector.currentPanel.sidebarPanes.callstack.selectedCallFrame; + this.assertEquals(expectations.functionsOnStack[0], callFrame.functionName); + var callbackInvoked = false; + this._checkSourceFrameWhenLoaded(expectations, function() { + callbackInvoked = true; + if (test.controlTaken_) + test.releaseControl(); + }); + if (!callbackInvoked) { + test.takeControl(); + } + return; + } + + this._waitForScriptPause( + { + functionsOnStack: ["callDebugger"], + lineNumber: 8, + lineText: " debugger;" + }, + function() { + test.releaseControl(); + }); + this.takeControl(); +}; + + +// Tests that pressing "Pause" will pause script execution if the script +// is already running. +TestSuite.prototype.testPauseWhenScriptIsRunning = function() +{ + this.showPanel("scripts"); + var test = this; + + test.evaluateInConsole_( + 'setTimeout("handleClick()" , 0)', + function(resultText) { + test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText); + testScriptPauseAfterDelay(); + }); + + // Wait for some time to make sure that inspected page is running the + // infinite loop. + function testScriptPauseAfterDelay() { + setTimeout(testScriptPause, 300); + } + + function testScriptPause() { + // The script should be in infinite loop. Click "Pause" button to + // pause it and wait for the result. + WebInspector.panels.scripts.pauseButton.click(); + + test._waitForScriptPause( + { + functionsOnStack: ["handleClick", "(anonymous function)"], + lineNumber: 5, + lineText: " while(true) {" + }, + function() { + test.releaseControl(); + }); + } + + this.takeControl(); +}; + + +/** + * Serializes options collection to string. + * @param {HTMLOptionsCollection} options + * @return {string} + */ +TestSuite.prototype.optionsToString_ = function(options) +{ + var names = []; + for (var i = 0; i < options.length; i++) + names.push('"' + options[i].text + '"'); + return names.join(","); +}; + + +/** + * Ensures that main HTML resource is selected in Scripts panel and that its + * source frame is setup. Invokes the callback when the condition is satisfied. + * @param {HTMLOptionsCollection} options + * @param {function(WebInspector.SourceView,string)} callback + */ +TestSuite.prototype.showMainPageScriptSource_ = function(scriptName, callback) +{ + var test = this; + + var scriptSelect = document.getElementById("scripts-files"); + var options = scriptSelect.options; + + test.assertTrue(options.length, "Scripts list is empty"); + + // Select page's script if it's not current option. + var scriptResource; + if (options[scriptSelect.selectedIndex].text === scriptName) + scriptResource = options[scriptSelect.selectedIndex].representedObject; + else { + var pageScriptIndex = -1; + for (var i = 0; i < options.length; i++) { + if (options[i].text === scriptName) { + pageScriptIndex = i; + break; + } + } + test.assertTrue(-1 !== pageScriptIndex, "Script with url " + scriptName + " not found among " + test.optionsToString_(options)); + scriptResource = options[pageScriptIndex].representedObject; + + // Current panel is "Scripts". + WebInspector.currentPanel._showScriptOrResource(scriptResource); + test.assertEquals(pageScriptIndex, scriptSelect.selectedIndex, "Unexpected selected option index."); + } + + test.assertTrue(scriptResource instanceof WebInspector.Resource, + "Unexpected resource class."); + test.assertTrue(!!scriptResource.url, "Resource URL is null."); + test.assertTrue(scriptResource.url.search(scriptName + "$") !== -1, "Main HTML resource should be selected."); + + var scriptsPanel = WebInspector.panels.scripts; + + var view = scriptsPanel.visibleView; + test.assertTrue(view instanceof WebInspector.SourceView); + + if (!view.sourceFrame._loaded) { + test.addSniffer(view, "_sourceFrameSetupFinished", function(event) { + callback(view, scriptResource.url); + }); + } else + callback(view, scriptResource.url); +}; + + +/* + * Evaluates the code in the console as if user typed it manually and invokes + * the callback when the result message is received and added to the console. + * @param {string} code + * @param {function(string)} callback + */ +TestSuite.prototype.evaluateInConsole_ = function(code, callback) +{ + WebInspector.console.visible = true; + WebInspector.console.prompt.text = code; + WebInspector.console.promptElement.dispatchEvent( TestSuite.createKeyEvent("Enter")); + + this.addSniffer(WebInspector.ConsoleView.prototype, "addMessage", + function(commandResult) { + callback(commandResult.toMessageElement().textContent); + }); +}; + + +/* + * Waits for "setbreakpoint" response, checks that corresponding breakpoint + * was successfully set and invokes the callback if it was. + * @param {string} scriptUrl + * @param {number} breakpointLine + * @param {function()} callback + */ +TestSuite.prototype.waitForSetBreakpointResponse_ = function(scriptUrl, breakpointLine, callback) +{ + var test = this; + test.addSniffer( + devtools.DebuggerAgent.prototype, + "handleSetBreakpointResponse_", + function(msg) { + var bps = this.urlToBreakpoints_[scriptUrl]; + test.assertTrue(!!bps, "No breakpoints for line " + breakpointLine); + var line = devtools.DebuggerAgent.webkitToV8LineNumber_(breakpointLine); + test.assertTrue(!!bps[line].getV8Id(), "Breakpoint id was not assigned."); + callback(); + }); +}; + + +/** + * Tests eval on call frame. + */ +TestSuite.prototype.testEvalOnCallFrame = function() +{ + this.showPanel("scripts"); + + var breakpointLine = 16; + + var test = this; + this.addSniffer(devtools.DebuggerAgent.prototype, "handleScriptsResponse_", + function(msg) { + test.showMainPageScriptSource_( + "debugger_test_page.html", + function(view, url) { + view._addBreakpoint(breakpointLine); + // Force v8 execution. + RemoteDebuggerAgent.processDebugCommands(); + test.waitForSetBreakpointResponse_(url, breakpointLine, setBreakpointCallback); + }); + }); + + function setBreakpointCallback() { + // Since breakpoints are ignored in evals' calculate() function is + // execute after zero-timeout so that the breakpoint is hit. + test.evaluateInConsole_( + 'setTimeout("calculate(123)" , 0)', + function(resultText) { + test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText); + waitForBreakpointHit(); + }); + } + + function waitForBreakpointHit() { + test.addSniffer( + devtools.DebuggerAgent.prototype, + "handleBacktraceResponse_", + function(msg) { + test.assertEquals(2, this.callFrames_.length, "Unexpected stack depth on the breakpoint. " + JSON.stringify(msg)); + test.assertEquals("calculate", this.callFrames_[0].functionName, "Unexpected top frame function."); + // Evaluate "e+1" where "e" is an argument of "calculate" function. + test.evaluateInConsole_( + "e+1", + function(resultText) { + test.assertEquals("124", resultText, 'Unexpected "e+1" value.'); + test.releaseControl(); + }); + }); + } + + this.takeControl(); +}; + + +/** + * Tests that console auto completion works when script execution is paused. + */ +TestSuite.prototype.testCompletionOnPause = function() +{ + this.showPanel("scripts"); + var test = this; + this._executeCodeWhenScriptsAreParsed("handleClick()", ["completion_on_pause.html$"]); + + this._waitForScriptPause( + { + functionsOnStack: ["innerFunction", "handleClick", "(anonymous function)"], + lineNumber: 9, + lineText: " debugger;" + }, + showConsole); + + function showConsole() { + test.addSniffer(WebInspector.console, "afterShow", testLocalsCompletion); + WebInspector.showConsole(); + } + + function testLocalsCompletion() { + checkCompletions("th", ["parameter1", "closureLocal", "p", "createClosureLocal"], testThisCompletion); + } + + function testThisCompletion() { + checkCompletions("this.", ["field1", "field2", "m"], testFieldCompletion); + } + + function testFieldCompletion() { + checkCompletions("this.field1.", ["id", "name"], function() { test.releaseControl(); }); + } + + function checkCompletions(expression, expectedProperties, callback) { + test.addSniffer(WebInspector.console, "_reportCompletions", + function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result, isException) { + test.assertTrue(!isException, "Exception while collecting completions"); + for (var i = 0; i < expectedProperties.length; i++) { + var name = expectedProperties[i]; + test.assertTrue(result[name], "Name " + name + " not found among the completions: " + JSON.stringify(result)); + } + setTimeout(callback, 0); + }); + WebInspector.console.prompt.text = expression; + WebInspector.console.prompt.autoCompleteSoon(); + } + + this.takeControl(); +}; + + +/** + * Tests that inspected page doesn't hang on reload if it contains a syntax + * error and DevTools window is open. + */ +TestSuite.prototype.testAutoContinueOnSyntaxError = function() +{ + this.showPanel("scripts"); + var test = this; + + function checkScriptsList() { + var scriptSelect = document.getElementById("scripts-files"); + var options = scriptSelect.options; + // There should be only console API source (see + // InjectedScript._ensureCommandLineAPIInstalled) since the page script + // contains a syntax error. + for (var i = 0 ; i < options.length; i++) { + if (options[i].text.search("script_syntax_error.html$") !== -1) + test.fail("Script with syntax error should not be in the list of parsed scripts."); + } + } + + this.addSniffer(devtools.DebuggerAgent.prototype, "handleScriptsResponse_", + function(msg) { + checkScriptsList(); + + // Reload inspected page. + test.evaluateInConsole_( + "window.location.reload(true);", + function(resultText) { + test.assertEquals("undefined", resultText, "Unexpected result of reload()."); + waitForExceptionEvent(); + }); + }); + + function waitForExceptionEvent() { + var exceptionCount = 0; + test.addSniffer( + devtools.DebuggerAgent.prototype, + "handleExceptionEvent_", + function(msg) { + exceptionCount++; + test.assertEquals(1, exceptionCount, "Too many exceptions."); + test.assertEquals(undefined, msg.getBody().script, "Unexpected exception: " + JSON.stringify(msg)); + test.releaseControl(); + }); + + // Check that the script is not paused on parse error. + test.addSniffer( + WebInspector, + "pausedScript", + function(callFrames) { + test.fail("Script execution should not pause on syntax error."); + }); + } + + this.takeControl(); +}; + + +/** + * Checks current execution line against expectations. + * @param {WebInspector.SourceFrame} sourceFrame + * @param {number} lineNumber Expected line number + * @param {string} lineContent Expected line text + */ +TestSuite.prototype._checkExecutionLine = function(sourceFrame, lineNumber, lineContent) +{ + this.assertEquals(lineNumber, sourceFrame.executionLine, "Unexpected execution line number."); + this.assertEquals(lineContent, sourceFrame._textModel.line(lineNumber - 1), "Unexpected execution line text."); +} + + +/** + * Checks that all expected scripts are present in the scripts list + * in the Scripts panel. + * @param {Array.<string>} expected Regular expressions describing + * expected script names. + * @return {boolean} Whether all the scripts are in "scripts-files" select + * box + */ +TestSuite.prototype._scriptsAreParsed = function(expected) +{ + var scriptSelect = document.getElementById("scripts-files"); + var options = scriptSelect.options; + + // Check that at least all the expected scripts are present. + var missing = expected.slice(0); + for (var i = 0 ; i < options.length; i++) { + for (var j = 0; j < missing.length; j++) { + if (options[i].text.search(missing[j]) !== -1) { + missing.splice(j, 1); + break; + } + } + } + return missing.length === 0; +}; + + +/** + * Waits for script pause, checks expectations, and invokes the callback. + * @param {Object} expectations Dictionary of expectations + * @param {function():void} callback + */ +TestSuite.prototype._waitForScriptPause = function(expectations, callback) +{ + var test = this; + // Wait until script is paused. + test.addSniffer( + WebInspector, + "pausedScript", + function(callFrames) { + var functionsOnStack = []; + for (var i = 0; i < callFrames.length; i++) + functionsOnStack.push(callFrames[i].functionName); + + test.assertEquals(expectations.functionsOnStack.join(","), functionsOnStack.join(","), "Unexpected stack."); + + // Check that execution line where the script is paused is + // expected one. + test._checkSourceFrameWhenLoaded(expectations, callback); + }); +}; + + +/** + * Waits for current source frame to load, checks expectations, and invokes + * the callback. + * @param {Object} expectations Dictionary of expectations + * @param {function():void} callback + */ +TestSuite.prototype._checkSourceFrameWhenLoaded = function(expectations, callback) +{ + var test = this; + + var frame = WebInspector.currentPanel.visibleView.sourceFrame; + if (frame._loaded) + checkExecLine(); + else { + setTimeout(function() { + test._checkSourceFrameWhenLoaded(expectations, callback); + }, 100); + } + function checkExecLine() { + test._checkExecutionLine(frame, expectations.lineNumber, expectations.lineText); + callback(); + } +}; + + +/** + * Performs sequence of steps. + * @param {Array.<Object|Function>} Array [expectations1,action1,expectations2, + * action2,...,actionN]. + */ +TestSuite.prototype._performSteps = function(actions) +{ + var test = this; + var i = 0; + function doNextAction() { + if (i > 0) + actions[i++](); + if (i < actions.length - 1) + test._waitForScriptPause(actions[i++], doNextAction); + } + doNextAction(); +}; + + +/** + * Waits until all the scripts are parsed and asynchronously executes the code + * in the inspected page. + */ +TestSuite.prototype._executeCodeWhenScriptsAreParsed = function(code, expectedScripts) +{ + var test = this; + + function executeFunctionInInspectedPage() { + // Since breakpoints are ignored in evals' calculate() function is + // execute after zero-timeout so that the breakpoint is hit. + test.evaluateInConsole_( + 'setTimeout("' + code + '" , 0)', + function(resultText) { + test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText); + }); + } + + test._waitUntilScriptsAreParsed(expectedScripts, executeFunctionInInspectedPage); +}; + + +/** + * Waits until all the scripts are parsed and invokes the callback. + */ +TestSuite.prototype._waitUntilScriptsAreParsed = function(expectedScripts, callback) +{ + var test = this; + + function waitForAllScripts() { + if (test._scriptsAreParsed(expectedScripts)) + callback(); + else + test.addSniffer(WebInspector, "parsedScriptSource", waitForAllScripts); + } + + waitForAllScripts(); +}; + + +/** + * Waits until all debugger scripts are parsed and executes "a()" in the + * inspected page. + */ +TestSuite.prototype._executeFunctionForStepTest = function() +{ + this._executeCodeWhenScriptsAreParsed("a()", ["debugger_step.html$", "debugger_step.js$"]); +}; + + +/** + * Tests step over in the debugger. + */ +TestSuite.prototype.testStepOver = function() +{ + this.showPanel("scripts"); + var test = this; + + this._executeFunctionForStepTest(); + + this._performSteps([ + { + functionsOnStack: ["d","a","(anonymous function)"], + lineNumber: 3, + lineText: " debugger;" + }, + function() { + document.getElementById("scripts-step-over").click(); + }, + { + functionsOnStack: ["d","a","(anonymous function)"], + lineNumber: 5, + lineText: " var y = fact(10);" + }, + function() { + document.getElementById("scripts-step-over").click(); + }, + { + functionsOnStack: ["d","a","(anonymous function)"], + lineNumber: 6, + lineText: " return y;" + }, + function() { + test.releaseControl(); + } + ]); + + test.takeControl(); +}; + + +/** + * Tests step out in the debugger. + */ +TestSuite.prototype.testStepOut = function() +{ + this.showPanel("scripts"); + var test = this; + + this._executeFunctionForStepTest(); + + this._performSteps([ + { + functionsOnStack: ["d","a","(anonymous function)"], + lineNumber: 3, + lineText: " debugger;" + }, + function() { + document.getElementById("scripts-step-out").click(); + }, + { + functionsOnStack: ["a","(anonymous function)"], + lineNumber: 8, + lineText: " printResult(result);" + }, + function() { + test.releaseControl(); + } + ]); + + test.takeControl(); +}; + + +/** + * Tests step in in the debugger. + */ +TestSuite.prototype.testStepIn = function() +{ + this.showPanel("scripts"); + var test = this; + + this._executeFunctionForStepTest(); + + this._performSteps([ + { + functionsOnStack: ["d","a","(anonymous function)"], + lineNumber: 3, + lineText: " debugger;" + }, + function() { + document.getElementById("scripts-step-over").click(); + }, + { + functionsOnStack: ["d","a","(anonymous function)"], + lineNumber: 5, + lineText: " var y = fact(10);" + }, + function() { + document.getElementById("scripts-step-into").click(); + }, + { + functionsOnStack: ["fact","d","a","(anonymous function)"], + lineNumber: 15, + lineText: " return r;" + }, + function() { + test.releaseControl(); + } + ]); + + test.takeControl(); +}; + + +/** + * Gets a XPathResult matching given xpath. + * @param {string} xpath + * @param {number} resultType + * @param {Node} opt_ancestor Context node. If not specified documentElement + * will be used + * @return {XPathResult} Type of returned value is determined by "resultType" parameter + */ + +TestSuite.prototype._evaluateXpath = function(xpath, resultType, opt_ancestor) +{ + if (!opt_ancestor) + opt_ancestor = document.documentElement; + try { + return document.evaluate(xpath, opt_ancestor, null, resultType, null); + } catch(e) { + this.fail('Error in expression: "' + xpath + '".' + e); + } +}; + + +/** + * Gets first Node matching given xpath. + * @param {string} xpath + * @param {Node} opt_ancestor Context node. If not specified documentElement + * will be used + * @return {?Node} + */ +TestSuite.prototype._findNode = function(xpath, opt_ancestor) +{ + var result = this._evaluateXpath(xpath, XPathResult.FIRST_ORDERED_NODE_TYPE, opt_ancestor).singleNodeValue; + this.assertTrue(!!result, "Cannot find node on path: " + xpath); + return result; +}; + + +/** + * Gets a text matching given xpath. + * @param {string} xpath + * @param {Node} opt_ancestor Context node. If not specified documentElement + * will be used + * @return {?string} + */ +TestSuite.prototype._findText = function(xpath, opt_ancestor) +{ + var result = this._evaluateXpath(xpath, XPathResult.STRING_TYPE, opt_ancestor).stringValue; + this.assertTrue(!!result, "Cannot find text on path: " + xpath); + return result; +}; + + +/** + * Gets an iterator over nodes matching given xpath. + * @param {string} xpath + * @param {Node} opt_ancestor Context node. If not specified, documentElement + * will be used + * @return {XPathResult} Iterator over the nodes + */ +TestSuite.prototype._nodeIterator = function(xpath, opt_ancestor) +{ + return this._evaluateXpath(xpath, XPathResult.ORDERED_NODE_ITERATOR_TYPE, opt_ancestor); +}; + + +/** + * Checks the scopeSectionDiv against the expectations. + * @param {Node} scopeSectionDiv The section div + * @param {Object} expectations Expectations dictionary + */ +TestSuite.prototype._checkScopeSectionDiv = function(scopeSectionDiv, expectations) +{ + var scopeTitle = this._findText('./div[@class="header"]/div[@class="title"]/text()', scopeSectionDiv); + this.assertEquals(expectations.title, scopeTitle, "Unexpected scope section title."); + if (!expectations.properties) + return; + this.assertTrue(scopeSectionDiv.hasStyleClass("expanded"), 'Section "' + scopeTitle + '" is collapsed.'); + + var propertyIt = this._nodeIterator("./ol/li", scopeSectionDiv); + var propertyLi; + var foundProps = []; + while (propertyLi = propertyIt.iterateNext()) { + var name = this._findText('./span[@class="name"]/text()', propertyLi); + var value = this._findText('./span[@class="value"]/text()', propertyLi); + this.assertTrue(!!name, 'Invalid variable name: "' + name + '"'); + this.assertTrue(name in expectations.properties, "Unexpected property: " + name); + this.assertEquals(expectations.properties[name], value, 'Unexpected "' + name + '" property value.'); + delete expectations.properties[name]; + foundProps.push(name + " = " + value); + } + + // Check that all expected properties were found. + for (var p in expectations.properties) + this.fail('Property "' + p + '" was not found in scope "' + scopeTitle + '". Found properties: "' + foundProps.join(",") + '"'); +}; + + +/** + * Expands scope sections matching the filter and invokes the callback on + * success. + * @param {function(WebInspector.ObjectPropertiesSection, number):boolean} + * filter + * @param {Function} callback + */ +TestSuite.prototype._expandScopeSections = function(filter, callback) +{ + var sections = WebInspector.currentPanel.sidebarPanes.scopechain.sections; + + var toBeUpdatedCount = 0; + function updateListener() { + --toBeUpdatedCount; + if (toBeUpdatedCount === 0) { + // Report when all scopes are expanded and populated. + callback(); + } + } + + // Global scope is always the last one. + for (var i = 0; i < sections.length - 1; i++) { + var section = sections[i]; + if (!filter(sections, i)) + continue; + ++toBeUpdatedCount; + var populated = section.populated; + + this._hookGetPropertiesCallback(updateListener, + function() { + section.expand(); + if (populated) { + // Make sure "updateProperties" callback will be called at least once + // after it was overridden. + section.update(); + } + }); + } +}; + + +/** + * Tests that scopes can be expanded and contain expected data. + */ +TestSuite.prototype.testExpandScope = function() +{ + this.showPanel("scripts"); + var test = this; + + this._executeCodeWhenScriptsAreParsed("handleClick()", ["debugger_closure.html$"]); + + this._waitForScriptPause( + { + functionsOnStack: ["innerFunction", "handleClick", "(anonymous function)"], + lineNumber: 8, + lineText: " debugger;" + }, + expandAllSectionsExceptGlobal); + + // Expanding Global scope takes for too long so we skeep it. + function expandAllSectionsExceptGlobal() { + test._expandScopeSections(function(sections, i) { + return i < sections.length - 1; + }, + examineScopes /* When all scopes are expanded and populated check them. */); + } + + // Check scope sections contents. + function examineScopes() { + var scopeVariablesSection = test._findNode('//div[@id="scripts-sidebar"]/div[div[@class="title"]/text()="Scope Variables"]'); + var expectedScopes = [ + { + title: "Local", + properties: { + x:"2009", + innerFunctionLocalVar:"2011", + "this": "global", + } + }, + { + title: "Closure", + properties: { + n:"TextParam", + makeClosureLocalVar:"local.TextParam", + } + }, + { + title: "Global", + }, + ]; + var it = test._nodeIterator('./div[@class="body"]/div', scopeVariablesSection); + var scopeIndex = 0; + var scopeDiv; + while (scopeDiv = it.iterateNext()) { + test.assertTrue(scopeIndex < expectedScopes.length, "Too many scopes."); + test._checkScopeSectionDiv(scopeDiv, expectedScopes[scopeIndex]); + ++scopeIndex; + } + test.assertEquals(expectedScopes.length, scopeIndex, "Unexpected number of scopes."); + + test.releaseControl(); + } + + test.takeControl(); +}; + + +/** + * Returns child tree element for a property with given name. + * @param {TreeElement} parent Parent tree element. + * @param {string} childName + * @param {string} objectPath Path to the object. Will be printed in the case + * of failure. + * @return {TreeElement} + */ +TestSuite.prototype._findChildProperty = function(parent, childName, objectPath) +{ + var children = parent.children; + for (var i = 0; i < children.length; i++) { + var treeElement = children[i]; + var property = treeElement.property; + if (property.name === childName) + return treeElement; + } + this.fail('Cannot find property "' + childName + '" in ' + objectPath); +}; + + +/** + * Executes the 'code' with InjectedScriptAccess.getProperties overriden + * so that all callbacks passed to InjectedScriptAccess.getProperties are + * extended with the "hook". + * @param {Function} hook The hook function. + * @param {Function} code A code snippet to be executed. + */ +TestSuite.prototype._hookGetPropertiesCallback = function(hook, code) +{ + var accessor = InjectedScriptAccess.prototype; + var orig = accessor.getProperties; + accessor.getProperties = function(objectProxy, ignoreHasOwnProperty, abbreviate, callback) { + orig.call(this, objectProxy, ignoreHasOwnProperty, abbreviate, + function() { + callback.apply(this, arguments); + hook(); + }); + }; + try { + code(); + } finally { + accessor.getProperties = orig; + } +}; + + +/** + * Tests that all elements in prototype chain of an object have expected + * intrinic proprties(__proto__, constructor, prototype). + */ +TestSuite.prototype.testDebugIntrinsicProperties = function() +{ + this.showPanel("scripts"); + var test = this; + + this._executeCodeWhenScriptsAreParsed("handleClick()", ["debugger_intrinsic_properties.html$"]); + + this._waitForScriptPause( + { + functionsOnStack: ["callDebugger", "handleClick", "(anonymous function)"], + lineNumber: 29, + lineText: " debugger;" + }, + expandLocalScope); + + var localScopeSection = null; + function expandLocalScope() { + test._expandScopeSections(function(sections, i) { + if (i === 0) { + test.assertTrue(sections[i].object.isLocal, "Scope #0 is not Local."); + localScopeSection = sections[i]; + return true; + } + return false; + }, + examineLocalScope); + } + + function examineLocalScope() { + var scopeExpectations = [ + "a", "Object", [ + "constructor", "function Child()", [ + "constructor", "function Function()", null, + "name", "Child", null, + "prototype", "Object", [ + "childProtoField", 21, null + ] + ], + + "__proto__", "Object", [ + "__proto__", "Object", [ + "__proto__", "Object", [ + "__proto__", "null", null, + "constructor", "function Object()", null, + ], + "constructor", "function Parent()", [ + "name", "Parent", null, + "prototype", "Object", [ + "parentProtoField", 11, null, + ] + ], + "parentProtoField", 11, null, + ], + "constructor", "function Child()", null, + "childProtoField", 21, null, + ], + + "parentField", 10, null, + "childField", 20, null, + ] + ]; + + checkProperty(localScopeSection.propertiesTreeOutline, "<Local Scope>", scopeExpectations); + } + + var propQueue = []; + var index = 0; + var expectedFinalIndex = 8; + + function expandAndCheckNextProperty() { + if (index === propQueue.length) { + test.assertEquals(expectedFinalIndex, index, "Unexpected number of expanded objects."); + test.releaseControl(); + return; + } + + // Read next property data from the queue. + var treeElement = propQueue[index].treeElement; + var path = propQueue[index].path; + var expectations = propQueue[index].expectations; + index++; + + // Expand the property. + test._hookGetPropertiesCallback(function() { + checkProperty(treeElement, path, expectations); + }, + function() { + treeElement.expand(); + }); + } + + function checkProperty(treeElement, path, expectations) { + for (var i = 0; i < expectations.length; i += 3) { + var name = expectations[i]; + var description = expectations[i+1]; + var value = expectations[i+2]; + + var propertyPath = path + "." + name; + var propertyTreeElement = test._findChildProperty(treeElement, name, path); + test.assertTrue(propertyTreeElement, 'Property "' + propertyPath + '" not found.'); + test.assertEquals(description, propertyTreeElement.property.value.description, 'Unexpected "' + propertyPath + '" description.'); + if (value) { + // Schedule property content check. + propQueue.push({ + treeElement: propertyTreeElement, + path: propertyPath, + expectations: value, + }); + } + } + // Check next property in the queue. + expandAndCheckNextProperty(); + } + + test.takeControl(); +}; + + +/** + * Tests "Pause" button will pause debugger when a snippet is evaluated. + */ +TestSuite.prototype.testPauseInEval = function() +{ + this.showPanel("scripts"); + + var test = this; + + var pauseButton = document.getElementById("scripts-pause"); + pauseButton.click(); + + devtools.tools.evaluateJavaScript("fib(10)"); + + this.addSniffer(WebInspector, "pausedScript", + function() { + test.releaseControl(); + }); + + test.takeControl(); +}; + + +/** + * Key event with given key identifier. + */ +TestSuite.createKeyEvent = function(keyIdentifier) +{ + var evt = document.createEvent("KeyboardEvent"); + evt.initKeyboardEvent("keydown", true /* can bubble */, true /* can cancel */, null /* view */, keyIdentifier, ""); + return evt; +}; + + +/** + * Tests console eval. + */ +TestSuite.prototype.testConsoleEval = function() +{ + var test = this; + this.evaluateInConsole_("123", + function(resultText) { + test.assertEquals("123", resultText); + test.releaseControl(); + }); + + this.takeControl(); +}; + + +/** + * Tests console log. + */ +TestSuite.prototype.testConsoleLog = function() +{ + WebInspector.console.visible = true; + var messages = WebInspector.console.messages; + var index = 0; + + var test = this; + var assertNext = function(line, message, opt_class, opt_count, opt_substr) { + var elem = messages[index++].toMessageElement(); + var clazz = elem.getAttribute("class"); + var expectation = (opt_count || '') + 'console_test_page.html:' + line + message; + if (opt_substr) + test.assertContains(elem.textContent, expectation); + else + test.assertEquals(expectation, elem.textContent); + if (opt_class) + test.assertContains(clazz, "console-" + opt_class); + }; + + assertNext("5", "log", "log-level"); + assertNext("7", "debug", "log-level"); + assertNext("9", "info", "log-level"); + assertNext("11", "warn", "warning-level"); + assertNext("13", "error", "error-level"); + assertNext("15", "Message format number 1, 2 and 3.5"); + assertNext("17", "Message format for string"); + assertNext("19", "Object Object"); + assertNext("22", "repeated", "log-level", 5); + assertNext("26", "count: 1"); + assertNext("26", "count: 2"); + assertNext("29", "group", "group-title"); + index++; + assertNext("33", "timer:", "log-level", "", true); + assertNext("35", "1 2 3", "log-level"); + assertNext("37", "HTMLDocument", "log-level"); + assertNext("39", "<html>", "log-level", "", true); +}; + + +/** + * Tests eval of global objects. + */ +TestSuite.prototype.testEvalGlobal = function() +{ + WebInspector.console.visible = true; + + var inputs = ["foo", "foobar"]; + var expectations = ["foo", "fooValue", "foobar", "ReferenceError: foobar is not defined"]; + + // Do not change code below - simply add inputs and expectations above. + var initEval = function(input) { + WebInspector.console.prompt.text = input; + WebInspector.console.promptElement.dispatchEvent( TestSuite.createKeyEvent("Enter")); + }; + var test = this; + var messagesCount = 0; + var inputIndex = 0; + this.addSniffer(WebInspector.ConsoleView.prototype, "addMessage", + function(commandResult) { + messagesCount++; + if (messagesCount === expectations.length) { + var messages = WebInspector.console.messages; + for (var i = 0; i < expectations; ++i) { + var elem = messages[i++].toMessageElement(); + test.assertEquals(elem.textContent, expectations[i]); + } + test.releaseControl(); + } else if (messagesCount % 2 === 0) + initEval(inputs[inputIndex++]); + }, true); + + initEval(inputs[inputIndex++]); + this.takeControl(); +}; + + +/** + * Tests that Storage panel can be open and that local DOM storage is added + * to the panel. + */ +TestSuite.prototype.testShowStoragePanel = function() +{ + var test = this; + this.addSniffer(WebInspector.panels.storage, "addDOMStorage", + function(storage) { + var orig = storage.getEntries; + storage.getEntries = function(callback) { + orig.call(this, function(entries) { + callback(entries); + test.releaseControl(); + }); + }; + try { + WebInspector.currentPanel.selectDOMStorage(storage.id); + storage.getEntries = orig; + } catch (e) { + test.fail("Exception in selectDOMStorage: " + e); + } + }); + this.showPanel("storage"); + + // Access localStorage so that it's pushed to the frontend. + this.evaluateInConsole_( + 'setTimeout("localStorage.x = 10" , 0)', + function(resultText) { + test.assertTrue(!isNaN(resultText), "Failed to get timer id: " + resultText); + }); + + // Wait until DOM storage is added to the panel. + this.takeControl(); +}; + + +/** + * Test runner for the test suite. + */ +var uiTests = {}; + + +/** + * Run each test from the test suit on a fresh instance of the suite. + */ +uiTests.runAllTests = function() +{ + // For debugging purposes. + for (var name in TestSuite.prototype) { + if (name.substring(0, 4) === "test" && typeof TestSuite.prototype[name] === "function") + uiTests.runTest(name); + } +}; + + +/** + * Run specified test on a fresh instance of the test suite. + * @param {string} name Name of a test method from TestSuite class. + */ +uiTests.runTest = function(name) +{ + new TestSuite().runTest(name); +}; + + +} diff --git a/WebKit/chromium/src/js/devTools.css b/WebKit/chromium/src/js/devTools.css new file mode 100755 index 0000000..1fa935f --- /dev/null +++ b/WebKit/chromium/src/js/devTools.css @@ -0,0 +1,223 @@ +#scripts-files option.injected { + color: rgb(70, 134, 240); +} + +.data-grid table { + line-height: 120%; +} + +body.attached #toolbar { + height: 34px; + border-top: 1px solid rgb(100, 100, 100); + cursor: default; /* overriden */ + padding-left: 0; +} + + +/* Chrome theme overrides */ +body.platform-windows #toolbar { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(242, 247, 253)), to(rgb(223, 234, 248))); +} + +body.platform-windows.inactive #toolbar { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(248, 248, 248)), to(rgb(237, 237, 237))); +} + + +/* Heap Profiler Styles */ + +.heap-snapshot-status-bar-item .glyph { + -webkit-mask-image: url(Images/focusButtonGlyph.png); +} + +.heap-snapshot-sidebar-tree-item .icon { + content: url(Images/profileIcon.png); +} + +.heap-snapshot-sidebar-tree-item.small .icon { + content: url(Images/profileSmallIcon.png); +} + +.heap-snapshot-view { + display: none; + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.heap-snapshot-view.visible { + display: block; +} + +.heap-snapshot-view .data-grid { + border: none; + max-height: 100%; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 93px; +} + +.heap-snapshot-view .data-grid th.count-column { + text-align: center; +} + +.heap-snapshot-view .data-grid td.count-column { + text-align: right; +} + +.heap-snapshot-view .data-grid th.size-column { + text-align: center; +} + +.heap-snapshot-view .data-grid td.size-column { + text-align: right; +} + +.heap-snapshot-view .data-grid th.countDelta-column { + text-align: center; +} + +.heap-snapshot-view .data-grid td.countDelta-column { + text-align: right; +} + +.heap-snapshot-view .data-grid th.sizeDelta-column { + text-align: center; +} + +.heap-snapshot-view .data-grid td.sizeDelta-column { + text-align: right; +} + +#heap-snapshot-summary-container { + position: absolute; + padding-top: 20px; + bottom: 0; + left: 0; + right: 0; + height: 93px; + margin-left: -1px; + border-left: 1px solid rgb(102, 102, 102); + background-color: rgb(101, 111, 130); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0))); + background-repeat: repeat-x; + background-position: top; + text-align: center; + text-shadow: black 0 1px 1px; + white-space: nowrap; + color: white; + -webkit-background-size: 1px 6px; + -webkit-background-origin: padding; + -webkit-background-clip: padding; +} + +.heap-snapshot-summary { + display: inline-block; + width: 50%; + min-width: 300px; + position: relative; +} + +.heap-snapshot-summary canvas.summary-graph { + width: 225px; +} + +.heap-snapshot-summary-label { + font-size: 12px; + font-weight: bold; + position: absolute; + top: 1px; + width: 50%; + left: 25%; +} + +body.platform-windows .section > .header { + border: 1px solid rgb(92, 116, 157); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(105, 133, 180)), to(rgb(92, 116, 157))); +} + +body.platform-windows .console-group-messages .section > .header { + padding: 0 8px 0 0; + background-image: none; + border: none; + min-height: 0; +} + +body.platform-windows #resources-filter { + background: -webkit-gradient(linear, left top, left bottom, from(rgb(233, 233, 233)), to(rgb(233, 233, 233))); +} + +body.platform-windows .crumbs .crumb { + -webkit-border-image: url(Images/segmentChromium.png) 0 12 0 2; +} + +body.platform-windows .crumbs .crumb.end { + -webkit-border-image: url(Images/segmentEndChromium.png) 0 2 0 2; +} + +body.platform-windows .crumbs .crumb.selected { + -webkit-border-image: url(Images/segmentSelectedChromium.png) 0 12 0 2; + color: white; + text-shadow: rgba(255, 255, 255, 0.5) 0 0px 0; +} + +body.platform-windows .crumbs .crumb.selected:hover { + -webkit-border-image: url(Images/segmentSelectedChromium.png) 0 12 0 2; +} + +body.platform-windows .crumbs .crumb.selected.end, .crumbs .crumb.selected.end:hover { + -webkit-border-image: url(Images/segmentSelectedEndChromium.png) 0 2 0 2; +} + +body.platform-windows .crumbs .crumb:hover { + -webkit-border-image: url(Images/segmentHoverChromium.png) 0 12 0 2; +} + +body.platform-windows .crumbs .crumb.dimmed:hover { + -webkit-border-image: url(Images/segmentHoverChromium.png) 0 12 0 2; +} + +body.platform-windows .crumbs .crumb.end:hover { + -webkit-border-image: url(Images/segmentHoverEndChromium.png) 0 2 0 2; +} + +body.platform-windows body.drawer-visible #main-status-bar { + background-image: url(Images/statusbarResizerVertical.png), url(Images/statusbarBackgroundChromium.png); +} + +body.platform-windows .status-bar { + background-image: url(Images/statusbarBackgroundChromium.png); +} + +body.platform-windows button.status-bar-item { + background-image: url(Images/statusbarButtonsChromium.png); +} + +body.platform-windows select.status-bar-item:active { + -webkit-border-image: url(Images/statusbarMenuButtonSelectedChromium.png) 0 17 0 2; +} + +body.platform-windows #drawer { + background-image: url(Images/statusbarBottomBackgroundChromium.png); +} + +body.platform-windows select.status-bar-item { + -webkit-border-image: url(Images/statusbarMenuButtonChromium.png) 0 17 0 2; +} + +.scope-bar li.selected { + -webkit-box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.0); +} + +.scope-bar li:active { + -webkit-box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.0); +} + +.timeline-category-tree-item input { + vertical-align: middle; +} diff --git a/WebKit/chromium/tests/TransparencyWinTest.cpp b/WebKit/chromium/tests/TransparencyWinTest.cpp new file mode 100644 index 0000000..b83c2a9 --- /dev/null +++ b/WebKit/chromium/tests/TransparencyWinTest.cpp @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TransparencyWin.h" + +#include "AffineTransform.h" +#include "ImageBuffer.h" + +#include <gtest/gtest.h> +#include <windows.h> + +namespace WebCore { + +static FloatRect RECTToFloatRect(const RECT* rect) +{ + return FloatRect(static_cast<float>(rect->left), + static_cast<float>(rect->top), + static_cast<float>(rect->right - rect->left), + static_cast<float>(rect->bottom - rect->top)); +} + +static void drawNativeRect(GraphicsContext* context, + int x, int y, int w, int h) +{ + skia::PlatformCanvas* canvas = context->platformContext()->canvas(); + HDC dc = canvas->beginPlatformPaint(); + + RECT innerRc; + innerRc.left = x; + innerRc.top = y; + innerRc.right = x + w; + innerRc.bottom = y + h; + FillRect(dc, &innerRc, + reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))); + + canvas->endPlatformPaint(); +} + +static Color getPixelAt(GraphicsContext* context, int x, int y) +{ + const SkBitmap& bitmap = context->platformContext()->canvas()-> + getTopPlatformDevice().accessBitmap(false); + return Color(*reinterpret_cast<const RGBA32*>(bitmap.getAddr32(x, y))); +} + +// Resets the top layer's alpha channel to 0 for each pixel. This simulates +// Windows messing it up. +static void clearTopLayerAlphaChannel(GraphicsContext* context) +{ + SkBitmap& bitmap = const_cast<SkBitmap&>(context->platformContext()-> + canvas()->getTopPlatformDevice().accessBitmap(false)); + for (int y = 0; y < bitmap.height(); y++) { + uint32_t* row = bitmap.getAddr32(0, y); + for (int x = 0; x < bitmap.width(); x++) + row[x] &= 0x00FFFFFF; + } +} + +// Clears the alpha channel on the specified pixel. +static void clearTopLayerAlphaPixel(GraphicsContext* context, int x, int y) +{ + SkBitmap& bitmap = const_cast<SkBitmap&>(context->platformContext()-> + canvas()->getTopPlatformDevice().accessBitmap(false)); + *bitmap.getAddr32(x, y) &= 0x00FFFFFF; +} + +static std::ostream& operator<<(std::ostream& out, const Color& c) +{ + std::ios_base::fmtflags oldFlags = out.flags(std::ios_base::hex | + std::ios_base::showbase); + out << c.rgb(); + out.flags(oldFlags); + return out; +} + +TEST(TransparencyWin, NoLayer) +{ + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(17, 16), DeviceRGB)); + + // KeepTransform + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::NoLayer, + TransparencyWin::KeepTransform, + IntRect(1, 1, 14, 12)); + + EXPECT_TRUE(src->context() == helper.context()); + EXPECT_TRUE(IntSize(14, 12) == helper.m_layerSize); + EXPECT_TRUE(IntRect(1, 1, 14, 12) == helper.drawRect()); + } + + // Untransform is not allowed for NoLayer. + + // ScaleTransform + src->context()->save(); + src->context()->scale(FloatSize(2.0, 0.5)); + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::NoLayer, + TransparencyWin::ScaleTransform, + IntRect(2, 2, 6, 6)); + helper.composite(); + + // The coordinate system should be based in the upper left of our box. + // It should be post-transformed. + EXPECT_TRUE(src->context() == helper.context()); + EXPECT_TRUE(IntSize(12, 3) == helper.m_layerSize); + EXPECT_TRUE(IntRect(4, 1, 12, 3) == helper.drawRect()); + } + src->context()->restore(); +} + +TEST(TransparencyWin, WhiteLayer) +{ + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + + // KeepTransform + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::WhiteLayer, + TransparencyWin::KeepTransform, + IntRect(1, 1, 14, 12)); + helper.composite(); + + EXPECT_TRUE(src->context() != helper.context()); + EXPECT_TRUE(IntSize(14, 12) == helper.m_layerSize); + EXPECT_TRUE(IntRect(1, 1, 14, 12) == helper.drawRect()); + } + + // Untransform + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::WhiteLayer, + TransparencyWin::Untransform, + IntRect(1, 1, 14, 12)); + helper.composite(); + + EXPECT_TRUE(src->context() != helper.context()); + EXPECT_TRUE(IntSize(14, 12) == helper.m_layerSize); + EXPECT_TRUE(IntRect(0, 0, 14, 12) == helper.drawRect()); + } + + // ScaleTransform + src->context()->save(); + src->context()->scale(FloatSize(2.0, 0.5)); + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::WhiteLayer, + TransparencyWin::ScaleTransform, + IntRect(2, 2, 6, 6)); + helper.composite(); + + // The coordinate system should be based in the upper left of our box. + // It should be post-transformed. + EXPECT_TRUE(src->context() != helper.context()); + EXPECT_TRUE(IntSize(12, 3) == helper.m_layerSize); + EXPECT_TRUE(IntRect(0, 0, 12, 3) == helper.drawRect()); + } + src->context()->restore(); +} + +TEST(TransparencyWin, TextComposite) +{ + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + + // KeepTransform is the only valid transform mode for TextComposite. + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::TextComposite, + TransparencyWin::KeepTransform, + IntRect(1, 1, 14, 12)); + helper.composite(); + + EXPECT_TRUE(src->context() != helper.context()); + EXPECT_TRUE(IntSize(14, 12) == helper.m_layerSize); + EXPECT_TRUE(IntRect(1, 1, 14, 12) == helper.drawRect()); + } +} + +TEST(TransparencyWin, OpaqueCompositeLayer) +{ + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + + // KeepTransform + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::OpaqueCompositeLayer, + TransparencyWin::KeepTransform, + IntRect(1, 1, 14, 12)); + helper.composite(); + + EXPECT_TRUE(src->context() != helper.context()); + EXPECT_TRUE(IntSize(14, 12) == helper.m_layerSize); + EXPECT_TRUE(IntRect(1, 1, 14, 12) == helper.drawRect()); + } + + // KeepTransform with scroll applied. + src->context()->save(); + src->context()->translate(0, -1); + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::OpaqueCompositeLayer, + TransparencyWin::KeepTransform, + IntRect(1, 1, 14, 14)); + helper.composite(); + + EXPECT_TRUE(src->context() != helper.context()); + EXPECT_TRUE(IntSize(14, 14) == helper.m_layerSize); + EXPECT_TRUE(IntRect(1, 1, 14, 14) == helper.drawRect()); + } + src->context()->restore(); + + // Untransform + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::OpaqueCompositeLayer, + TransparencyWin::Untransform, + IntRect(1, 1, 14, 12)); + helper.composite(); + + EXPECT_TRUE(src->context() != helper.context()); + EXPECT_TRUE(IntSize(14, 12) == helper.m_layerSize); + EXPECT_TRUE(IntRect(0, 0, 14, 12) == helper.drawRect()); + } + + // ScaleTransform + src->context()->save(); + src->context()->scale(FloatSize(2.0, 0.5)); + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::OpaqueCompositeLayer, + TransparencyWin::ScaleTransform, + IntRect(2, 2, 6, 6)); + helper.composite(); + + // The coordinate system should be based in the upper left of our box. + // It should be post-transformed. + EXPECT_TRUE(src->context() != helper.context()); + EXPECT_TRUE(IntSize(12, 3) == helper.m_layerSize); + EXPECT_TRUE(IntRect(0, 0, 12, 3) == helper.drawRect()); + } + src->context()->restore(); +} + +TEST(TransparencyWin, WhiteLayerPixelTest) +{ + // Make a total transparent buffer, and draw the white layer inset by 1 px. + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::WhiteLayer, + TransparencyWin::KeepTransform, + IntRect(1, 1, 14, 14)); + + // Coordinates should be in the original space, not the layer. + drawNativeRect(helper.context(), 3, 3, 1, 1); + clearTopLayerAlphaChannel(helper.context()); + helper.composite(); + } + + // The final image should be transparent around the edges for 1 px, white + // in the middle, with (3,3) (what we drew above) being opaque black. + EXPECT_EQ(Color(Color::transparent), getPixelAt(src->context(), 0, 0)); + EXPECT_EQ(Color(Color::white), getPixelAt(src->context(), 2, 2)); + EXPECT_EQ(Color(Color::black), getPixelAt(src->context(), 3, 3)); + EXPECT_EQ(Color(Color::white), getPixelAt(src->context(), 4, 4)); +} + +TEST(TransparencyWin, OpaqueCompositeLayerPixel) +{ + Color red(0xFFFF0000), darkRed(0xFFBF0000); + Color green(0xFF00FF00); + + // Make a red bottom layer, followed by a half green next layer @ 50%. + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + + FloatRect fullRect(0, 0, 16, 16); + src->context()->fillRect(fullRect, red, DeviceColorSpace); + src->context()->beginTransparencyLayer(0.5); + FloatRect rightHalf(8, 0, 8, 16); + src->context()->fillRect(rightHalf, green, DeviceColorSpace); + + // Make a transparency layer inset by one pixel, and fill it inset by + // another pixel with 50% black. + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::OpaqueCompositeLayer, + TransparencyWin::KeepTransform, + IntRect(1, 1, 14, 14)); + + FloatRect inner(2, 2, 12, 12); + helper.context()->fillRect(inner, Color(0x7f000000), DeviceColorSpace); + // These coordinates are relative to the layer, whish is inset by 1x1 + // pixels from the top left. So we're actually clearing (2, 2) and + // (13,13), which are the extreme corners of the black area (and which + // we check below). + clearTopLayerAlphaPixel(helper.context(), 1, 1); + clearTopLayerAlphaPixel(helper.context(), 12, 12); + helper.composite(); + } + + // Finish the compositing. + src->context()->endTransparencyLayer(); + + // Check that we got the right values, it should be like the rectangle was + // drawn with half opacity even though the alpha channel got messed up. + EXPECT_EQ(red, getPixelAt(src->context(), 0, 0)); + EXPECT_EQ(red, getPixelAt(src->context(), 1, 1)); + EXPECT_EQ(darkRed, getPixelAt(src->context(), 2, 2)); + + // The dark result is: + // (black @ 50% atop green) @ 50% atop red = 0xFF804000 + // which is 0xFFA02000 (Skia computes 0xFFA11F00 due to rounding). + Color darkGreenRed(0xFF803f00); + EXPECT_EQ(darkGreenRed, getPixelAt(src->context(), 13, 13)); + + // 50% green on top of red = FF808000 (rounded to what Skia will produce). + Color greenRed(0xFF807F00); + EXPECT_EQ(greenRed, getPixelAt(src->context(), 14, 14)); + EXPECT_EQ(greenRed, getPixelAt(src->context(), 15, 15)); +} + +// Tests that translations are properly handled when using KeepTransform. +TEST(TransparencyWin, TranslateOpaqueCompositeLayer) +{ + // Fill with white. + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + Color white(0xFFFFFFFF); + FloatRect fullRect(0, 0, 16, 16); + src->context()->fillRect(fullRect, white, DeviceColorSpace); + + // Scroll down by 8 (coordinate system goes up). + src->context()->save(); + src->context()->translate(0, -8); + + Color red(0xFFFF0000); + Color green(0xFF00FF00); + { + // Make the transparency layer after translation will be @ (0, -8) with + // size 16x16. + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::OpaqueCompositeLayer, + TransparencyWin::KeepTransform, + IntRect(0, 0, 16, 16)); + + // Draw a red pixel at (15, 15). This should be the at (15, 7) after + // the transform. + FloatRect bottomRight(15, 15, 1, 1); + helper.context()->fillRect(bottomRight, green, DeviceColorSpace); + helper.composite(); + } + + src->context()->restore(); + + // Check the pixel we wrote. + EXPECT_EQ(green, getPixelAt(src->context(), 15, 7)); +} + +// Same as OpaqueCompositeLayer, but the canvas has a rotation applied. This +// tests that the propert transform is applied to the copied layer. +TEST(TransparencyWin, RotateOpaqueCompositeLayer) +{ + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + + // The background is white. + Color white(0xFFFFFFFF); + FloatRect fullRect(0, 0, 16, 16); + src->context()->fillRect(fullRect, white, DeviceColorSpace); + + // Rotate the image by 90 degrees. This matrix is the same as + // cw90.rotate(90); but avoids rounding errors. Rounding errors can cause + // Skia to think that !rectStaysRect() and it will fall through to path + // drawing mode, which in turn gives us antialiasing. We want no + // antialiasing or other rounding problems since we're testing exact pixel + // values. + src->context()->save(); + AffineTransform cw90(0, 1, -1, 0, 0, 0); + src->context()->concatCTM(cw90); + + // Make a transparency layer consisting of a horizontal line of 50% black. + // Since the rotation is applied, this will actually be a vertical line + // down the middle of the image. + src->context()->beginTransparencyLayer(0.5); + FloatRect blackRect(0, -9, 16, 2); + Color black(0xFF000000); + src->context()->fillRect(blackRect, black, DeviceColorSpace); + + // Now draw 50% red square. + { + // Create a transparency helper inset one pixel in the buffer. The + // coordinates are before transforming into this space, and maps to + // IntRect(1, 1, 14, 14). + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::OpaqueCompositeLayer, + TransparencyWin::Untransform, + IntRect(1, -15, 14, 14)); + + // Fill with red. + helper.context()->fillRect(helper.drawRect(), Color(0x7f7f0000), DeviceColorSpace); + clearTopLayerAlphaChannel(helper.context()); + helper.composite(); + } + + // Finish the compositing. + src->context()->endTransparencyLayer(); + + // Top corner should be the original background. + EXPECT_EQ(white, getPixelAt(src->context(), 0, 0)); + + // Check the stripe down the middle, first at the top... + Color gray(0xFF808080); + EXPECT_EQ(white, getPixelAt(src->context(), 6, 0)); + EXPECT_EQ(gray, getPixelAt(src->context(), 7, 0)); + EXPECT_EQ(gray, getPixelAt(src->context(), 8, 0)); + EXPECT_EQ(white, getPixelAt(src->context(), 9, 0)); + + // ...now at the bottom. + EXPECT_EQ(white, getPixelAt(src->context(), 6, 15)); + EXPECT_EQ(gray, getPixelAt(src->context(), 7, 15)); + EXPECT_EQ(gray, getPixelAt(src->context(), 8, 15)); + EXPECT_EQ(white, getPixelAt(src->context(), 9, 15)); + + // Our red square should be 25% red over the top of those two. + Color redwhite(0xFFdfbfbf); + Color redgray(0xFF9f8080); + EXPECT_EQ(white, getPixelAt(src->context(), 0, 1)); + EXPECT_EQ(redwhite, getPixelAt(src->context(), 1, 1)); + EXPECT_EQ(redwhite, getPixelAt(src->context(), 6, 1)); + EXPECT_EQ(redgray, getPixelAt(src->context(), 7, 1)); + EXPECT_EQ(redgray, getPixelAt(src->context(), 8, 1)); + EXPECT_EQ(redwhite, getPixelAt(src->context(), 9, 1)); + EXPECT_EQ(redwhite, getPixelAt(src->context(), 14, 1)); + EXPECT_EQ(white, getPixelAt(src->context(), 15, 1)); + + // Complete the 50% transparent layer. + src->context()->restore(); +} + +TEST(TransparencyWin, TranslateScaleOpaqueCompositeLayer) +{ + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + + // The background is white on top with red on bottom. + Color white(0xFFFFFFFF); + FloatRect topRect(0, 0, 16, 8); + src->context()->fillRect(topRect, white, DeviceColorSpace); + Color red(0xFFFF0000); + FloatRect bottomRect(0, 8, 16, 8); + src->context()->fillRect(bottomRect, red, DeviceColorSpace); + + src->context()->save(); + + // Translate left by one pixel. + AffineTransform left; + left.translate(-1, 0); + + // Scale by 2x. + AffineTransform scale; + scale.scale(2.0); + src->context()->concatCTM(scale); + + // Then translate up by one pixel (which will actually be 2 due to scaling). + AffineTransform up; + up.translate(0, -1); + src->context()->concatCTM(up); + + // Now draw 50% red square. + { + // Create a transparency helper inset one pixel in the buffer. The + // coordinates are before transforming into this space, and maps to + // IntRect(1, 1, 14, 14). + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::OpaqueCompositeLayer, + TransparencyWin::KeepTransform, + IntRect(1, -15, 14, 14)); + + // Fill with red. + helper.context()->fillRect(helper.drawRect(), Color(0x7f7f0000), DeviceColorSpace); + clearTopLayerAlphaChannel(helper.context()); + helper.composite(); + } +} + +// Tests scale mode with no additional copy. +TEST(TransparencyWin, Scale) +{ + // Create an opaque white buffer. + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + FloatRect fullBuffer(0, 0, 16, 16); + src->context()->fillRect(fullBuffer, Color::white, DeviceColorSpace); + + // Scale by 2x. + src->context()->save(); + AffineTransform scale; + scale.scale(2.0); + src->context()->concatCTM(scale); + + // Start drawing a rectangle from 1->4. This should get scaled to 2->8. + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::NoLayer, + TransparencyWin::ScaleTransform, + IntRect(1, 1, 3, 3)); + + // The context should now have the identity transform and the returned + // rect should be scaled. + EXPECT_TRUE(helper.context()->getCTM().isIdentity()); + EXPECT_EQ(2, helper.drawRect().x()); + EXPECT_EQ(2, helper.drawRect().y()); + EXPECT_EQ(8, helper.drawRect().right()); + EXPECT_EQ(8, helper.drawRect().bottom()); + + // Set the pixel at (2, 2) to be transparent. This should be fixed when + // the helper goes out of scope. We don't want to call + // clearTopLayerAlphaChannel because that will actually clear the whole + // canvas (since we have no extra layer!). + SkBitmap& bitmap = const_cast<SkBitmap&>(helper.context()-> + platformContext()->canvas()->getTopPlatformDevice(). + accessBitmap(false)); + *bitmap.getAddr32(2, 2) &= 0x00FFFFFF; + helper.composite(); + } + + src->context()->restore(); + + // Check the pixel we previously made transparent, it should have gotten + // fixed back up to white. + + // The current version doesn't fixup transparency when there is no layer. + // This seems not to be necessary, so we don't bother, but if it becomes + // necessary, this line should be uncommented. + // EXPECT_EQ(Color(Color::white), getPixelAt(src->context(), 2, 2)); +} + +// Tests scale mode with an additional copy for transparency. This will happen +// if we have a scaled textbox, for example. WebKit will create a new +// transparency layer, draw the text field, then draw the text into it, then +// composite this down with an opacity. +TEST(TransparencyWin, ScaleTransparency) +{ + // Create an opaque white buffer. + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + FloatRect fullBuffer(0, 0, 16, 16); + src->context()->fillRect(fullBuffer, Color::white, DeviceColorSpace); + + // Make another layer (which duplicates how WebKit will make this). We fill + // the top half with red, and have the layer be 50% opaque. + src->context()->beginTransparencyLayer(0.5); + FloatRect topHalf(0, 0, 16, 8); + src->context()->fillRect(topHalf, Color(0xFFFF0000), DeviceColorSpace); + + // Scale by 2x. + src->context()->save(); + AffineTransform scale; + scale.scale(2.0); + src->context()->concatCTM(scale); + + // Make a layer inset two pixels (because of scaling, this is 2->14). And + // will it with 50% black. + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::OpaqueCompositeLayer, + TransparencyWin::ScaleTransform, + IntRect(1, 1, 6, 6)); + + helper.context()->fillRect(helper.drawRect(), Color(0x7f000000), DeviceColorSpace); + clearTopLayerAlphaChannel(helper.context()); + helper.composite(); + } + + // Finish the layer. + src->context()->restore(); + src->context()->endTransparencyLayer(); + + Color redBackground(0xFFFF8080); // 50% red composited on white. + EXPECT_EQ(redBackground, getPixelAt(src->context(), 0, 0)); + EXPECT_EQ(redBackground, getPixelAt(src->context(), 1, 1)); + + // Top half (minus two pixel border) should be 50% gray atop opaque + // red = 0xFF804141. Then that's composited with 50% transparency on solid + // white = 0xFFC0A1A1. + Color darkRed(0xFFBF8080); + EXPECT_EQ(darkRed, getPixelAt(src->context(), 2, 2)); + EXPECT_EQ(darkRed, getPixelAt(src->context(), 7, 7)); + + // Bottom half (minus a two pixel border) should be a layer with 5% gray + // with another 50% opacity composited atop white. + Color darkWhite(0xFFBFBFBF); + EXPECT_EQ(darkWhite, getPixelAt(src->context(), 8, 8)); + EXPECT_EQ(darkWhite, getPixelAt(src->context(), 13, 13)); + + Color white(0xFFFFFFFF); // Background in the lower-right. + EXPECT_EQ(white, getPixelAt(src->context(), 14, 14)); + EXPECT_EQ(white, getPixelAt(src->context(), 15, 15)); +} + +TEST(TransparencyWin, Text) +{ + OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), DeviceRGB)); + + // Our text should end up 50% transparent blue-green. + Color fullResult(0x80008080); + + { + TransparencyWin helper; + helper.init(src->context(), + TransparencyWin::TextComposite, + TransparencyWin::KeepTransform, + IntRect(0, 0, 16, 16)); + helper.setTextCompositeColor(fullResult); + + // Write several different squares to simulate ClearType. These should + // all reduce to 2/3 coverage. + FloatRect pixel(0, 0, 1, 1); + helper.context()->fillRect(pixel, 0xFFFF0000, DeviceColorSpace); + pixel.move(1.0f, 0.0f); + helper.context()->fillRect(pixel, 0xFF00FF00, DeviceColorSpace); + pixel.move(1.0f, 0.0f); + helper.context()->fillRect(pixel, 0xFF0000FF, DeviceColorSpace); + pixel.move(1.0f, 0.0f); + helper.context()->fillRect(pixel, 0xFF008080, DeviceColorSpace); + pixel.move(1.0f, 0.0f); + helper.context()->fillRect(pixel, 0xFF800080, DeviceColorSpace); + pixel.move(1.0f, 0.0f); + helper.context()->fillRect(pixel, 0xFF808000, DeviceColorSpace); + + // Try one with 100% coverage (opaque black). + pixel.move(1.0f, 0.0f); + helper.context()->fillRect(pixel, 0xFF000000, DeviceColorSpace); + + // Now mess with the alpha channel. + clearTopLayerAlphaChannel(helper.context()); + helper.composite(); + } + + Color oneThirdResult(0x55005555); // = fullResult * 2 / 3 + EXPECT_EQ(oneThirdResult, getPixelAt(src->context(), 0, 0)); + EXPECT_EQ(oneThirdResult, getPixelAt(src->context(), 1, 0)); + EXPECT_EQ(oneThirdResult, getPixelAt(src->context(), 2, 0)); + EXPECT_EQ(oneThirdResult, getPixelAt(src->context(), 3, 0)); + EXPECT_EQ(oneThirdResult, getPixelAt(src->context(), 4, 0)); + EXPECT_EQ(oneThirdResult, getPixelAt(src->context(), 5, 0)); + EXPECT_EQ(fullResult, getPixelAt(src->context(), 6, 0)); + EXPECT_EQ(Color::transparent, getPixelAt(src->context(), 7, 0)); +} + +} // namespace WebCore diff --git a/WebKit/chromium/tests/UniscribeHelperTest.cpp b/WebKit/chromium/tests/UniscribeHelperTest.cpp new file mode 100644 index 0000000..8aaed11 --- /dev/null +++ b/WebKit/chromium/tests/UniscribeHelperTest.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include <gtest/gtest.h> + +#include "PlatformString.h" +#include "UniscribeHelper.h" + +using namespace WebCore; + +namespace { + +class UniscribeTest : public testing::Test { +public: + UniscribeTest() + { + } + + // Returns an HFONT with the given name. The caller does not have to free + // this, it will be automatically freed at the end of the test. Returns 0 + // on failure. On success, the + HFONT MakeFont(const wchar_t* fontName, SCRIPT_CACHE** cache) + { + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + lf.lfHeight = 20; + wcscpy_s(lf.lfFaceName, fontName); + + HFONT hfont = CreateFontIndirect(&lf); + if (!hfont) + return 0; + + *cache = new SCRIPT_CACHE; + **cache = 0; + createdFonts.append(std::make_pair(hfont, *cache)); + return hfont; + } + +protected: + // Default font properties structure for tests to use. + SCRIPT_FONTPROPERTIES properties; + +private: + virtual void SetUp() + { + memset(&properties, 0, sizeof(SCRIPT_FONTPROPERTIES)); + properties.cBytes = sizeof(SCRIPT_FONTPROPERTIES); + properties.wgBlank = ' '; + properties.wgDefault = '?'; // Used when the char is not in the font. + properties.wgInvalid = '#'; // Used for invalid characters. + } + + virtual void TearDown() + { + // Free any allocated fonts. + for (size_t i = 0; i < createdFonts.size(); i++) { + DeleteObject(createdFonts[i].first); + ScriptFreeCache(createdFonts[i].second); + delete createdFonts[i].second; + } + createdFonts.clear(); + } + + // Tracks allocated fonts so we can delete them at the end of the test. + // The script cache pointer is heap allocated and must be freed. + Vector< std::pair<HFONT, SCRIPT_CACHE*> > createdFonts; +}; + +} // namespace + +// This test tests giving Uniscribe a very large buffer, which will cause a +// failure. +TEST_F(UniscribeTest, TooBig) +{ + // Make a large string with an e with a zillion combining accents. + String input(L"e"); + for (int i = 0; i < 100000; i++) + input.append(static_cast<UChar>(0x301)); // Combining acute accent. + + SCRIPT_CACHE* scriptCache; + HFONT hfont = MakeFont(L"Times New Roman", &scriptCache); + ASSERT_TRUE(hfont); + + // Test a long string without the normal length protection we have. This + // will cause shaping to fail. + { + UniscribeHelper uniscribe( + input.characters(), static_cast<int>(input.length()), + false, hfont, scriptCache, &properties); + uniscribe.initWithOptionalLengthProtection(false); + + // There should be one shaping entry, with nothing in it. + ASSERT_EQ(1, uniscribe.m_shapes.size()); + EXPECT_EQ(0, uniscribe.m_shapes[0].m_glyphs.size()); + EXPECT_EQ(0, uniscribe.m_shapes[0].m_logs.size()); + EXPECT_EQ(0, uniscribe.m_shapes[0].m_visualAttributes.size()); + EXPECT_EQ(0, uniscribe.m_shapes[0].m_advance.size()); + EXPECT_EQ(0, uniscribe.m_shapes[0].m_offsets.size()); + EXPECT_EQ(0, uniscribe.m_shapes[0].m_justify.size()); + EXPECT_EQ(0, uniscribe.m_shapes[0].m_abc.abcA); + EXPECT_EQ(0, uniscribe.m_shapes[0].m_abc.abcB); + EXPECT_EQ(0, uniscribe.m_shapes[0].m_abc.abcC); + + // The sizes of the other stuff should match the shaping entry. + EXPECT_EQ(1, uniscribe.m_runs.size()); + EXPECT_EQ(1, uniscribe.m_screenOrder.size()); + + // Check that the various querying functions handle the empty case + // properly. + EXPECT_EQ(0, uniscribe.width()); + EXPECT_EQ(0, uniscribe.firstGlyphForCharacter(0)); + EXPECT_EQ(0, uniscribe.firstGlyphForCharacter(1000)); + EXPECT_EQ(0, uniscribe.xToCharacter(0)); + EXPECT_EQ(0, uniscribe.xToCharacter(1000)); + } + + // Now test the very large string and make sure it is handled properly by + // the length protection. + { + UniscribeHelper uniscribe( + input.characters(), static_cast<int>(input.length()), + false, hfont, scriptCache, &properties); + uniscribe.initWithOptionalLengthProtection(true); + + // There should be 0 runs and shapes. + EXPECT_EQ(0, uniscribe.m_runs.size()); + EXPECT_EQ(0, uniscribe.m_shapes.size()); + EXPECT_EQ(0, uniscribe.m_screenOrder.size()); + + EXPECT_EQ(0, uniscribe.width()); + EXPECT_EQ(0, uniscribe.firstGlyphForCharacter(0)); + EXPECT_EQ(0, uniscribe.firstGlyphForCharacter(1000)); + EXPECT_EQ(0, uniscribe.xToCharacter(0)); + EXPECT_EQ(0, uniscribe.xToCharacter(1000)); + } +} |