summaryrefslogtreecommitdiff
path: root/Tools/DumpRenderTree
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
commit40736c5763bf61337c8c14e16d8587db021a87d4 (patch)
treeb17a9c00042ad89cb1308e2484491799aa14e9f8 /Tools/DumpRenderTree
downloadqtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Tools/DumpRenderTree')
-rw-r--r--Tools/DumpRenderTree/AccessibilityController.cpp151
-rw-r--r--Tools/DumpRenderTree/AccessibilityController.h85
-rw-r--r--Tools/DumpRenderTree/AccessibilityTextMarker.cpp134
-rw-r--r--Tools/DumpRenderTree/AccessibilityTextMarker.h105
-rw-r--r--Tools/DumpRenderTree/AccessibilityUIElement.cpp1122
-rw-r--r--Tools/DumpRenderTree/AccessibilityUIElement.h236
-rw-r--r--Tools/DumpRenderTree/CyclicRedundancyCheck.cpp64
-rw-r--r--Tools/DumpRenderTree/CyclicRedundancyCheck.h38
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.gypi97
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.h66
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.sln100
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj1153
-rw-r--r--Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h39
-rw-r--r--Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m38
-rw-r--r--Tools/DumpRenderTree/DumpRenderTreePrefix.h38
-rwxr-xr-xTools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/Assertions.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/Atomics.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/Compiler.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h1
-rwxr-xr-xTools/DumpRenderTree/ForwardingHeaders/wtf/ExportMacros.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/HashMap.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/HashSet.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/HashTraits.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/Locker.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/MainThread.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/MathExtras.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/Noncopyable.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnArrayPtr.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtrCommon.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/PassOwnPtr.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/Platform.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/RefCounted.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/RetainPtr.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/StdLibExtras.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/TemporaryChange.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeRefCounted.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/Threading.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadingPrimitives.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/Vector.h1
-rw-r--r--Tools/DumpRenderTree/GCController.cpp100
-rw-r--r--Tools/DumpRenderTree/GCController.h50
-rw-r--r--Tools/DumpRenderTree/JavaScriptThreading.h40
-rw-r--r--Tools/DumpRenderTree/LayoutTestController.cpp2607
-rw-r--r--Tools/DumpRenderTree/LayoutTestController.h441
-rw-r--r--Tools/DumpRenderTree/Makefile2
-rw-r--r--Tools/DumpRenderTree/PixelDumpSupport.cpp136
-rw-r--r--Tools/DumpRenderTree/PixelDumpSupport.h55
-rw-r--r--Tools/DumpRenderTree/StorageTrackerDelegate.h37
-rw-r--r--Tools/DumpRenderTree/StorageTrackerDelegate.mm82
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp1267
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h96
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm100
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp272
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h269
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp209
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.h30
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp56
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp64
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/FormValue.cpp53
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp72
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp112
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp48
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp56
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp94
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp125
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp88
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp170
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp70
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp70
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp68
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PrivateBrowsing.cpp106
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ContentsScaleFactor.cpp107
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp82
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/SupportsCarbonEventModel.cpp62
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp118
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DumpWindowRect.cpp66
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp73
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp188
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp78
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp98
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowlessPaintRectCoordinates.cpp83
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp50
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist69
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp833
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/CallJSThatDestroysPlugin.cpp112
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def6
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc102
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj556
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops19
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebug.vsprops8
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugAll.vsprops8
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd1
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd6
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops8
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops8
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def6
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.cpp130
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.h61
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp76
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h51
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/resource.h14
-rw-r--r--Tools/DumpRenderTree/WorkQueue.cpp108
-rw-r--r--Tools/DumpRenderTree/WorkQueue.h53
-rw-r--r--Tools/DumpRenderTree/WorkQueueItem.h149
-rw-r--r--Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp93
-rw-r--r--Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h81
-rw-r--r--Tools/DumpRenderTree/cf/WebArchiveDumpSupport.cpp230
-rw-r--r--Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h41
-rw-r--r--Tools/DumpRenderTree/cg/ImageDiffCG.cpp254
-rw-r--r--Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp113
-rw-r--r--Tools/DumpRenderTree/cg/PixelDumpSupportCG.h84
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityController.cpp151
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityController.h83
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp817
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityUIElement.h164
-rw-r--r--Tools/DumpRenderTree/chromium/CppBoundClass.cpp352
-rw-r--r--Tools/DumpRenderTree/chromium/CppBoundClass.h245
-rw-r--r--Tools/DumpRenderTree/chromium/CppVariant.cpp321
-rw-r--r--Tools/DumpRenderTree/chromium/CppVariant.h141
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp131
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h96
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp102
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsClient.h87
-rw-r--r--Tools/DumpRenderTree/chromium/DumpRenderTree.cpp290
-rw-r--r--Tools/DumpRenderTree/chromium/EventSender.cpp1130
-rw-r--r--Tools/DumpRenderTree/chromium/EventSender.h179
-rw-r--r--Tools/DumpRenderTree/chromium/GamepadController.cpp171
-rw-r--r--Tools/DumpRenderTree/chromium/GamepadController.h67
-rw-r--r--Tools/DumpRenderTree/chromium/ImageDiff.cpp521
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestController.cpp2152
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestController.h701
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestHelper.mm118
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp84
-rw-r--r--Tools/DumpRenderTree/chromium/MockSpellCheck.cpp164
-rw-r--r--Tools/DumpRenderTree/chromium/MockSpellCheck.h84
-rw-r--r--Tools/DumpRenderTree/chromium/NotificationPresenter.cpp154
-rw-r--r--Tools/DumpRenderTree/chromium/NotificationPresenter.h78
-rw-r--r--Tools/DumpRenderTree/chromium/PlainTextController.cpp79
-rw-r--r--Tools/DumpRenderTree/chromium/PlainTextController.h52
-rw-r--r--Tools/DumpRenderTree/chromium/Task.cpp79
-rw-r--r--Tools/DumpRenderTree/chromium/Task.h96
-rw-r--r--Tools/DumpRenderTree/chromium/TestEventPrinter.cpp184
-rw-r--r--Tools/DumpRenderTree/chromium/TestEventPrinter.h52
-rw-r--r--Tools/DumpRenderTree/chromium/TestNavigationController.cpp277
-rw-r--r--Tools/DumpRenderTree/chromium/TestNavigationController.h211
-rw-r--r--Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h9
-rw-r--r--Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h8
-rw-r--r--Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h1
-rw-r--r--Tools/DumpRenderTree/chromium/TestShell.cpp768
-rw-r--r--Tools/DumpRenderTree/chromium/TestShell.h253
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellGtk.cpp52
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellLinux.cpp219
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellMac.mm149
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellStub.cpp45
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellWin.cpp217
-rw-r--r--Tools/DumpRenderTree/chromium/TestWebPlugin.cpp326
-rw-r--r--Tools/DumpRenderTree/chromium/TestWebPlugin.h126
-rw-r--r--Tools/DumpRenderTree/chromium/TestWebWorker.h93
-rw-r--r--Tools/DumpRenderTree/chromium/TextInputController.cpp249
-rw-r--r--Tools/DumpRenderTree/chromium/TextInputController.h74
-rw-r--r--Tools/DumpRenderTree/chromium/WebPermissions.cpp132
-rw-r--r--Tools/DumpRenderTree/chromium/WebPermissions.h79
-rw-r--r--Tools/DumpRenderTree/chromium/WebPreferences.cpp243
-rw-r--r--Tools/DumpRenderTree/chromium/WebPreferences.h119
-rwxr-xr-xTools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp527
-rw-r--r--Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h203
-rw-r--r--Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.h59
-rw-r--r--Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.mm202
-rwxr-xr-xTools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp787
-rw-r--r--Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h98
-rw-r--r--Tools/DumpRenderTree/chromium/WebViewHost.cpp1687
-rw-r--r--Tools/DumpRenderTree/chromium/WebViewHost.h368
-rw-r--r--Tools/DumpRenderTree/chromium/config.h53
-rw-r--r--Tools/DumpRenderTree/chromium/fonts.conf229
-rw-r--r--Tools/DumpRenderTree/config.h87
-rw-r--r--Tools/DumpRenderTree/efl/CMakeLists.txt132
-rw-r--r--Tools/DumpRenderTree/efl/DumpHistoryItem.cpp134
-rw-r--r--Tools/DumpRenderTree/efl/DumpHistoryItem.h33
-rw-r--r--Tools/DumpRenderTree/efl/DumpRenderTree.cpp416
-rw-r--r--Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp282
-rw-r--r--Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h80
-rw-r--r--Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h41
-rw-r--r--Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp113
-rw-r--r--Tools/DumpRenderTree/efl/DumpRenderTreeView.h32
-rw-r--r--Tools/DumpRenderTree/efl/EventSender.cpp507
-rw-r--r--Tools/DumpRenderTree/efl/EventSender.h41
-rw-r--r--Tools/DumpRenderTree/efl/FontManagement.cpp132
-rw-r--r--Tools/DumpRenderTree/efl/FontManagement.h31
-rw-r--r--Tools/DumpRenderTree/efl/GCControllerEfl.cpp49
-rw-r--r--Tools/DumpRenderTree/efl/ImageDiff.cpp359
-rw-r--r--Tools/DumpRenderTree/efl/JSStringUtils.cpp38
-rw-r--r--Tools/DumpRenderTree/efl/JSStringUtils.h38
-rw-r--r--Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp785
-rw-r--r--Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp71
-rw-r--r--Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp79
-rw-r--r--Tools/DumpRenderTree/fonts/WebKit Layout Tests 2.ttfbin0 -> 28812 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKit Layout Tests.ttfbin0 -> 28780 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKitWeightWatcher100.ttfbin0 -> 28512 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKitWeightWatcher200.ttfbin0 -> 28512 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKitWeightWatcher300.ttfbin0 -> 28492 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKitWeightWatcher400.ttfbin0 -> 28440 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKitWeightWatcher500.ttfbin0 -> 28424 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKitWeightWatcher600.ttfbin0 -> 28460 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKitWeightWatcher700.ttfbin0 -> 28384 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKitWeightWatcher800.ttfbin0 -> 28492 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/WebKitWeightWatcher900.ttfbin0 -> 28492 bytes
-rw-r--r--Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp155
-rw-r--r--Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h35
-rw-r--r--Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp107
-rw-r--r--Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp820
-rw-r--r--Tools/DumpRenderTree/gtk/DumpRenderTree.cpp1208
-rw-r--r--Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h46
-rw-r--r--Tools/DumpRenderTree/gtk/EditingCallbacks.cpp206
-rw-r--r--Tools/DumpRenderTree/gtk/EditingCallbacks.h35
-rw-r--r--Tools/DumpRenderTree/gtk/EventSender.cpp898
-rw-r--r--Tools/DumpRenderTree/gtk/EventSender.h42
-rw-r--r--Tools/DumpRenderTree/gtk/GCControllerGtk.cpp50
-rw-r--r--Tools/DumpRenderTree/gtk/GNUmakefile.ImageDiff.am28
-rw-r--r--Tools/DumpRenderTree/gtk/ImageDiff.cpp239
-rw-r--r--Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp1038
-rw-r--r--Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp73
-rw-r--r--Tools/DumpRenderTree/gtk/PlainTextController.cpp65
-rw-r--r--Tools/DumpRenderTree/gtk/PlainTextController.h37
-rw-r--r--Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp78
-rw-r--r--Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h51
-rw-r--r--Tools/DumpRenderTree/gtk/TextInputController.cpp215
-rw-r--r--Tools/DumpRenderTree/gtk/TextInputController.h37
-rw-r--r--Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp102
-rw-r--r--Tools/DumpRenderTree/gtk/fonts/AHEM____.TTFbin0 -> 12480 bytes
-rw-r--r--Tools/DumpRenderTree/gtk/fonts/FontWithNoValidEncoding.fonbin0 -> 8368 bytes
-rw-r--r--Tools/DumpRenderTree/gtk/fonts/fonts.conf419
-rw-r--r--Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm108
-rw-r--r--Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.h48
-rw-r--r--Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.mm131
-rw-r--r--Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm81
-rw-r--r--Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm1394
-rw-r--r--Tools/DumpRenderTree/mac/AppleScriptController.h39
-rw-r--r--Tools/DumpRenderTree/mac/AppleScriptController.m127
-rw-r--r--Tools/DumpRenderTree/mac/CheckedMalloc.cpp92
-rw-r--r--Tools/DumpRenderTree/mac/CheckedMalloc.h31
-rw-r--r--Tools/DumpRenderTree/mac/Configurations/Base.xcconfig62
-rw-r--r--Tools/DumpRenderTree/mac/Configurations/CompilerVersion.xcconfig84
-rw-r--r--Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig40
-rw-r--r--Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig28
-rw-r--r--Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig24
-rw-r--r--Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig29
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTree.mm1353
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h53
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm146
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreeMac.h71
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h38
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m206
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h46
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm118
-rw-r--r--Tools/DumpRenderTree/mac/EditingDelegate.h38
-rw-r--r--Tools/DumpRenderTree/mac/EditingDelegate.mm192
-rw-r--r--Tools/DumpRenderTree/mac/EventSendingController.h55
-rw-r--r--Tools/DumpRenderTree/mac/EventSendingController.mm873
-rw-r--r--Tools/DumpRenderTree/mac/FrameLoadDelegate.h42
-rw-r--r--Tools/DumpRenderTree/mac/FrameLoadDelegate.mm423
-rw-r--r--Tools/DumpRenderTree/mac/GCControllerMac.mm49
-rw-r--r--Tools/DumpRenderTree/mac/HistoryDelegate.h32
-rw-r--r--Tools/DumpRenderTree/mac/HistoryDelegate.mm81
-rw-r--r--Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h1
-rw-r--r--Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm1243
-rw-r--r--Tools/DumpRenderTree/mac/MockGeolocationProvider.h47
-rw-r--r--Tools/DumpRenderTree/mac/MockGeolocationProvider.mm112
-rw-r--r--Tools/DumpRenderTree/mac/NavigationController.h39
-rw-r--r--Tools/DumpRenderTree/mac/NavigationController.m112
-rw-r--r--Tools/DumpRenderTree/mac/ObjCController.h38
-rw-r--r--Tools/DumpRenderTree/mac/ObjCController.m296
-rw-r--r--Tools/DumpRenderTree/mac/ObjCPlugin.h36
-rw-r--r--Tools/DumpRenderTree/mac/ObjCPlugin.m207
-rw-r--r--Tools/DumpRenderTree/mac/ObjCPluginFunction.h34
-rw-r--r--Tools/DumpRenderTree/mac/ObjCPluginFunction.m37
-rw-r--r--Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c42
-rw-r--r--Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm54
-rw-r--r--Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c1167
-rw-r--r--Tools/DumpRenderTree/mac/PerlSupport/Makefile82
-rw-r--r--Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm263
-rw-r--r--Tools/DumpRenderTree/mac/PlainTextController.h28
-rw-r--r--Tools/DumpRenderTree/mac/PlainTextController.mm60
-rw-r--r--Tools/DumpRenderTree/mac/PolicyDelegate.h41
-rw-r--r--Tools/DumpRenderTree/mac/PolicyDelegate.mm113
-rw-r--r--Tools/DumpRenderTree/mac/ResourceLoadDelegate.h35
-rw-r--r--Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm262
-rw-r--r--Tools/DumpRenderTree/mac/TextInputController.h42
-rw-r--r--Tools/DumpRenderTree/mac/TextInputController.m431
-rw-r--r--Tools/DumpRenderTree/mac/UIDelegate.h42
-rw-r--r--Tools/DumpRenderTree/mac/UIDelegate.mm280
-rw-r--r--Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm77
-rw-r--r--Tools/DumpRenderTree/mac/WorkQueueItemMac.mm97
-rw-r--r--Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp148
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTree.pro61
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTree.qrc5
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp1185
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTreeQt.h236
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.cpp679
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.h113
-rw-r--r--Tools/DumpRenderTree/qt/GCControllerQt.cpp54
-rw-r--r--Tools/DumpRenderTree/qt/GCControllerQt.h50
-rw-r--r--Tools/DumpRenderTree/qt/ImageDiff.cpp151
-rw-r--r--Tools/DumpRenderTree/qt/ImageDiff.pro15
-rw-r--r--Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp1023
-rw-r--r--Tools/DumpRenderTree/qt/LayoutTestControllerQt.h321
-rw-r--r--Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp44
-rw-r--r--Tools/DumpRenderTree/qt/PlainTextControllerQt.h47
-rw-r--r--Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro60
-rw-r--r--Tools/DumpRenderTree/qt/TextInputControllerQt.cpp163
-rw-r--r--Tools/DumpRenderTree/qt/TextInputControllerQt.h57
-rw-r--r--Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp119
-rw-r--r--Tools/DumpRenderTree/qt/WorkQueueItemQt.h177
-rw-r--r--Tools/DumpRenderTree/qt/fonts.conf258
-rw-r--r--Tools/DumpRenderTree/qt/fonts/AHEM____.TTFbin0 -> 12480 bytes
-rw-r--r--Tools/DumpRenderTree/qt/main.cpp249
-rw-r--r--Tools/DumpRenderTree/qt/resources/user.css4
-rw-r--r--Tools/DumpRenderTree/qt/testplugin.cpp67
-rw-r--r--Tools/DumpRenderTree/qt/testplugin.h45
-rw-r--r--Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h1
-rw-r--r--Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h1
-rw-r--r--Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h1
-rw-r--r--Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp330
-rw-r--r--Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp698
-rw-r--r--Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp145
-rw-r--r--Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.h66
-rw-r--r--Tools/DumpRenderTree/win/DraggingInfo.h67
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTree.cpp1459
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTree.vcproj728
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeApple.vsprops15
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeCFLite.vsprops11
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeCairo.vsprops15
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops21
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeDebug.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeDebugAll.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeDebugCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeLauncher.vcproj396
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeLauncherCommon.vsprops18
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebug.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugAll.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeLauncherProduction.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeLauncherRelease.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeLauncherReleaseCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd62
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd20
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeWin.h71
-rw-r--r--Tools/DumpRenderTree/win/EditingDelegate.cpp424
-rw-r--r--Tools/DumpRenderTree/win/EditingDelegate.h176
-rw-r--r--Tools/DumpRenderTree/win/EventSender.cpp693
-rw-r--r--Tools/DumpRenderTree/win/EventSender.h43
-rw-r--r--Tools/DumpRenderTree/win/FrameLoadDelegate.cpp438
-rw-r--r--Tools/DumpRenderTree/win/FrameLoadDelegate.h175
-rw-r--r--Tools/DumpRenderTree/win/GCControllerWin.cpp61
-rw-r--r--Tools/DumpRenderTree/win/HistoryDelegate.cpp221
-rw-r--r--Tools/DumpRenderTree/win/HistoryDelegate.h72
-rw-r--r--Tools/DumpRenderTree/win/ImageDiff.vcproj452
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffCairo.cpp260
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffCommon.vsprops19
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffDebug.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffDebugAll.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffLauncher.vcproj396
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffLauncherCommon.vsprops18
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffLauncherDebug.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffLauncherDebugAll.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffLauncherDebugCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffLauncherProduction.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffLauncherRelease.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffLauncherReleaseCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd1
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd6
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffProduction.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffRelease.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops8
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffWin.cpp33
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops18
-rw-r--r--Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp1563
-rw-r--r--Tools/DumpRenderTree/win/MD5.cpp78
-rw-r--r--Tools/DumpRenderTree/win/MD5.h45
-rw-r--r--Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp99
-rw-r--r--Tools/DumpRenderTree/win/PolicyDelegate.cpp187
-rw-r--r--Tools/DumpRenderTree/win/PolicyDelegate.h82
-rw-r--r--Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp372
-rw-r--r--Tools/DumpRenderTree/win/ResourceLoadDelegate.h119
-rw-r--r--Tools/DumpRenderTree/win/UIDelegate.cpp664
-rw-r--r--Tools/DumpRenderTree/win/UIDelegate.h415
-rw-r--r--Tools/DumpRenderTree/win/WorkQueueItemWin.cpp168
-rw-r--r--Tools/DumpRenderTree/wscript65
-rw-r--r--Tools/DumpRenderTree/wx/DumpRenderTreeWx.cpp339
-rw-r--r--Tools/DumpRenderTree/wx/DumpRenderTreeWx.h34
-rw-r--r--Tools/DumpRenderTree/wx/GCControllerWx.cpp43
-rw-r--r--Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp668
-rw-r--r--Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp57
408 files changed, 70902 insertions, 0 deletions
diff --git a/Tools/DumpRenderTree/AccessibilityController.cpp b/Tools/DumpRenderTree/AccessibilityController.cpp
new file mode 100644
index 000000000..b367d5c46
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityController.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityController.h"
+
+#include "AccessibilityUIElement.h"
+#include <JavaScriptCore/JSRetainPtr.h>
+
+// Static Value Getters
+
+static JSValueRef getFocusedElementCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, controller->focusedElement());
+}
+
+static JSValueRef getRootElementCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, controller->rootElement());
+}
+
+// Object Creation
+
+void AccessibilityController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> accessibilityControllerStr(Adopt, JSStringCreateWithUTF8CString("accessibilityController"));
+
+ JSClassRef classRef = getJSClass();
+ JSValueRef accessibilityControllerObject = JSObjectMake(context, classRef, this);
+ JSClassRelease(classRef);
+
+ JSObjectSetProperty(context, windowObject, accessibilityControllerStr.get(), accessibilityControllerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
+}
+
+static JSValueRef logFocusEventsCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ controller->setLogFocusEvents(true);
+ return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef logValueChangeEventsCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ controller->setLogValueChangeEvents(true);
+ return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef logScrollingStartEventsCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ controller->setLogScrollingStartEvents(true);
+ return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef logAccessibilityEventsCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ controller->setLogAccessibilityEvents(true);
+ return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef getElementAtPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int x = 0;
+ int y = 0;
+ if (argumentCount == 2) {
+ x = JSValueToNumber(context, arguments[0], exception);
+ y = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, controller->elementAtPoint(x, y));
+}
+
+static JSValueRef addNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 1)
+ return JSValueMakeBoolean(context, false);
+
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ JSObjectRef callback = JSValueToObject(context, arguments[0], exception);
+ bool succeeded = controller->addNotificationListener(callback);
+ return JSValueMakeBoolean(context, succeeded);
+}
+
+static JSValueRef removeNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ controller->removeNotificationListener();
+ return JSValueMakeUndefined(context);
+}
+
+JSClassRef AccessibilityController::getJSClass()
+{
+ static JSStaticFunction staticFunctions[] = {
+ { "logFocusEvents", logFocusEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "logValueChangeEvents", logValueChangeEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "logScrollingStartEvents", logScrollingStartEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "logAccessibilityEvents", logAccessibilityEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "elementAtPoint", getElementAtPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addNotificationListener", addNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "removeNotificationListener", removeNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+ };
+
+ static JSStaticValue staticValues[] = {
+ { "focusedElement", getFocusedElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "rootElement", getRootElementCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0, 0 }
+ };
+
+ static JSClassDefinition classDefinition = {
+ 0, kJSClassAttributeNone, "AccessibilityController", 0, staticValues, staticFunctions,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ return JSClassCreate(&classDefinition);
+}
+
+void AccessibilityController::resetToConsistentState()
+{
+ setLogFocusEvents(false);
+ setLogValueChangeEvents(false);
+ setLogScrollingStartEvents(false);
+ setLogAccessibilityEvents(false);
+}
diff --git a/Tools/DumpRenderTree/AccessibilityController.h b/Tools/DumpRenderTree/AccessibilityController.h
new file mode 100644
index 000000000..1d52353cd
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityController.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AccessibilityController_h
+#define AccessibilityController_h
+
+#include "AccessibilityUIElement.h"
+#include <JavaScriptCore/JSObjectRef.h>
+#include <string>
+#include <wtf/HashMap.h>
+#include <wtf/Platform.h>
+#if PLATFORM(WIN)
+#include <windows.h>
+#endif
+
+class AccessibilityController {
+public:
+ AccessibilityController();
+ ~AccessibilityController();
+
+ void makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception);
+
+ // Controller Methods - platform-independent implementations
+ AccessibilityUIElement rootElement();
+ AccessibilityUIElement focusedElement();
+ AccessibilityUIElement elementAtPoint(int x, int y);
+
+ void setLogFocusEvents(bool);
+ void setLogValueChangeEvents(bool);
+ void setLogScrollingStartEvents(bool);
+ void setLogAccessibilityEvents(bool);
+
+ void resetToConsistentState();
+
+ // Global notification listener, captures notifications on any object.
+ bool addNotificationListener(JSObjectRef functionCallback);
+ void removeNotificationListener();
+
+#if PLATFORM(WIN)
+ // Helper methods so this class can add the listeners on behalf of AccessibilityUIElement.
+ void winAddNotificationListener(PlatformUIElement, JSObjectRef functionCallback);
+ void winNotificationReceived(PlatformUIElement, const std::string& eventName);
+#endif
+
+private:
+ static JSClassRef getJSClass();
+
+#if PLATFORM(WIN)
+ HWINEVENTHOOK m_focusEventHook;
+ HWINEVENTHOOK m_valueChangeEventHook;
+ HWINEVENTHOOK m_scrollingStartEventHook;
+
+ HWINEVENTHOOK m_allEventsHook;
+ HWINEVENTHOOK m_notificationsEventHook;
+ HashMap<PlatformUIElement, JSObjectRef> m_notificationListeners;
+#endif
+
+#if PLATFORM(MAC)
+ RetainPtr<NotificationHandler> m_globalNotificationHandler;
+#endif
+};
+
+#endif // AccessibilityController_h
diff --git a/Tools/DumpRenderTree/AccessibilityTextMarker.cpp b/Tools/DumpRenderTree/AccessibilityTextMarker.cpp
new file mode 100644
index 000000000..12504978b
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityTextMarker.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityTextMarker.h"
+
+#include "AccessibilityUIElement.h"
+#include <JavaScriptCore/JSRetainPtr.h>
+
+// MARK: AccessibilityTextMarker
+
+// Callback methods
+
+AccessibilityTextMarker* toTextMarker(JSObjectRef object)
+{
+ return static_cast<AccessibilityTextMarker*>(JSObjectGetPrivate(object));
+}
+
+static JSValueRef isMarkerEqualCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 1)
+ return JSValueMakeBoolean(context, false);
+
+ JSObjectRef otherMarker = JSValueToObject(context, arguments[0], exception);
+ return JSValueMakeBoolean(context, toTextMarker(thisObject)->isEqual(toTextMarker(otherMarker)));
+}
+
+// Destruction
+
+static void markerFinalize(JSObjectRef thisObject)
+{
+ delete toTextMarker(thisObject);
+}
+
+// Object Creation
+
+JSObjectRef AccessibilityTextMarker::makeJSAccessibilityTextMarker(JSContextRef context, const AccessibilityTextMarker& element)
+{
+ return JSObjectMake(context, AccessibilityTextMarker::getJSClass(), new AccessibilityTextMarker(element));
+}
+
+JSClassRef AccessibilityTextMarker::getJSClass()
+{
+ static JSStaticValue staticValues[] = {
+ { 0, 0, 0, 0 }
+ };
+
+ static JSStaticFunction staticFunctions[] = {
+ { "isEqual", isMarkerEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+ };
+
+ static JSClassDefinition classDefinition = {
+ 0, kJSClassAttributeNone, "AccessibilityTextMarker", 0, staticValues, staticFunctions,
+ 0, markerFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ static JSClassRef accessibilityTextMarkerClass = JSClassCreate(&classDefinition);
+ return accessibilityTextMarkerClass;
+}
+
+// MARK: AccessibilityTextMarkerRange
+
+// Callback methods
+
+AccessibilityTextMarkerRange* toTextMarkerRange(JSObjectRef object)
+{
+ return static_cast<AccessibilityTextMarkerRange*>(JSObjectGetPrivate(object));
+}
+
+static JSValueRef isMarkerRangeEqualCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 1)
+ return JSValueMakeBoolean(context, false);
+
+ JSObjectRef otherMarker = JSValueToObject(context, arguments[0], exception);
+ return JSValueMakeBoolean(context, toTextMarkerRange(thisObject)->isEqual(toTextMarkerRange(otherMarker)));
+}
+
+// Destruction
+
+static void markerRangeFinalize(JSObjectRef thisObject)
+{
+ delete toTextMarkerRange(thisObject);
+}
+
+// Object Creation
+
+JSObjectRef AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(JSContextRef context, const AccessibilityTextMarkerRange& element)
+{
+ return JSObjectMake(context, AccessibilityTextMarkerRange::getJSClass(), new AccessibilityTextMarkerRange(element));
+}
+
+JSClassRef AccessibilityTextMarkerRange::getJSClass()
+{
+ static JSStaticValue staticValues[] = {
+ { 0, 0, 0, 0 }
+ };
+
+ static JSStaticFunction staticFunctions[] = {
+ { "isEqual", isMarkerRangeEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+ };
+
+ static JSClassDefinition classDefinition = {
+ 0, kJSClassAttributeNone, "AccessibilityTextMarkerRange", 0, staticValues, staticFunctions,
+ 0, markerRangeFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ static JSClassRef accessibilityTextMarkerRangeClass = JSClassCreate(&classDefinition);
+ return accessibilityTextMarkerRangeClass;
+}
diff --git a/Tools/DumpRenderTree/AccessibilityTextMarker.h b/Tools/DumpRenderTree/AccessibilityTextMarker.h
new file mode 100644
index 000000000..aeb078d78
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityTextMarker.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AccessibilityTextMarker_h
+#define AccessibilityTextMarker_h
+
+#include <JavaScriptCore/JSObjectRef.h>
+
+#if PLATFORM(MAC)
+#define SUPPORTS_AX_TEXTMARKERS 1
+#else
+#define SUPPORTS_AX_TEXTMARKERS 0
+#endif
+
+#if PLATFORM(MAC)
+#include <wtf/RetainPtr.h>
+typedef CFTypeRef PlatformTextMarker;
+typedef CFTypeRef PlatformTextMarkerRange;
+#else
+typedef void* PlatformTextMarker;
+typedef void* PlatformTextMarkerRange;
+#endif
+
+class AccessibilityUIElement;
+
+class AccessibilityTextMarker {
+public:
+ AccessibilityTextMarker(PlatformTextMarker);
+ AccessibilityTextMarker(const AccessibilityTextMarker&);
+ ~AccessibilityTextMarker();
+
+ PlatformTextMarker platformTextMarker() const;
+
+ static JSObjectRef makeJSAccessibilityTextMarker(JSContextRef, const AccessibilityTextMarker&);
+ bool isEqual(AccessibilityTextMarker*);
+
+private:
+ static JSClassRef getJSClass();
+#if PLATFORM(MAC)
+ RetainPtr<PlatformTextMarker> m_textMarker;
+#else
+ PlatformTextMarker m_textMarker;
+#endif
+};
+
+class AccessibilityTextMarkerRange {
+public:
+ AccessibilityTextMarkerRange(PlatformTextMarkerRange);
+ AccessibilityTextMarkerRange(const AccessibilityTextMarkerRange&);
+ ~AccessibilityTextMarkerRange();
+
+ PlatformTextMarkerRange platformTextMarkerRange() const;
+
+ static JSObjectRef makeJSAccessibilityTextMarkerRange(JSContextRef, const AccessibilityTextMarkerRange&);
+ bool isEqual(AccessibilityTextMarkerRange*);
+
+private:
+ static JSClassRef getJSClass();
+#if PLATFORM(MAC)
+ RetainPtr<PlatformTextMarkerRange> m_textMarkerRange;
+#else
+ PlatformTextMarkerRange m_textMarkerRange;
+#endif
+};
+
+AccessibilityTextMarker* toTextMarker(JSObjectRef object);
+AccessibilityTextMarkerRange* toTextMarkerRange(JSObjectRef object);
+
+#if !SUPPORTS_AX_TEXTMARKERS
+inline AccessibilityTextMarker::AccessibilityTextMarker(PlatformTextMarker) { }
+inline AccessibilityTextMarker::AccessibilityTextMarker(const AccessibilityTextMarker&) { }
+inline AccessibilityTextMarker::~AccessibilityTextMarker() { }
+inline bool AccessibilityTextMarker::isEqual(AccessibilityTextMarker*) { return false; }
+inline PlatformTextMarker AccessibilityTextMarker::platformTextMarker() const { return m_textMarker; }
+
+inline AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(PlatformTextMarkerRange) { }
+inline AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(const AccessibilityTextMarkerRange&) { }
+inline AccessibilityTextMarkerRange::~AccessibilityTextMarkerRange() { }
+inline bool AccessibilityTextMarkerRange::isEqual(AccessibilityTextMarkerRange*) { return false; }
+inline PlatformTextMarkerRange AccessibilityTextMarkerRange::platformTextMarkerRange() const { return m_textMarkerRange; }
+#endif
+
+#endif // AccessibilityUIElement_h
diff --git a/Tools/DumpRenderTree/AccessibilityUIElement.cpp b/Tools/DumpRenderTree/AccessibilityUIElement.cpp
new file mode 100644
index 000000000..67fc4d73c
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityUIElement.cpp
@@ -0,0 +1,1122 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityUIElement.h"
+
+#include <JavaScriptCore/JSRetainPtr.h>
+
+// Static Functions
+
+static inline AccessibilityUIElement* toAXElement(JSObjectRef object)
+{
+ // FIXME: We should ASSERT that it is the right class here.
+ return static_cast<AccessibilityUIElement*>(JSObjectGetPrivate(object));
+}
+
+static JSValueRef allAttributesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> attributes(Adopt, toAXElement(thisObject)->allAttributes());
+ return JSValueMakeString(context, attributes.get());
+}
+
+static JSValueRef attributesOfLinkedUIElementsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> linkedUIDescription(Adopt, toAXElement(thisObject)->attributesOfLinkedUIElements());
+ return JSValueMakeString(context, linkedUIDescription.get());
+}
+
+static JSValueRef attributesOfDocumentLinksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> linkedUIDescription(Adopt, toAXElement(thisObject)->attributesOfDocumentLinks());
+ return JSValueMakeString(context, linkedUIDescription.get());
+}
+
+static JSValueRef attributesOfChildrenCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> childrenDescription(Adopt, toAXElement(thisObject)->attributesOfChildren());
+ return JSValueMakeString(context, childrenDescription.get());
+}
+
+static JSValueRef parameterizedAttributeNamesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> parameterizedAttributeNames(Adopt, toAXElement(thisObject)->parameterizedAttributeNames());
+ return JSValueMakeString(context, parameterizedAttributeNames.get());
+}
+
+static JSValueRef attributesOfColumnHeadersCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> attributesOfColumnHeaders(Adopt, toAXElement(thisObject)->attributesOfColumnHeaders());
+ return JSValueMakeString(context, attributesOfColumnHeaders.get());
+}
+
+static JSValueRef attributesOfRowHeadersCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> attributesOfRowHeaders(Adopt, toAXElement(thisObject)->attributesOfRowHeaders());
+ return JSValueMakeString(context, attributesOfRowHeaders.get());
+}
+
+static JSValueRef attributesOfColumnsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> attributesOfColumns(Adopt, toAXElement(thisObject)->attributesOfColumns());
+ return JSValueMakeString(context, attributesOfColumns.get());
+}
+
+static JSValueRef attributesOfRowsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> attributesOfRows(Adopt, toAXElement(thisObject)->attributesOfRows());
+ return JSValueMakeString(context, attributesOfRows.get());
+}
+
+static JSValueRef attributesOfVisibleCellsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> attributesOfVisibleCells(Adopt, toAXElement(thisObject)->attributesOfVisibleCells());
+ return JSValueMakeString(context, attributesOfVisibleCells.get());
+}
+
+static JSValueRef attributesOfHeaderCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> attributesOfHeader(Adopt, toAXElement(thisObject)->attributesOfHeader());
+ return JSValueMakeString(context, attributesOfHeader.get());
+}
+
+static JSValueRef indexInTableCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->indexInTable());
+}
+
+static JSValueRef rowIndexRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> rowIndexRange(Adopt, toAXElement(thisObject)->rowIndexRange());
+ return JSValueMakeString(context, rowIndexRange.get());
+}
+
+static JSValueRef columnIndexRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> columnIndexRange(Adopt, toAXElement(thisObject)->columnIndexRange());
+ return JSValueMakeString(context, columnIndexRange.get());
+}
+
+static JSValueRef lineForIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = -1;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return JSValueMakeNumber(context, toAXElement(thisObject)->lineForIndex(indexNumber));
+}
+
+static JSValueRef rangeForLineCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = -1;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ JSRetainPtr<JSStringRef> rangeLine(Adopt, toAXElement(thisObject)->rangeForLine(indexNumber));
+ return JSValueMakeString(context, rangeLine.get());
+}
+
+static JSValueRef boundsForRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ unsigned location = UINT_MAX, length = 0;
+ if (argumentCount == 2) {
+ location = JSValueToNumber(context, arguments[0], exception);
+ length = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ JSRetainPtr<JSStringRef> boundsDescription(Adopt, toAXElement(thisObject)->boundsForRange(location, length));
+ return JSValueMakeString(context, boundsDescription.get());
+}
+
+static JSValueRef stringForRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ unsigned location = UINT_MAX, length = 0;
+ if (argumentCount == 2) {
+ location = JSValueToNumber(context, arguments[0], exception);
+ length = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ JSRetainPtr<JSStringRef> stringDescription(Adopt, toAXElement(thisObject)->stringForRange(location, length));
+ return JSValueMakeString(context, stringDescription.get());
+}
+
+static JSValueRef attributedStringForRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ unsigned location = UINT_MAX, length = 0;
+ if (argumentCount == 2) {
+ location = JSValueToNumber(context, arguments[0], exception);
+ length = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ JSRetainPtr<JSStringRef> stringDescription(Adopt, toAXElement(thisObject)->attributedStringForRange(location, length));
+ return JSValueMakeString(context, stringDescription.get());
+}
+
+static JSValueRef attributedStringRangeIsMisspelledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ unsigned location = UINT_MAX, length = 0;
+ if (argumentCount == 2) {
+ location = JSValueToNumber(context, arguments[0], exception);
+ length = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->attributedStringRangeIsMisspelled(location, length));
+}
+
+static JSValueRef uiElementForSearchPredicateCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityUIElement* startElement = 0;
+ bool isDirectionNext = true;
+ JSStringRef searchKey = 0;
+ JSStringRef searchText = 0;
+ if (argumentCount == 4) {
+ JSObjectRef startElementObject = JSValueToObject(context, arguments[0], exception);
+ if (startElementObject)
+ startElement = toAXElement(startElementObject);
+ isDirectionNext = JSValueToBoolean(context, arguments[1]);
+ if (JSValueIsString(context, arguments[2]))
+ searchKey = JSValueToStringCopy(context, arguments[2], exception);
+ if (JSValueIsString(context, arguments[3]))
+ searchText = JSValueToStringCopy(context, arguments[3], exception);
+ }
+
+ JSObjectRef resultObject = AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementForSearchPredicate(startElement, isDirectionNext, searchKey, searchText));
+ if (searchKey)
+ JSStringRelease(searchKey);
+ if (searchText)
+ JSStringRelease(searchText);
+
+ return resultObject;
+}
+
+static JSValueRef indexOfChildCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 1)
+ return 0;
+
+ JSObjectRef otherElement = JSValueToObject(context, arguments[0], exception);
+ AccessibilityUIElement* childElement = toAXElement(otherElement);
+ return JSValueMakeNumber(context, (double)toAXElement(thisObject)->indexOfChild(childElement));
+}
+
+static JSValueRef childAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = -1;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->getChildAtIndex(indexNumber));
+}
+
+static JSValueRef selectedChildAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = -1;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->selectedChildAtIndex(indexNumber));
+}
+
+static JSValueRef linkedUIElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = -1;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->linkedUIElementAtIndex(indexNumber));
+}
+
+static JSValueRef disclosedRowAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = 0;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->disclosedRowAtIndex(indexNumber));
+}
+
+static JSValueRef ariaOwnsElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = 0;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->ariaOwnsElementAtIndex(indexNumber));
+}
+
+static JSValueRef ariaFlowToElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = 0;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->ariaFlowToElementAtIndex(indexNumber));
+}
+
+static JSValueRef selectedRowAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = 0;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->selectedRowAtIndex(indexNumber));
+}
+
+static JSValueRef isEqualCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSObjectRef otherElement = 0;
+ if (argumentCount == 1)
+ otherElement = JSValueToObject(context, arguments[0], exception);
+ else
+ return JSValueMakeBoolean(context, false);
+
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isEqual(toAXElement(otherElement)));
+}
+
+static JSValueRef setSelectedChildCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSObjectRef element = 0;
+ if (argumentCount == 1)
+ element = JSValueToObject(context, arguments[0], exception);
+
+ toAXElement(thisObject)->setSelectedChild(toAXElement(element));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef elementAtPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int x = 0;
+ int y = 0;
+ if (argumentCount == 2) {
+ x = JSValueToNumber(context, arguments[0], exception);
+ y = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->elementAtPoint(x, y));
+}
+
+static JSValueRef isAttributeSupportedCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSStringRef attribute = 0;
+ if (argumentCount == 1)
+ attribute = JSValueToStringCopy(context, arguments[0], exception);
+ JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->isAttributeSupported(attribute));
+ if (attribute)
+ JSStringRelease(attribute);
+ return result;
+}
+
+static JSValueRef isAttributeSettableCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSStringRef attribute = 0;
+ if (argumentCount == 1)
+ attribute = JSValueToStringCopy(context, arguments[0], exception);
+ JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->isAttributeSettable(attribute));
+ if (attribute)
+ JSStringRelease(attribute);
+ return result;
+}
+
+
+static JSValueRef isActionSupportedCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSStringRef action = 0;
+ if (argumentCount == 1)
+ action = JSValueToStringCopy(context, arguments[0], exception);
+ JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->isActionSupported(action));
+ if (action)
+ JSStringRelease(action);
+ return result;
+}
+
+static JSValueRef boolAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSStringRef attribute = 0;
+ if (argumentCount == 1)
+ attribute = JSValueToStringCopy(context, arguments[0], exception);
+ bool val = toAXElement(thisObject)->boolAttributeValue(attribute);
+ JSValueRef result = JSValueMakeBoolean(context, val);
+ if (attribute)
+ JSStringRelease(attribute);
+ return result;
+}
+
+static JSValueRef stringAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSStringRef attribute = 0;
+ if (argumentCount == 1)
+ attribute = JSValueToStringCopy(context, arguments[0], exception);
+ JSRetainPtr<JSStringRef> stringAttributeValue(Adopt, toAXElement(thisObject)->stringAttributeValue(attribute));
+ JSValueRef result = JSValueMakeString(context, stringAttributeValue.get());
+ if (attribute)
+ JSStringRelease(attribute);
+ return result;
+}
+
+static JSValueRef uiElementAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> attribute;
+ if (argumentCount == 1)
+ attribute.adopt(JSValueToStringCopy(context, arguments[0], exception));
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->uiElementAttributeValue(attribute.get()));
+}
+
+static JSValueRef numberAttributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSStringRef attribute = 0;
+ if (argumentCount == 1)
+ attribute = JSValueToStringCopy(context, arguments[0], exception);
+ double val = toAXElement(thisObject)->numberAttributeValue(attribute);
+ JSValueRef result = JSValueMakeNumber(context, val);
+ if (attribute)
+ JSStringRelease(attribute);
+ return result;
+}
+
+static JSValueRef cellForColumnAndRowCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ unsigned column = 0, row = 0;
+ if (argumentCount == 2) {
+ column = JSValueToNumber(context, arguments[0], exception);
+ row = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->cellForColumnAndRow(column, row));
+}
+
+static JSValueRef titleUIElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->titleUIElement());
+}
+
+static JSValueRef parentElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->parentElement());
+}
+
+static JSValueRef disclosedByRowCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->disclosedByRow());
+}
+
+static JSValueRef setSelectedTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ unsigned location = UINT_MAX, length = 0;
+ if (argumentCount == 2) {
+ location = JSValueToNumber(context, arguments[0], exception);
+ length = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ toAXElement(thisObject)->setSelectedTextRange(location, length);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef incrementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->increment();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef decrementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->decrement();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef showMenuCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->showMenu();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef pressCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->press();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef takeFocusCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->takeFocus();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef takeSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->takeSelection();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef addSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->addSelection();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef removeSelectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->removeSelection();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef textMarkerRangeForElementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityUIElement* uiElement = 0;
+ if (argumentCount == 1)
+ uiElement = toAXElement(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->textMarkerRangeForElement(uiElement));
+}
+
+static JSValueRef attributedStringForTextMarkerRangeContainsAttributeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarkerRange* markerRange = 0;
+ JSStringRef attribute = 0;
+ if (argumentCount == 2) {
+ attribute = JSValueToStringCopy(context, arguments[0], exception);
+ markerRange = toTextMarkerRange(JSValueToObject(context, arguments[1], exception));
+ }
+
+ JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->attributedStringForTextMarkerRangeContainsAttribute(attribute, markerRange));
+ if (attribute)
+ JSStringRelease(attribute);
+
+ return result;
+}
+
+static JSValueRef textMarkerRangeLengthCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarkerRange* range = 0;
+ if (argumentCount == 1)
+ range = toTextMarkerRange(JSValueToObject(context, arguments[0], exception));
+
+ return JSValueMakeNumber(context, (int)toAXElement(thisObject)->textMarkerRangeLength(range));
+}
+
+static JSValueRef nextTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = 0;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->nextTextMarker(marker));
+}
+
+static JSValueRef previousTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = 0;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->previousTextMarker(marker));
+}
+
+static JSValueRef stringForTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarkerRange* markerRange = 0;
+ if (argumentCount == 1)
+ markerRange = toTextMarkerRange(JSValueToObject(context, arguments[0], exception));
+
+ JSRetainPtr<JSStringRef> markerRangeString(Adopt, toAXElement(thisObject)->stringForTextMarkerRange(markerRange));
+ return JSValueMakeString(context, markerRangeString.get());
+}
+
+static JSValueRef textMarkerForPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int x = 0;
+ int y = 0;
+ if (argumentCount == 2) {
+ x = JSValueToNumber(context, arguments[0], exception);
+ y = JSValueToNumber(context, arguments[1], exception);
+ }
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->textMarkerForPoint(x, y));
+}
+
+static JSValueRef textMarkerRangeForMarkersCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* startMarker = 0;
+ AccessibilityTextMarker* endMarker = 0;
+ if (argumentCount == 2) {
+ startMarker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+ endMarker = toTextMarker(JSValueToObject(context, arguments[1], exception));
+ }
+
+ return AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange(context, toAXElement(thisObject)->textMarkerRangeForMarkers(startMarker, endMarker));
+}
+
+static JSValueRef startTextMarkerForTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarkerRange* markerRange = 0;
+ if (argumentCount == 1)
+ markerRange = toTextMarkerRange(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->startTextMarkerForTextMarkerRange(markerRange));
+}
+
+static JSValueRef endTextMarkerForTextMarkerRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarkerRange* markerRange = 0;
+ if (argumentCount == 1)
+ markerRange = toTextMarkerRange(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityTextMarker::makeJSAccessibilityTextMarker(context, toAXElement(thisObject)->endTextMarkerForTextMarkerRange(markerRange));
+}
+
+static JSValueRef accessibilityElementForTextMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ AccessibilityTextMarker* marker = 0;
+ if (argumentCount == 1)
+ marker = toTextMarker(JSValueToObject(context, arguments[0], exception));
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->accessibilityElementForTextMarker(marker));
+}
+
+// Static Value Getters
+
+static JSValueRef getARIADropEffectsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> dropEffects(Adopt, toAXElement(thisObject)->ariaDropEffects());
+ return JSValueMakeString(context, dropEffects.get());
+}
+
+static JSValueRef getARIAIsGrabbedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->ariaIsGrabbed());
+}
+
+static JSValueRef getIsValidCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ AccessibilityUIElement* uiElement = toAXElement(thisObject);
+ if (!uiElement->platformUIElement())
+ return JSValueMakeBoolean(context, false);
+
+ // There might be other platform logic that one could check here...
+
+ return JSValueMakeBoolean(context, true);
+}
+
+static JSValueRef getRoleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> role(Adopt, toAXElement(thisObject)->role());
+ return JSValueMakeString(context, role.get());
+}
+
+static JSValueRef getSubroleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> role(Adopt, toAXElement(thisObject)->subrole());
+ return JSValueMakeString(context, role.get());
+}
+
+static JSValueRef getRoleDescriptionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> roleDesc(Adopt, toAXElement(thisObject)->roleDescription());
+ return JSValueMakeString(context, roleDesc.get());
+}
+
+static JSValueRef getTitleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> title(Adopt, toAXElement(thisObject)->title());
+ return JSValueMakeString(context, title.get());
+}
+
+static JSValueRef getDescriptionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> description(Adopt, toAXElement(thisObject)->description());
+ return JSValueMakeString(context, description.get());
+}
+
+static JSValueRef getStringValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> stringValue(Adopt, toAXElement(thisObject)->stringValue());
+ return JSValueMakeString(context, stringValue.get());
+}
+
+static JSValueRef getLanguageCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> language(Adopt, toAXElement(thisObject)->language());
+ return JSValueMakeString(context, language.get());
+}
+
+static JSValueRef getHelpTextCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> language(Adopt, toAXElement(thisObject)->helpText());
+ return JSValueMakeString(context, language.get());
+}
+
+static JSValueRef getOrientationCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> orientation(Adopt, toAXElement(thisObject)->orientation());
+ return JSValueMakeString(context, orientation.get());
+}
+
+static JSValueRef getChildrenCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->childrenCount());
+}
+
+static JSValueRef rowCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->rowCount());
+}
+
+static JSValueRef columnCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->columnCount());
+}
+
+static JSValueRef getXCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->x());
+}
+
+static JSValueRef getYCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->y());
+}
+
+static JSValueRef getWidthCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->width());
+}
+
+static JSValueRef getHeightCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->height());
+}
+
+static JSValueRef getClickPointXCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->clickPointX());
+}
+
+static JSValueRef getClickPointYCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->clickPointY());
+}
+
+static JSValueRef getIntValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->intValue());
+}
+
+static JSValueRef getMinValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->minValue());
+}
+
+static JSValueRef getMaxValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->maxValue());
+}
+
+static JSValueRef getInsertionPointLineNumberCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->insertionPointLineNumber());
+}
+
+static JSValueRef getSelectedTextRangeCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> selectedTextRange(Adopt, toAXElement(thisObject)->selectedTextRange());
+ return JSValueMakeString(context, selectedTextRange.get());
+}
+
+static JSValueRef getIsEnabledCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isEnabled());
+}
+
+static JSValueRef getIsRequiredCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isRequired());
+}
+
+static JSValueRef getIsFocusedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isFocused());
+}
+
+static JSValueRef getIsFocusableCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isFocusable());
+}
+
+static JSValueRef getIsSelectedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isSelected());
+}
+
+static JSValueRef getIsSelectableCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isSelectable());
+}
+
+static JSValueRef getIsMultiSelectableCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isMultiSelectable());
+}
+
+static JSValueRef getIsSelectedOptionActiveCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isSelectedOptionActive());
+}
+
+static JSValueRef getIsExpandedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isExpanded());
+}
+
+static JSValueRef getIsCheckedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isChecked());
+}
+
+static JSValueRef getIsVisibleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isVisible());
+}
+
+static JSValueRef getIsOffScreenCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isOffScreen());
+}
+
+static JSValueRef getIsCollapsedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isCollapsed());
+}
+
+static JSValueRef isIgnoredCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isIgnored());
+}
+
+static JSValueRef speakCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ JSRetainPtr<JSStringRef> speakString(Adopt, toAXElement(thisObject)->speak());
+ return JSValueMakeString(context, speakString.get());
+}
+
+static JSValueRef selectedChildrenCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->selectedChildrenCount());
+}
+
+static JSValueRef horizontalScrollbarCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->horizontalScrollbar());
+}
+
+static JSValueRef verticalScrollbarCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->verticalScrollbar());
+}
+
+static JSValueRef getHasPopupCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->hasPopup());
+}
+
+static JSValueRef hierarchicalLevelCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->hierarchicalLevel());
+}
+
+static JSValueRef getValueDescriptionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> valueDescription(Adopt, toAXElement(thisObject)->valueDescription());
+ return JSValueMakeString(context, valueDescription.get());
+}
+
+static JSValueRef getAccessibilityValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> accessibilityValue(Adopt, toAXElement(thisObject)->accessibilityValue());
+ return JSValueMakeString(context, accessibilityValue.get());
+}
+
+static JSValueRef getDocumentEncodingCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> documentEncoding(Adopt, toAXElement(thisObject)->documentEncoding());
+ return JSValueMakeString(context, documentEncoding.get());
+}
+
+static JSValueRef getDocumentURICallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> documentURI(Adopt, toAXElement(thisObject)->documentURI());
+ return JSValueMakeString(context, documentURI.get());
+}
+
+static JSValueRef getURLCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> url(Adopt, toAXElement(thisObject)->url());
+ return JSValueMakeString(context, url.get());
+}
+
+static JSValueRef addNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 1)
+ return JSValueMakeBoolean(context, false);
+
+ JSObjectRef callback = JSValueToObject(context, arguments[0], exception);
+ bool succeeded = toAXElement(thisObject)->addNotificationListener(callback);
+ return JSValueMakeBoolean(context, succeeded);
+}
+
+static JSValueRef removeNotificationListenerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->removeNotificationListener();
+ return JSValueMakeUndefined(context);
+}
+
+// Implementation
+
+// Unsupported methods on various platforms.
+#if !PLATFORM(MAC)
+JSStringRef AccessibilityUIElement::speak() { return 0; }
+JSStringRef AccessibilityUIElement::rangeForLine(int line) { return 0; }
+void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement*) const { }
+unsigned AccessibilityUIElement::selectedChildrenCount() const { return 0; }
+AccessibilityUIElement AccessibilityUIElement::selectedChildAtIndex(unsigned) const { return 0; }
+AccessibilityUIElement AccessibilityUIElement::horizontalScrollbar() const { return 0; }
+AccessibilityUIElement AccessibilityUIElement::verticalScrollbar() const { return 0; }
+AccessibilityUIElement AccessibilityUIElement::uiElementAttributeValue(JSStringRef) const { return 0; }
+#endif
+
+#if !PLATFORM(WIN)
+bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
+{
+ return platformUIElement() == otherElement->platformUIElement();
+}
+#endif
+
+#if !SUPPORTS_AX_TEXTMARKERS
+
+AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement*)
+{
+ return 0;
+}
+
+int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange*)
+{
+ return 0;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker*, AccessibilityTextMarker*)
+{
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*)
+{
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker*)
+{
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::textMarkerForPoint(int x, int y)
+{
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker*)
+{
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker*)
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange*)
+{
+ return 0;
+}
+
+bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*)
+{
+ return false;
+}
+
+#endif
+
+// Destruction
+
+static void finalize(JSObjectRef thisObject)
+{
+ delete toAXElement(thisObject);
+}
+
+// Object Creation
+
+JSObjectRef AccessibilityUIElement::makeJSAccessibilityUIElement(JSContextRef context, const AccessibilityUIElement& element)
+{
+ return JSObjectMake(context, AccessibilityUIElement::getJSClass(), new AccessibilityUIElement(element));
+}
+
+JSClassRef AccessibilityUIElement::getJSClass()
+{
+ static JSStaticValue staticValues[] = {
+ { "accessibilityValue", getAccessibilityValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "role", getRoleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "subrole", getSubroleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "roleDescription", getRoleDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "title", getTitleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "description", getDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "language", getLanguageCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "helpText", getHelpTextCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "stringValue", getStringValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "x", getXCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "y", getYCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "width", getWidthCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "height", getHeightCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "clickPointX", getClickPointXCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "clickPointY", getClickPointYCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "intValue", getIntValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "minValue", getMinValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "maxValue", getMaxValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "childrenCount", getChildrenCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "rowCount", rowCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "columnCount", columnCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "insertionPointLineNumber", getInsertionPointLineNumberCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "selectedTextRange", getSelectedTextRangeCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isEnabled", getIsEnabledCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isRequired", getIsRequiredCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isFocused", getIsFocusedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isFocusable", getIsFocusableCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isSelected", getIsSelectedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isSelectable", getIsSelectableCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isMultiSelectable", getIsMultiSelectableCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isSelectedOptionActive", getIsSelectedOptionActiveCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isExpanded", getIsExpandedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isChecked", getIsCheckedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isVisible", getIsVisibleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isOffScreen", getIsOffScreenCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isCollapsed", getIsCollapsedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "hasPopup", getHasPopupCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "valueDescription", getValueDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "hierarchicalLevel", hierarchicalLevelCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "documentEncoding", getDocumentEncodingCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "documentURI", getDocumentURICallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "url", getURLCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isValid", getIsValidCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "orientation", getOrientationCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ariaIsGrabbed", getARIAIsGrabbedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ariaDropEffects", getARIADropEffectsCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isIgnored", isIgnoredCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "speak", speakCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "selectedChildrenCount", selectedChildrenCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "horizontalScrollbar", horizontalScrollbarCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "verticalScrollbar", verticalScrollbarCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0, 0 }
+ };
+
+ static JSStaticFunction staticFunctions[] = {
+ { "allAttributes", allAttributesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributesOfLinkedUIElements", attributesOfLinkedUIElementsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributesOfDocumentLinks", attributesOfDocumentLinksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributesOfChildren", attributesOfChildrenCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "parameterizedAttributeNames", parameterizedAttributeNamesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "lineForIndex", lineForIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "rangeForLine", rangeForLineCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "boundsForRange", boundsForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "stringForRange", stringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributedStringForRange", attributedStringForRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributedStringRangeIsMisspelled", attributedStringRangeIsMisspelledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "uiElementForSearchPredicate", uiElementForSearchPredicateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "childAtIndex", childAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "linkedUIElementAtIndex", linkedUIElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "indexOfChild", indexOfChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "elementAtPoint", elementAtPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributesOfColumnHeaders", attributesOfColumnHeadersCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributesOfRowHeaders", attributesOfRowHeadersCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributesOfColumns", attributesOfColumnsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributesOfRows", attributesOfRowsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributesOfVisibleCells", attributesOfVisibleCellsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributesOfHeader", attributesOfHeaderCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "indexInTable", indexInTableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "rowIndexRange", rowIndexRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "columnIndexRange", columnIndexRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "cellForColumnAndRow", cellForColumnAndRowCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "titleUIElement", titleUIElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSelectedTextRange", setSelectedTextRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "stringAttributeValue", stringAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "uiElementAttributeValue", uiElementAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "numberAttributeValue", numberAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "boolAttributeValue", boolAttributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isAttributeSupported", isAttributeSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isAttributeSettable", isAttributeSettableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isActionSupported", isActionSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "parentElement", parentElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "disclosedByRow", disclosedByRowCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "increment", incrementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "decrement", decrementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "showMenu", showMenuCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "press", pressCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "disclosedRowAtIndex", disclosedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ariaOwnsElementAtIndex", ariaOwnsElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ariaFlowToElementAtIndex", ariaFlowToElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "selectedRowAtIndex", selectedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isEqual", isEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addNotificationListener", addNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "removeNotificationListener", removeNotificationListenerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "takeFocus", takeFocusCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "takeSelection", takeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addSelection", addSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "removeSelection", removeSelectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textMarkerRangeForElement", textMarkerRangeForElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "attributedStringForTextMarkerRangeContainsAttribute", attributedStringForTextMarkerRangeContainsAttributeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textMarkerRangeForMarkers", textMarkerRangeForMarkersCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "startTextMarkerForTextMarkerRange", startTextMarkerForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "endTextMarkerForTextMarkerRange", endTextMarkerForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "accessibilityElementForTextMarker", accessibilityElementForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textMarkerRangeLength", textMarkerRangeLengthCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textMarkerForPoint", textMarkerForPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "nextTextMarker", nextTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "previousTextMarker", previousTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "stringForTextMarkerRange", stringForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSelectedChild", setSelectedChildCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "selectedChildAtIndex", selectedChildAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+ };
+
+ static JSClassDefinition classDefinition = {
+ 0, kJSClassAttributeNone, "AccessibilityUIElement", 0, staticValues, staticFunctions,
+ 0, finalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ static JSClassRef accessibilityUIElementClass = JSClassCreate(&classDefinition);
+ return accessibilityUIElementClass;
+}
diff --git a/Tools/DumpRenderTree/AccessibilityUIElement.h b/Tools/DumpRenderTree/AccessibilityUIElement.h
new file mode 100644
index 000000000..38d35cf58
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityUIElement.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AccessibilityUIElement_h
+#define AccessibilityUIElement_h
+
+#include "AccessibilityTextMarker.h"
+#include <JavaScriptCore/JSObjectRef.h>
+#include <wtf/Platform.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+typedef id PlatformUIElement;
+#else
+typedef struct objc_object* PlatformUIElement;
+#endif
+#elif PLATFORM(WIN)
+#undef _WINSOCKAPI_
+#define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h
+
+#include <WebCore/COMPtr.h>
+#include <oleacc.h>
+
+typedef COMPtr<IAccessible> PlatformUIElement;
+#elif PLATFORM(GTK)
+#include <atk/atk.h>
+typedef AtkObject* PlatformUIElement;
+#else
+typedef void* PlatformUIElement;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+typedef id NotificationHandler;
+#else
+typedef struct objc_object* NotificationHandler;
+#endif
+#endif
+
+class AccessibilityUIElement {
+public:
+ AccessibilityUIElement(PlatformUIElement);
+ AccessibilityUIElement(const AccessibilityUIElement&);
+ ~AccessibilityUIElement();
+
+ PlatformUIElement platformUIElement() { return m_element; }
+
+ static JSObjectRef makeJSAccessibilityUIElement(JSContextRef, const AccessibilityUIElement&);
+
+ bool isEqual(AccessibilityUIElement* otherElement);
+
+ void getLinkedUIElements(Vector<AccessibilityUIElement>&);
+ void getDocumentLinks(Vector<AccessibilityUIElement>&);
+ void getChildren(Vector<AccessibilityUIElement>&);
+ void getChildrenWithRange(Vector<AccessibilityUIElement>&, unsigned location, unsigned length);
+
+ AccessibilityUIElement elementAtPoint(int x, int y);
+ AccessibilityUIElement getChildAtIndex(unsigned);
+ unsigned indexOfChild(AccessibilityUIElement*);
+ int childrenCount();
+ AccessibilityUIElement titleUIElement();
+ AccessibilityUIElement parentElement();
+
+ void takeFocus();
+ void takeSelection();
+ void addSelection();
+ void removeSelection();
+
+ // Methods - platform-independent implementations
+ JSStringRef allAttributes();
+ JSStringRef attributesOfLinkedUIElements();
+ AccessibilityUIElement linkedUIElementAtIndex(unsigned);
+
+ JSStringRef attributesOfDocumentLinks();
+ JSStringRef attributesOfChildren();
+ JSStringRef parameterizedAttributeNames();
+ void increment();
+ void decrement();
+ void showMenu();
+ void press();
+
+ // Attributes - platform-independent implementations
+ JSStringRef stringAttributeValue(JSStringRef attribute);
+ double numberAttributeValue(JSStringRef attribute);
+ AccessibilityUIElement uiElementAttributeValue(JSStringRef attribute) const;
+ bool boolAttributeValue(JSStringRef attribute);
+ bool isAttributeSupported(JSStringRef attribute);
+ bool isAttributeSettable(JSStringRef attribute);
+ bool isActionSupported(JSStringRef action);
+ JSStringRef role();
+ JSStringRef subrole();
+ JSStringRef roleDescription();
+ JSStringRef title();
+ JSStringRef description();
+ JSStringRef language();
+ JSStringRef stringValue();
+ JSStringRef accessibilityValue() const;
+ JSStringRef helpText() const;
+ JSStringRef orientation() const;
+ double x();
+ double y();
+ double width();
+ double height();
+ double intValue() const;
+ double minValue();
+ double maxValue();
+ JSStringRef valueDescription();
+ int insertionPointLineNumber();
+ JSStringRef selectedTextRange();
+ bool isEnabled();
+ bool isRequired() const;
+
+ bool isFocused() const;
+ bool isFocusable() const;
+ bool isSelected() const;
+ bool isSelectable() const;
+ bool isMultiSelectable() const;
+ bool isSelectedOptionActive() const;
+ void setSelectedChild(AccessibilityUIElement*) const;
+ unsigned selectedChildrenCount() const;
+ AccessibilityUIElement selectedChildAtIndex(unsigned) const;
+
+ bool isExpanded() const;
+ bool isChecked() const;
+ bool isVisible() const;
+ bool isOffScreen() const;
+ bool isCollapsed() const;
+ bool isIgnored() const;
+ bool hasPopup() const;
+ int hierarchicalLevel() const;
+ double clickPointX();
+ double clickPointY();
+ JSStringRef documentEncoding();
+ JSStringRef documentURI();
+ JSStringRef url();
+
+ // CSS3-speech properties.
+ JSStringRef speak();
+
+ // Table-specific attributes
+ JSStringRef attributesOfColumnHeaders();
+ JSStringRef attributesOfRowHeaders();
+ JSStringRef attributesOfColumns();
+ JSStringRef attributesOfRows();
+ JSStringRef attributesOfVisibleCells();
+ JSStringRef attributesOfHeader();
+ int indexInTable();
+ JSStringRef rowIndexRange();
+ JSStringRef columnIndexRange();
+ int rowCount();
+ int columnCount();
+
+ // Tree/Outline specific attributes
+ AccessibilityUIElement selectedRowAtIndex(unsigned);
+ AccessibilityUIElement disclosedByRow();
+ AccessibilityUIElement disclosedRowAtIndex(unsigned);
+
+ // ARIA specific
+ AccessibilityUIElement ariaOwnsElementAtIndex(unsigned);
+ AccessibilityUIElement ariaFlowToElementAtIndex(unsigned);
+
+ // ARIA Drag and Drop
+ bool ariaIsGrabbed() const;
+ // A space concatentated string of all the drop effects.
+ JSStringRef ariaDropEffects() const;
+
+ // Parameterized attributes
+ int lineForIndex(int);
+ JSStringRef rangeForLine(int);
+ JSStringRef boundsForRange(unsigned location, unsigned length);
+ void setSelectedTextRange(unsigned location, unsigned length);
+ JSStringRef stringForRange(unsigned location, unsigned length);
+ JSStringRef attributedStringForRange(unsigned location, unsigned length);
+ bool attributedStringRangeIsMisspelled(unsigned location, unsigned length);
+ AccessibilityUIElement uiElementForSearchPredicate(AccessibilityUIElement* startElement, bool isDirectionNext, JSStringRef searchKey, JSStringRef searchText);
+
+ // Table-specific
+ AccessibilityUIElement cellForColumnAndRow(unsigned column, unsigned row);
+
+ // Scrollarea-specific
+ AccessibilityUIElement horizontalScrollbar() const;
+ AccessibilityUIElement verticalScrollbar() const;
+
+ // Text markers.
+ AccessibilityTextMarkerRange textMarkerRangeForElement(AccessibilityUIElement*);
+ AccessibilityTextMarkerRange textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker);
+ AccessibilityTextMarker startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*);
+ AccessibilityTextMarker endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*);
+ AccessibilityTextMarker textMarkerForPoint(int x, int y);
+ AccessibilityTextMarker previousTextMarker(AccessibilityTextMarker*);
+ AccessibilityTextMarker nextTextMarker(AccessibilityTextMarker*);
+ AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker*);
+ JSStringRef stringForTextMarkerRange(AccessibilityTextMarkerRange*);
+ int textMarkerRangeLength(AccessibilityTextMarkerRange*);
+ bool attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*);
+
+ // Notifications
+ // Function callback should take one argument, the name of the notification.
+ bool addNotificationListener(JSObjectRef functionCallback);
+ // Make sure you call remove, because you can't rely on objects being deallocated in a timely fashion.
+ void removeNotificationListener();
+
+private:
+ static JSClassRef getJSClass();
+ PlatformUIElement m_element;
+
+ // A retained, platform specific object used to help manage notifications for this object.
+#if PLATFORM(MAC)
+ NotificationHandler m_notificationHandler;
+#endif
+};
+
+#endif // AccessibilityUIElement_h
diff --git a/Tools/DumpRenderTree/CyclicRedundancyCheck.cpp b/Tools/DumpRenderTree/CyclicRedundancyCheck.cpp
new file mode 100644
index 000000000..562225395
--- /dev/null
+++ b/Tools/DumpRenderTree/CyclicRedundancyCheck.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010, Robert Eisele <robert@xarg.org> 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 "CyclicRedundancyCheck.h"
+
+#include <wtf/Vector.h>
+
+static void makeCrcTable(unsigned crcTable[256])
+{
+ for (unsigned i = 0; i < 256; i++) {
+ unsigned c = i;
+ for (int k = 0; k < 8; k++) {
+ if (c & 1)
+ c = -306674912 ^ ((c >> 1) & 0x7fffffff);
+ else
+ c = c >> 1;
+ }
+ crcTable[i] = c;
+ }
+}
+
+unsigned computeCrc(const Vector<unsigned char>& buffer)
+{
+ static unsigned crcTable[256];
+ static bool crcTableComputed = false;
+ if (!crcTableComputed) {
+ makeCrcTable(crcTable);
+ crcTableComputed = true;
+ }
+
+ unsigned crc = 0xffffffffU;
+ for (size_t i = 0; i < buffer.size(); ++i)
+ crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffU);
+ return crc ^ 0xffffffffU;
+}
+
diff --git a/Tools/DumpRenderTree/CyclicRedundancyCheck.h b/Tools/DumpRenderTree/CyclicRedundancyCheck.h
new file mode 100644
index 000000000..ef1d78e86
--- /dev/null
+++ b/Tools/DumpRenderTree/CyclicRedundancyCheck.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 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 CyclicRedundancyCheck_h
+#define CyclicRedundancyCheck_h
+
+#include <wtf/Vector.h>
+
+unsigned computeCrc(const Vector<unsigned char>&);
+
+#endif
diff --git a/Tools/DumpRenderTree/DumpRenderTree.gypi b/Tools/DumpRenderTree/DumpRenderTree.gypi
new file mode 100644
index 000000000..47442bf2a
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTree.gypi
@@ -0,0 +1,97 @@
+{
+ 'variables': {
+ 'drt_files': [
+ 'chromium/AccessibilityController.cpp',
+ 'chromium/AccessibilityController.h',
+ 'chromium/AccessibilityUIElement.cpp',
+ 'chromium/AccessibilityUIElement.h',
+ 'chromium/CppBoundClass.cpp',
+ 'chromium/CppBoundClass.h',
+ 'chromium/CppVariant.cpp',
+ 'chromium/CppVariant.h',
+ 'chromium/DRTDevToolsAgent.cpp',
+ 'chromium/DRTDevToolsAgent.h',
+ 'chromium/DRTDevToolsClient.cpp',
+ 'chromium/DRTDevToolsClient.h',
+ 'chromium/DumpRenderTree.cpp',
+ 'chromium/EventSender.cpp',
+ 'chromium/EventSender.h',
+ 'chromium/GamepadController.cpp',
+ 'chromium/GamepadController.h',
+ 'chromium/LayoutTestController.cpp',
+ 'chromium/LayoutTestController.h',
+ 'chromium/MockSpellCheck.cpp',
+ 'chromium/MockSpellCheck.h',
+ 'chromium/NotificationPresenter.h',
+ 'chromium/NotificationPresenter.cpp',
+ 'chromium/PlainTextController.cpp',
+ 'chromium/PlainTextController.h',
+ 'chromium/Task.h',
+ 'chromium/Task.cpp',
+ 'chromium/TestEventPrinter.h',
+ 'chromium/TestEventPrinter.cpp',
+ 'chromium/TestNavigationController.cpp',
+ 'chromium/TestNavigationController.h',
+ 'chromium/TestShell.cpp',
+ 'chromium/TestShell.h',
+ 'chromium/TestShellLinux.cpp',
+ 'chromium/TestShellGtk.cpp',
+ 'chromium/TestShellMac.mm',
+ 'chromium/TestShellWin.cpp',
+ 'chromium/TestWebPlugin.cpp',
+ 'chromium/TestWebPlugin.h',
+ 'chromium/TextInputController.cpp',
+ 'chromium/TextInputController.h',
+ 'chromium/WebPermissions.cpp',
+ 'chromium/WebPermissions.h',
+ 'chromium/WebPreferences.cpp',
+ 'chromium/WebPreferences.h',
+ 'chromium/WebViewHost.cpp',
+ 'chromium/WebViewHost.h',
+ ],
+ 'test_plugin_files': [
+ 'TestNetscapePlugIn/PluginObject.cpp',
+ 'TestNetscapePlugIn/PluginObject.h',
+ 'TestNetscapePlugIn/PluginObjectMac.mm',
+ 'TestNetscapePlugIn/PluginTest.cpp',
+ 'TestNetscapePlugIn/PluginTest.h',
+ 'TestNetscapePlugIn/TestObject.cpp',
+ 'TestNetscapePlugIn/TestObject.h',
+ 'TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp',
+ 'TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp',
+ 'TestNetscapePlugIn/Tests/FormValue.cpp',
+ 'TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp',
+ 'TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp',
+ 'TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp',
+ 'TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp',
+ 'TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp',
+ 'TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp',
+ 'TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp',
+ 'TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp',
+ 'TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp',
+ 'TestNetscapePlugIn/Tests/PrivateBrowsing.cpp',
+ 'TestNetscapePlugIn/main.cpp',
+ ],
+ 'conditions': [
+ ['(OS=="linux" and toolkit_uses_gtk!=1) or OS=="android"', {
+ 'drt_files': [
+ 'chromium/TestShellStub.cpp',
+ ],
+ }],
+ ['OS=="win"', {
+ 'drt_files': [
+ 'chromium/WebThemeControlDRTWin.cpp',
+ 'chromium/WebThemeControlDRTWin.h',
+ 'chromium/WebThemeEngineDRTWin.cpp',
+ 'chromium/WebThemeEngineDRTWin.h',
+ ],
+ }],
+ ['OS=="mac"', {
+ 'drt_files': [
+ 'chromium/WebThemeEngineDRTMac.mm',
+ 'chromium/WebThemeEngineDRTMac.h',
+ ],
+ }],
+ ],
+ }
+}
diff --git a/Tools/DumpRenderTree/DumpRenderTree.h b/Tools/DumpRenderTree/DumpRenderTree.h
new file mode 100644
index 000000000..c1e83b5c9
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTree.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTree_h
+#define DumpRenderTree_h
+
+// FIXME: Remove this when all platforms are using config.h
+#ifndef Config_H
+#include <wtf/Platform.h>
+#endif
+
+#if PLATFORM(MAC)
+#include "DumpRenderTreeMac.h"
+#elif PLATFORM(WIN)
+#include "DumpRenderTreeWin.h"
+#elif PLATFORM(GTK)
+#include "DumpRenderTreeGtk.h"
+#elif PLATFORM(WX)
+#include "DumpRenderTreeWx.h"
+#elif PLATFORM(EFL)
+#include "DumpRenderTreeEfl.h"
+#endif
+
+#include <string>
+#include <wtf/RefPtr.h>
+
+#if !OS(OPENBSD)
+std::wstring urlSuitableForTestResult(const std::wstring& url);
+#endif
+
+class LayoutTestController;
+
+extern volatile bool done;
+
+// FIXME: This is a bad abstraction. We should insted pass this to other controller objects which need access to it.
+extern RefPtr<LayoutTestController> gLayoutTestController;
+
+void dump();
+void displayWebView();
+
+#endif // DumpRenderTree_h
diff --git a/Tools/DumpRenderTree/DumpRenderTree.sln b/Tools/DumpRenderTree/DumpRenderTree.sln
new file mode 100644
index 000000000..5a9a70a7b
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTree.sln
@@ -0,0 +1,100 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DumpRenderTree", "win\DumpRenderTree.vcproj", "{6567DFD4-D6DE-4CD5-825D-17E353D160E1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C} = {C0737398-3565-439E-A2B8-AB2BE4D5430C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestNetscapePlugin", "TestNetscapePlugin\win\TestNetscapePlugin.vcproj", "{C0737398-3565-439E-A2B8-AB2BE4D5430C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017} = {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageDiff", "win\ImageDiff.vcproj", "{59CC0547-70AC-499C-9B19-EC01C6F61137}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DumpRenderTreeLauncher", "win\DumpRenderTreeLauncher.vcproj", "{2974EA02-840B-4995-8719-8920A61006F1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1} = {6567DFD4-D6DE-4CD5-825D-17E353D160E1}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageDiffLauncher", "win\ImageDiffLauncher.vcproj", "{DD7949B6-F2B4-47C2-9C42-E21E84CB1017}"
+ ProjectSection(ProjectDependencies) = postProject
+ {59CC0547-70AC-499C-9B19-EC01C6F61137} = {59CC0547-70AC-499C-9B19-EC01C6F61137}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug_All|Win32 = Debug_All|Win32
+ Debug_Cairo_CFLite|Win32 = Debug_Cairo_CFLite|Win32
+ Debug|Win32 = Debug|Win32
+ Production|Win32 = Production|Win32
+ Release_Cairo_CFLite|Win32 = Release_Cairo_CFLite|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Debug|Win32.Build.0 = Debug|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Production|Win32.ActiveCfg = Production|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Production|Win32.Build.0 = Production|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Release|Win32.ActiveCfg = Release|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Release|Win32.Build.0 = Release|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug|Win32.Build.0 = Debug|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Production|Win32.ActiveCfg = Production|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Production|Win32.Build.0 = Production|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release|Win32.ActiveCfg = Release|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release|Win32.Build.0 = Release|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug|Win32.ActiveCfg = Debug|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug|Win32.Build.0 = Debug|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Production|Win32.ActiveCfg = Production|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Production|Win32.Build.0 = Production|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release|Win32.ActiveCfg = Release|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release|Win32.Build.0 = Release|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Debug|Win32.Build.0 = Debug|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Production|Win32.ActiveCfg = Production|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Production|Win32.Build.0 = Production|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Release|Win32.ActiveCfg = Release|Win32
+ {2974EA02-840B-4995-8719-8920A61006F1}.Release|Win32.Build.0 = Release|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Debug|Win32.Build.0 = Debug|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Production|Win32.ActiveCfg = Production|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Production|Win32.Build.0 = Production|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Release|Win32.ActiveCfg = Release|Win32
+ {DD7949B6-F2B4-47C2-9C42-E21E84CB1017}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj b/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..2032302d1
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj
@@ -0,0 +1,1153 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ A84F608D08B1370600E9745F /* All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = A84F609208B1371400E9745F /* Build configuration list for PBXAggregateTarget "All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ A84F609108B1370E00E9745F /* PBXTargetDependency */,
+ A84F608F08B1370E00E9745F /* PBXTargetDependency */,
+ 141BF238096A451E00E0753C /* PBXTargetDependency */,
+ 5DC82A701023C93D00FD1D3B /* PBXTargetDependency */,
+ );
+ name = All;
+ productName = All;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 0F37A4A711E6628700275F54 /* PluginObjectMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F37A4A611E6628700275F54 /* PluginObjectMac.mm */; };
+ 0F37A4AA11E6629100275F54 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A752A108AF5D1F00138E45 /* QuartzCore.framework */; };
+ 141BF435096A455900E0753C /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9335435F03D75502008635CE /* WebKit.framework */; };
+ 141BF436096A455900E0753C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A84F608908B136DA00E9745F /* Cocoa.framework */; };
+ 141BF438096A455900E0753C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A817090308B164D300CCB9FB /* JavaScriptCore.framework */; };
+ 141BF439096A455900E0753C /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE8257EF08D22389000507AB /* Carbon.framework */; };
+ 141BF453096A45EB00E0753C /* PluginObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 141BF447096A45C800E0753C /* PluginObject.h */; };
+ 14770FE20A22ADF7009342EE /* GCController.h in Headers */ = {isa = PBXBuildFile; fileRef = 14770FE00A22ADF7009342EE /* GCController.h */; };
+ 1A14C8A51406DE0400B254F7 /* SupportsCarbonEventModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A14C8A31406DE0400B254F7 /* SupportsCarbonEventModel.cpp */; };
+ 1A1E4298141141C400388758 /* PrivateBrowsing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A1E4296141141C400388758 /* PrivateBrowsing.cpp */; };
+ 1A215A8111F2609C008AD0F5 /* PluginTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A215A7F11F2609C008AD0F5 /* PluginTest.cpp */; };
+ 1A215A8211F2609C008AD0F5 /* PluginTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A215A8011F2609C008AD0F5 /* PluginTest.h */; };
+ 1A215BE711F27658008AD0F5 /* DocumentOpenInDestroyStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */; };
+ 1A24BAA9120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */; };
+ 1A31EB3813466AC100017372 /* ConvertPoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A31EB3713466AC100017372 /* ConvertPoint.cpp */; };
+ 1A3E28AA1311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */; };
+ 1A5CC1F5137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5CC1F3137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp */; };
+ 1A66C35114576A920099A115 /* ContentsScaleFactor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A66C34F14576A920099A115 /* ContentsScaleFactor.cpp */; };
+ 1A8F02E80BB9B4EC008CFA34 /* TestObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A8F024C0BB9B056008CFA34 /* TestObject.h */; };
+ 1AC6C8490D07638600CD3161 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C77F0D07589B00CD3161 /* main.cpp */; };
+ 1AC6C84A0D07638600CD3161 /* PluginObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C7800D07589B00CD3161 /* PluginObject.cpp */; };
+ 1AC6C84B0D07638600CD3161 /* TestObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C7810D07589B00CD3161 /* TestObject.cpp */; };
+ 1AC77DCF120605B6005C19EF /* NPRuntimeRemoveProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */; };
+ 1ACF898D132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACF898B132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp */; };
+ 1AD4CB2212A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */; };
+ 1AD9D2FE12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AD9D2FD12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp */; };
+ 1AFF66BC137DEFD200791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF66BB137DEA8300791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp */; };
+ 23BCB8900EA57623003C6289 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23BCB88F0EA57623003C6289 /* OpenGL.framework */; };
+ 29CFBA10122736E600BC30C0 /* AccessibilityTextMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = 29CFBA0E122736E600BC30C0 /* AccessibilityTextMarker.h */; };
+ 29CFBA11122736E600BC30C0 /* AccessibilityTextMarker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 29CFBA0F122736E600BC30C0 /* AccessibilityTextMarker.cpp */; };
+ 29CFBA2E12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29CFBA2D12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm */; };
+ 3A5626CB131CA02A002BE6D9 /* StorageTrackerDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3A5626C1131C8B17002BE6D9 /* StorageTrackerDelegate.mm */; };
+ 3A5626CC131CA036002BE6D9 /* StorageTrackerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A5626C0131C8B17002BE6D9 /* StorageTrackerDelegate.h */; };
+ 417DAA1D137B3E24007C57FB /* WebCoreTestSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 417DAA1C137B3E24007C57FB /* WebCoreTestSupport.h */; };
+ 440590711268453800CFD48D /* WebArchiveDumpSupportMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 440590701268453800CFD48D /* WebArchiveDumpSupportMac.mm */; };
+ 4437730E125CBC3600AAE02C /* WebArchiveDumpSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 44A997830FCDE86400580F10 /* WebArchiveDumpSupport.cpp */; };
+ 4437730F125CBC4D00AAE02C /* WebArchiveDumpSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 44A997820FCDE86400580F10 /* WebArchiveDumpSupport.h */; };
+ 4AD6A11413C8124000EA9737 /* FormValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AD6A11313C8124000EA9737 /* FormValue.cpp */; };
+ 5185F6B210714E07007AA393 /* HistoryDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5185F69F10714A57007AA393 /* HistoryDelegate.mm */; };
+ 5185F6B310714E12007AA393 /* HistoryDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5185F69E10714A57007AA393 /* HistoryDelegate.h */; };
+ 53CBB832134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBB830134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp */; };
+ 53CBB833134E42F3001CE6A4 /* CyclicRedundancyCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */; };
+ 5DB9AC970F722C3600684641 /* AHEM____.TTF in Copy Font Files */ = {isa = PBXBuildFile; fileRef = AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */; };
+ 5DB9AC980F722C3600684641 /* WebKitWeightWatcher100.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */; };
+ 5DB9AC990F722C3600684641 /* WebKitWeightWatcher200.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */; };
+ 5DB9AC9A0F722C3600684641 /* WebKitWeightWatcher300.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09730DAC3CB600C8B4E5 /* WebKitWeightWatcher300.ttf */; };
+ 5DB9AC9B0F722C3600684641 /* WebKitWeightWatcher400.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09740DAC3CB600C8B4E5 /* WebKitWeightWatcher400.ttf */; };
+ 5DB9AC9C0F722C3600684641 /* WebKitWeightWatcher500.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09750DAC3CB600C8B4E5 /* WebKitWeightWatcher500.ttf */; };
+ 5DB9AC9D0F722C3600684641 /* WebKitWeightWatcher600.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09760DAC3CB600C8B4E5 /* WebKitWeightWatcher600.ttf */; };
+ 5DB9AC9E0F722C3600684641 /* WebKitWeightWatcher700.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09770DAC3CB600C8B4E5 /* WebKitWeightWatcher700.ttf */; };
+ 5DB9AC9F0F722C3600684641 /* WebKitWeightWatcher800.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09780DAC3CB600C8B4E5 /* WebKitWeightWatcher800.ttf */; };
+ 5DB9ACA00F722C3600684641 /* WebKitWeightWatcher900.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09790DAC3CB600C8B4E5 /* WebKitWeightWatcher900.ttf */; };
+ 5DE8AE4413A2C15900D6A37D /* libWebCoreTestSupport.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DE8AE4313A2C15800D6A37D /* libWebCoreTestSupport.dylib */; };
+ 80045AED147718E7008290A8 /* AccessibilityNotificationHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 80045AEB147718E7008290A8 /* AccessibilityNotificationHandler.h */; };
+ 80045AEE147718E7008290A8 /* AccessibilityNotificationHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 80045AEC147718E7008290A8 /* AccessibilityNotificationHandler.mm */; };
+ 8465E2C70FFA8DF2003B8342 /* PixelDumpSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */; };
+ 933BF5AB0F93FA5C000F0441 /* PlainTextController.h in Headers */ = {isa = PBXBuildFile; fileRef = 933BF5A90F93FA5C000F0441 /* PlainTextController.h */; };
+ 933BF5AC0F93FA5C000F0441 /* PlainTextController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 933BF5AA0F93FA5C000F0441 /* PlainTextController.mm */; };
+ 9340994C08540CAE007F3BC8 /* DumpRenderTreePrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = 32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */; };
+ 9340995108540CAE007F3BC8 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9335435F03D75502008635CE /* WebKit.framework */; };
+ A817090008B163EF00CCB9FB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A84F608908B136DA00E9745F /* Cocoa.framework */; };
+ A817090408B164D300CCB9FB /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A817090308B164D300CCB9FB /* JavaScriptCore.framework */; };
+ A84F608A08B136DA00E9745F /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A84F608908B136DA00E9745F /* Cocoa.framework */; };
+ A8B91ADA0CF3B32F008F91FF /* DumpRenderTreePasteboard.m in Sources */ = {isa = PBXBuildFile; fileRef = A8B91AD70CF3B32F008F91FF /* DumpRenderTreePasteboard.m */; };
+ A8B91ADC0CF3B32F008F91FF /* DumpRenderTreeWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = A8B91AD90CF3B32F008F91FF /* DumpRenderTreeWindow.mm */; };
+ A8B91AE00CF3B372008F91FF /* DumpRenderTreeWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A8B91ADD0CF3B372008F91FF /* DumpRenderTreeWindow.h */; };
+ A8B91AE20CF3B372008F91FF /* DumpRenderTreePasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = A8B91ADF0CF3B372008F91FF /* DumpRenderTreePasteboard.h */; };
+ A8B91BFD0CF522B4008F91FF /* CheckedMalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8B91BF70CF522B4008F91FF /* CheckedMalloc.cpp */; };
+ A8B91BFF0CF522B4008F91FF /* CheckedMalloc.h in Headers */ = {isa = PBXBuildFile; fileRef = A8B91BF90CF522B4008F91FF /* CheckedMalloc.h */; };
+ A8D79CEA0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A8D79CE80FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h */; };
+ A8D79CEB0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A8D79CE90FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m */; };
+ AE8259F308D22463000507AB /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE8257EF08D22389000507AB /* Carbon.framework */; };
+ AE8259F408D22463000507AB /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE8257EF08D22389000507AB /* Carbon.framework */; };
+ B5A752A208AF5D1F00138E45 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5A752A108AF5D1F00138E45 /* QuartzCore.framework */; };
+ BC0131DA0C9772010087317D /* LayoutTestController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0131D80C9772010087317D /* LayoutTestController.cpp */; };
+ BC0131DB0C9772010087317D /* LayoutTestController.h in Headers */ = {isa = PBXBuildFile; fileRef = BC0131D90C9772010087317D /* LayoutTestController.h */; };
+ BC0E24E00E2D9451001B6BC2 /* AccessibilityUIElement.h in Headers */ = {isa = PBXBuildFile; fileRef = BC0E24DE0E2D9451001B6BC2 /* AccessibilityUIElement.h */; };
+ BC0E24E10E2D9451001B6BC2 /* AccessibilityUIElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0E24DF0E2D9451001B6BC2 /* AccessibilityUIElement.cpp */; };
+ BC0E26150E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC0E26140E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm */; };
+ BC47412A0D038A4C0072B006 /* JavaScriptThreading.h in Headers */ = {isa = PBXBuildFile; fileRef = BC4741290D038A4C0072B006 /* JavaScriptThreading.h */; };
+ BC4741410D038A570072B006 /* JavaScriptThreadingPthreads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC4741400D038A570072B006 /* JavaScriptThreadingPthreads.cpp */; };
+ BC9D90240C97472E0099A4A3 /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC9D90210C97472D0099A4A3 /* WorkQueue.cpp */; };
+ BC9D90250C97472E0099A4A3 /* WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = BC9D90220C97472E0099A4A3 /* WorkQueue.h */; };
+ BC9D90260C97472E0099A4A3 /* WorkQueueItem.h in Headers */ = {isa = PBXBuildFile; fileRef = BC9D90230C97472E0099A4A3 /* WorkQueueItem.h */; };
+ BCA18B230C9B014B00114369 /* GCControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B210C9B014B00114369 /* GCControllerMac.mm */; };
+ BCA18B240C9B014B00114369 /* LayoutTestControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B220C9B014B00114369 /* LayoutTestControllerMac.mm */; };
+ BCA18B260C9B015C00114369 /* WorkQueueItemMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B250C9B015C00114369 /* WorkQueueItemMac.mm */; };
+ BCA18B310C9B01B400114369 /* ObjCController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B2F0C9B01B400114369 /* ObjCController.h */; };
+ BCA18B320C9B01B400114369 /* ObjCController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B300C9B01B400114369 /* ObjCController.m */; };
+ BCA18B380C9B021900114369 /* AppleScriptController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B360C9B021900114369 /* AppleScriptController.h */; };
+ BCA18B390C9B021900114369 /* AppleScriptController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B370C9B021900114369 /* AppleScriptController.m */; };
+ BCA18B3C0C9B024900114369 /* TextInputController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B3A0C9B024900114369 /* TextInputController.h */; };
+ BCA18B490C9B02C400114369 /* TextInputController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B480C9B02C400114369 /* TextInputController.m */; };
+ BCA18B610C9B08C200114369 /* EditingDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B570C9B08C200114369 /* EditingDelegate.h */; };
+ BCA18B620C9B08C200114369 /* EditingDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B580C9B08C200114369 /* EditingDelegate.mm */; };
+ BCA18B630C9B08C200114369 /* FrameLoadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B590C9B08C200114369 /* FrameLoadDelegate.h */; };
+ BCA18B640C9B08C200114369 /* FrameLoadDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B5A0C9B08C200114369 /* FrameLoadDelegate.mm */; };
+ BCA18B650C9B08C200114369 /* PolicyDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B5B0C9B08C200114369 /* PolicyDelegate.h */; };
+ BCA18B660C9B08C200114369 /* PolicyDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B5C0C9B08C200114369 /* PolicyDelegate.mm */; };
+ BCA18B670C9B08C200114369 /* ResourceLoadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B5D0C9B08C200114369 /* ResourceLoadDelegate.h */; };
+ BCA18B680C9B08C200114369 /* ResourceLoadDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B5E0C9B08C200114369 /* ResourceLoadDelegate.mm */; };
+ BCA18B690C9B08C200114369 /* UIDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B5F0C9B08C200114369 /* UIDelegate.h */; };
+ BCA18B6A0C9B08C200114369 /* UIDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B600C9B08C200114369 /* UIDelegate.mm */; };
+ BCA18B6F0C9B08DB00114369 /* EventSendingController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B6B0C9B08DB00114369 /* EventSendingController.h */; };
+ BCA18B700C9B08DB00114369 /* EventSendingController.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B6C0C9B08DB00114369 /* EventSendingController.mm */; };
+ BCA18B710C9B08DB00114369 /* NavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B6D0C9B08DB00114369 /* NavigationController.h */; };
+ BCA18B720C9B08DB00114369 /* NavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B6E0C9B08DB00114369 /* NavigationController.m */; };
+ BCA18B7A0C9B08F100114369 /* DumpRenderTreeDraggingInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B730C9B08F100114369 /* DumpRenderTreeDraggingInfo.h */; };
+ BCA18B7B0C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B740C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm */; };
+ BCA18B7D0C9B08F100114369 /* ObjCPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B760C9B08F100114369 /* ObjCPlugin.h */; };
+ BCA18B7E0C9B08F100114369 /* ObjCPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B770C9B08F100114369 /* ObjCPlugin.m */; };
+ BCA18B7F0C9B08F100114369 /* ObjCPluginFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18B780C9B08F100114369 /* ObjCPluginFunction.h */; };
+ BCA18B800C9B08F100114369 /* ObjCPluginFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = BCA18B790C9B08F100114369 /* ObjCPluginFunction.m */; };
+ BCA18C0B0C9B59EF00114369 /* DumpRenderTreeMac.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA18C0A0C9B59EF00114369 /* DumpRenderTreeMac.h */; };
+ BCA18C470C9B5B9400114369 /* DumpRenderTree.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18C460C9B5B9400114369 /* DumpRenderTree.mm */; settings = {COMPILER_FLAGS = "-Wno-deprecated-declarations"; }; };
+ BCB284C70CFA83C4007E533E /* PixelDumpSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = BCB2848A0CFA820F007E533E /* PixelDumpSupport.h */; };
+ BCB284CD0CFA83C8007E533E /* PixelDumpSupportCG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCB284880CFA8202007E533E /* PixelDumpSupportCG.cpp */; };
+ BCB284D00CFA83CC007E533E /* PixelDumpSupportCG.h in Headers */ = {isa = PBXBuildFile; fileRef = BCB284890CFA8202007E533E /* PixelDumpSupportCG.h */; };
+ BCB284D60CFA83D1007E533E /* PixelDumpSupportMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCB2848C0CFA8221007E533E /* PixelDumpSupportMac.mm */; };
+ BCB284F60CFA84F8007E533E /* ImageDiffCG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCB284F30CFA84F2007E533E /* ImageDiffCG.cpp */; };
+ BCD08B3A0E1057EF00A7D0C1 /* AccessibilityController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */; };
+ BCD08B710E1059D200A7D0C1 /* AccessibilityControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */; };
+ BCF6C6500C98E9C000AC063E /* GCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCF6C64F0C98E9C000AC063E /* GCController.cpp */; };
+ C031182B134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */; };
+ C06F9ABC1267A7060058E1F6 /* PassDifferentNPPStruct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */; };
+ C0E720751281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */; };
+ C0EC3C9C12787F0500939164 /* NullNPPGetValuePointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */; };
+ E1B7816511AF31B7007E1BC2 /* MockGeolocationProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */; };
+ E1B7816711AF31C3007E1BC2 /* MockGeolocationProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 141BF237096A451E00E0753C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 141BF21E096A441D00E0753C;
+ remoteInfo = TestNetscapePlugIn;
+ };
+ 5DC82A6F1023C93D00FD1D3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5DC82A661023C8DE00FD1D3B;
+ remoteInfo = "DumpRenderTree Perl Support";
+ };
+ A84F608E08B1370E00E9745F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B5A7525A08AF4A4A00138E45;
+ remoteInfo = ImageDiff;
+ };
+ A84F609008B1370E00E9745F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 9340994A08540CAE007F3BC8;
+ remoteInfo = DumpRenderTree;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 5DB9ACAA0F722C4400684641 /* Copy Font Files */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = DumpRenderTree.resources;
+ dstSubfolderSpec = 7;
+ files = (
+ 5DB9AC970F722C3600684641 /* AHEM____.TTF in Copy Font Files */,
+ 5DB9AC980F722C3600684641 /* WebKitWeightWatcher100.ttf in Copy Font Files */,
+ 5DB9AC990F722C3600684641 /* WebKitWeightWatcher200.ttf in Copy Font Files */,
+ 5DB9AC9A0F722C3600684641 /* WebKitWeightWatcher300.ttf in Copy Font Files */,
+ 5DB9AC9B0F722C3600684641 /* WebKitWeightWatcher400.ttf in Copy Font Files */,
+ 5DB9AC9C0F722C3600684641 /* WebKitWeightWatcher500.ttf in Copy Font Files */,
+ 5DB9AC9D0F722C3600684641 /* WebKitWeightWatcher600.ttf in Copy Font Files */,
+ 5DB9AC9E0F722C3600684641 /* WebKitWeightWatcher700.ttf in Copy Font Files */,
+ 5DB9AC9F0F722C3600684641 /* WebKitWeightWatcher800.ttf in Copy Font Files */,
+ 5DB9ACA00F722C3600684641 /* WebKitWeightWatcher900.ttf in Copy Font Files */,
+ );
+ name = "Copy Font Files";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 0F37A4A611E6628700275F54 /* PluginObjectMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PluginObjectMac.mm; sourceTree = "<group>"; };
+ 141BF233096A44CF00E0753C /* TestNetscapePlugIn.plugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestNetscapePlugIn.plugin; sourceTree = BUILT_PRODUCTS_DIR; };
+ 141BF447096A45C800E0753C /* PluginObject.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PluginObject.h; sourceTree = "<group>"; };
+ 141BF448096A45C800E0753C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; name = Info.plist; path = mac/Info.plist; sourceTree = "<group>"; };
+ 14770FE00A22ADF7009342EE /* GCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCController.h; sourceTree = "<group>"; };
+ 1A14C8A31406DE0400B254F7 /* SupportsCarbonEventModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SupportsCarbonEventModel.cpp; sourceTree = "<group>"; };
+ 1A1E4296141141C400388758 /* PrivateBrowsing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrivateBrowsing.cpp; sourceTree = "<group>"; };
+ 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentOpenInDestroyStream.cpp; sourceTree = "<group>"; };
+ 1A215A7F11F2609C008AD0F5 /* PluginTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginTest.cpp; sourceTree = "<group>"; };
+ 1A215A8011F2609C008AD0F5 /* PluginTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginTest.h; sourceTree = "<group>"; };
+ 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPRuntimeObjectFromDestroyedPlugin.cpp; sourceTree = "<group>"; };
+ 1A31EB3713466AC100017372 /* ConvertPoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConvertPoint.cpp; sourceTree = "<group>"; };
+ 1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetURLWithJavaScriptURLDestroyingPlugin.cpp; sourceTree = "<group>"; };
+ 1A5CC1F3137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetURLWithJavaScriptURL.cpp; sourceTree = "<group>"; };
+ 1A66C34F14576A920099A115 /* ContentsScaleFactor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentsScaleFactor.cpp; sourceTree = "<group>"; };
+ 1A8F024C0BB9B056008CFA34 /* TestObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestObject.h; sourceTree = "<group>"; };
+ 1AC6C77F0D07589B00CD3161 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
+ 1AC6C7800D07589B00CD3161 /* PluginObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginObject.cpp; sourceTree = "<group>"; };
+ 1AC6C7810D07589B00CD3161 /* TestObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestObject.cpp; sourceTree = "<group>"; };
+ 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPRuntimeRemoveProperty.cpp; sourceTree = "<group>"; };
+ 1ACF898B132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPDeallocateCalledBeforeNPShutdown.cpp; sourceTree = "<group>"; };
+ 1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetUserAgentWithNullNPPFromNPPNew.cpp; sourceTree = "<group>"; };
+ 1AD9D2FD12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginScriptableNPObjectInvokeDefault.cpp; sourceTree = "<group>"; };
+ 1AFF66BB137DEA8300791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetURLNotifyWithURLThatFailsToLoad.cpp; sourceTree = "<group>"; };
+ 23BCB88F0EA57623003C6289 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
+ 29CFBA0E122736E600BC30C0 /* AccessibilityTextMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityTextMarker.h; sourceTree = "<group>"; };
+ 29CFBA0F122736E600BC30C0 /* AccessibilityTextMarker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityTextMarker.cpp; sourceTree = "<group>"; };
+ 29CFBA2D12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityTextMarkerMac.mm; path = mac/AccessibilityTextMarkerMac.mm; sourceTree = "<group>"; };
+ 32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumpRenderTreePrefix.h; sourceTree = "<group>"; };
+ 375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher100.ttf; path = fonts/WebKitWeightWatcher100.ttf; sourceTree = "<group>"; };
+ 375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher200.ttf; path = fonts/WebKitWeightWatcher200.ttf; sourceTree = "<group>"; };
+ 375F09730DAC3CB600C8B4E5 /* WebKitWeightWatcher300.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher300.ttf; path = fonts/WebKitWeightWatcher300.ttf; sourceTree = "<group>"; };
+ 375F09740DAC3CB600C8B4E5 /* WebKitWeightWatcher400.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher400.ttf; path = fonts/WebKitWeightWatcher400.ttf; sourceTree = "<group>"; };
+ 375F09750DAC3CB600C8B4E5 /* WebKitWeightWatcher500.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher500.ttf; path = fonts/WebKitWeightWatcher500.ttf; sourceTree = "<group>"; };
+ 375F09760DAC3CB600C8B4E5 /* WebKitWeightWatcher600.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher600.ttf; path = fonts/WebKitWeightWatcher600.ttf; sourceTree = "<group>"; };
+ 375F09770DAC3CB600C8B4E5 /* WebKitWeightWatcher700.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher700.ttf; path = fonts/WebKitWeightWatcher700.ttf; sourceTree = "<group>"; };
+ 375F09780DAC3CB600C8B4E5 /* WebKitWeightWatcher800.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher800.ttf; path = fonts/WebKitWeightWatcher800.ttf; sourceTree = "<group>"; };
+ 375F09790DAC3CB600C8B4E5 /* WebKitWeightWatcher900.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher900.ttf; path = fonts/WebKitWeightWatcher900.ttf; sourceTree = "<group>"; };
+ 3A5626C0131C8B17002BE6D9 /* StorageTrackerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageTrackerDelegate.h; sourceTree = "<group>"; };
+ 3A5626C1131C8B17002BE6D9 /* StorageTrackerDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StorageTrackerDelegate.mm; sourceTree = "<group>"; };
+ 417DAA1C137B3E24007C57FB /* WebCoreTestSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebCoreTestSupport.h; path = WebCoreTestSupport/WebCoreTestSupport.h; sourceTree = BUILT_PRODUCTS_DIR; };
+ 440590701268453800CFD48D /* WebArchiveDumpSupportMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WebArchiveDumpSupportMac.mm; path = mac/WebArchiveDumpSupportMac.mm; sourceTree = "<group>"; };
+ 44A997820FCDE86400580F10 /* WebArchiveDumpSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebArchiveDumpSupport.h; path = cf/WebArchiveDumpSupport.h; sourceTree = "<group>"; };
+ 44A997830FCDE86400580F10 /* WebArchiveDumpSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebArchiveDumpSupport.cpp; path = cf/WebArchiveDumpSupport.cpp; sourceTree = "<group>"; };
+ 4AD6A11313C8124000EA9737 /* FormValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormValue.cpp; sourceTree = "<group>"; };
+ 5185F69E10714A57007AA393 /* HistoryDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HistoryDelegate.h; path = mac/HistoryDelegate.h; sourceTree = "<group>"; };
+ 5185F69F10714A57007AA393 /* HistoryDelegate.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = HistoryDelegate.mm; path = mac/HistoryDelegate.mm; sourceTree = "<group>"; };
+ 53CBB830134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CyclicRedundancyCheck.cpp; sourceTree = "<group>"; };
+ 53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CyclicRedundancyCheck.h; sourceTree = "<group>"; };
+ 5DE8AE4313A2C15800D6A37D /* libWebCoreTestSupport.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libWebCoreTestSupport.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ 80045AEB147718E7008290A8 /* AccessibilityNotificationHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AccessibilityNotificationHandler.h; path = mac/AccessibilityNotificationHandler.h; sourceTree = "<group>"; };
+ 80045AEC147718E7008290A8 /* AccessibilityNotificationHandler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityNotificationHandler.mm; path = mac/AccessibilityNotificationHandler.mm; sourceTree = "<group>"; };
+ 8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PixelDumpSupport.cpp; sourceTree = "<group>"; };
+ 9335435F03D75502008635CE /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WebKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 933BF5A90F93FA5C000F0441 /* PlainTextController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlainTextController.h; path = mac/PlainTextController.h; sourceTree = "<group>"; };
+ 933BF5AA0F93FA5C000F0441 /* PlainTextController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlainTextController.mm; path = mac/PlainTextController.mm; sourceTree = "<group>"; };
+ 9340995408540CAF007F3BC8 /* DumpRenderTree */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DumpRenderTree; sourceTree = BUILT_PRODUCTS_DIR; };
+ A803FF7409CAAD08009B2A37 /* DumpRenderTree.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = DumpRenderTree.h; sourceTree = "<group>"; };
+ A817090308B164D300CCB9FB /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ A84F608908B136DA00E9745F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ A8B91AD70CF3B32F008F91FF /* DumpRenderTreePasteboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DumpRenderTreePasteboard.m; path = mac/DumpRenderTreePasteboard.m; sourceTree = "<group>"; };
+ A8B91AD90CF3B32F008F91FF /* DumpRenderTreeWindow.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = DumpRenderTreeWindow.mm; path = mac/DumpRenderTreeWindow.mm; sourceTree = "<group>"; };
+ A8B91ADD0CF3B372008F91FF /* DumpRenderTreeWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreeWindow.h; path = mac/DumpRenderTreeWindow.h; sourceTree = "<group>"; };
+ A8B91ADF0CF3B372008F91FF /* DumpRenderTreePasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreePasteboard.h; path = mac/DumpRenderTreePasteboard.h; sourceTree = "<group>"; };
+ A8B91BF70CF522B4008F91FF /* CheckedMalloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckedMalloc.cpp; path = mac/CheckedMalloc.cpp; sourceTree = "<group>"; };
+ A8B91BF90CF522B4008F91FF /* CheckedMalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CheckedMalloc.h; path = mac/CheckedMalloc.h; sourceTree = "<group>"; };
+ A8D79CE80FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumpRenderTreeFileDraggingSource.h; sourceTree = "<group>"; };
+ A8D79CE90FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DumpRenderTreeFileDraggingSource.m; sourceTree = "<group>"; };
+ AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */ = {isa = PBXFileReference; lastKnownFileType = file; name = "AHEM____.TTF"; path = "qt/fonts/AHEM____.TTF"; sourceTree = "<group>"; };
+ AE8257EF08D22389000507AB /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
+ B5A7526708AF4A4A00138E45 /* ImageDiff */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ImageDiff; sourceTree = BUILT_PRODUCTS_DIR; };
+ B5A752A108AF5D1F00138E45 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
+ BC0131D80C9772010087317D /* LayoutTestController.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutTestController.cpp; sourceTree = "<group>"; };
+ BC0131D90C9772010087317D /* LayoutTestController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LayoutTestController.h; sourceTree = "<group>"; };
+ BC0E24DE0E2D9451001B6BC2 /* AccessibilityUIElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityUIElement.h; sourceTree = "<group>"; };
+ BC0E24DF0E2D9451001B6BC2 /* AccessibilityUIElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityUIElement.cpp; sourceTree = "<group>"; };
+ BC0E26140E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityUIElementMac.mm; path = mac/AccessibilityUIElementMac.mm; sourceTree = "<group>"; };
+ BC4741290D038A4C0072B006 /* JavaScriptThreading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptThreading.h; sourceTree = "<group>"; };
+ BC4741400D038A570072B006 /* JavaScriptThreadingPthreads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JavaScriptThreadingPthreads.cpp; path = pthreads/JavaScriptThreadingPthreads.cpp; sourceTree = "<group>"; };
+ BC646A4B136905DE00B35DED /* CompilerVersion.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = CompilerVersion.xcconfig; path = mac/Configurations/CompilerVersion.xcconfig; sourceTree = "<group>"; };
+ BC9D90210C97472D0099A4A3 /* WorkQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = WorkQueue.cpp; sourceTree = "<group>"; };
+ BC9D90220C97472E0099A4A3 /* WorkQueue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WorkQueue.h; sourceTree = "<group>"; };
+ BC9D90230C97472E0099A4A3 /* WorkQueueItem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WorkQueueItem.h; sourceTree = "<group>"; };
+ BCA18B210C9B014B00114369 /* GCControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = GCControllerMac.mm; path = mac/GCControllerMac.mm; sourceTree = "<group>"; };
+ BCA18B220C9B014B00114369 /* LayoutTestControllerMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = LayoutTestControllerMac.mm; path = mac/LayoutTestControllerMac.mm; sourceTree = "<group>"; };
+ BCA18B250C9B015C00114369 /* WorkQueueItemMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = WorkQueueItemMac.mm; path = mac/WorkQueueItemMac.mm; sourceTree = "<group>"; };
+ BCA18B2F0C9B01B400114369 /* ObjCController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjCController.h; path = mac/ObjCController.h; sourceTree = "<group>"; };
+ BCA18B300C9B01B400114369 /* ObjCController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = ObjCController.m; path = mac/ObjCController.m; sourceTree = "<group>"; };
+ BCA18B360C9B021900114369 /* AppleScriptController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AppleScriptController.h; path = mac/AppleScriptController.h; sourceTree = "<group>"; };
+ BCA18B370C9B021900114369 /* AppleScriptController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = AppleScriptController.m; path = mac/AppleScriptController.m; sourceTree = "<group>"; };
+ BCA18B3A0C9B024900114369 /* TextInputController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TextInputController.h; path = mac/TextInputController.h; sourceTree = "<group>"; };
+ BCA18B480C9B02C400114369 /* TextInputController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = TextInputController.m; path = mac/TextInputController.m; sourceTree = "<group>"; };
+ BCA18B570C9B08C200114369 /* EditingDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = EditingDelegate.h; path = mac/EditingDelegate.h; sourceTree = "<group>"; };
+ BCA18B580C9B08C200114369 /* EditingDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = EditingDelegate.mm; path = mac/EditingDelegate.mm; sourceTree = "<group>"; };
+ BCA18B590C9B08C200114369 /* FrameLoadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = FrameLoadDelegate.h; path = mac/FrameLoadDelegate.h; sourceTree = "<group>"; };
+ BCA18B5A0C9B08C200114369 /* FrameLoadDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = FrameLoadDelegate.mm; path = mac/FrameLoadDelegate.mm; sourceTree = "<group>"; };
+ BCA18B5B0C9B08C200114369 /* PolicyDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PolicyDelegate.h; path = mac/PolicyDelegate.h; sourceTree = "<group>"; };
+ BCA18B5C0C9B08C200114369 /* PolicyDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = PolicyDelegate.mm; path = mac/PolicyDelegate.mm; sourceTree = "<group>"; };
+ BCA18B5D0C9B08C200114369 /* ResourceLoadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ResourceLoadDelegate.h; path = mac/ResourceLoadDelegate.h; sourceTree = "<group>"; };
+ BCA18B5E0C9B08C200114369 /* ResourceLoadDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = ResourceLoadDelegate.mm; path = mac/ResourceLoadDelegate.mm; sourceTree = "<group>"; };
+ BCA18B5F0C9B08C200114369 /* UIDelegate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = UIDelegate.h; path = mac/UIDelegate.h; sourceTree = "<group>"; };
+ BCA18B600C9B08C200114369 /* UIDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = UIDelegate.mm; path = mac/UIDelegate.mm; sourceTree = "<group>"; };
+ BCA18B6B0C9B08DB00114369 /* EventSendingController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = EventSendingController.h; path = mac/EventSendingController.h; sourceTree = "<group>"; };
+ BCA18B6C0C9B08DB00114369 /* EventSendingController.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = EventSendingController.mm; path = mac/EventSendingController.mm; sourceTree = "<group>"; };
+ BCA18B6D0C9B08DB00114369 /* NavigationController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = NavigationController.h; path = mac/NavigationController.h; sourceTree = "<group>"; };
+ BCA18B6E0C9B08DB00114369 /* NavigationController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = NavigationController.m; path = mac/NavigationController.m; sourceTree = "<group>"; };
+ BCA18B730C9B08F100114369 /* DumpRenderTreeDraggingInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreeDraggingInfo.h; path = mac/DumpRenderTreeDraggingInfo.h; sourceTree = "<group>"; };
+ BCA18B740C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = DumpRenderTreeDraggingInfo.mm; path = mac/DumpRenderTreeDraggingInfo.mm; sourceTree = "<group>"; };
+ BCA18B760C9B08F100114369 /* ObjCPlugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjCPlugin.h; path = mac/ObjCPlugin.h; sourceTree = "<group>"; };
+ BCA18B770C9B08F100114369 /* ObjCPlugin.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = ObjCPlugin.m; path = mac/ObjCPlugin.m; sourceTree = "<group>"; };
+ BCA18B780C9B08F100114369 /* ObjCPluginFunction.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjCPluginFunction.h; path = mac/ObjCPluginFunction.h; sourceTree = "<group>"; };
+ BCA18B790C9B08F100114369 /* ObjCPluginFunction.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = ObjCPluginFunction.m; path = mac/ObjCPluginFunction.m; sourceTree = "<group>"; };
+ BCA18C0A0C9B59EF00114369 /* DumpRenderTreeMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DumpRenderTreeMac.h; path = mac/DumpRenderTreeMac.h; sourceTree = "<group>"; };
+ BCA18C460C9B5B9400114369 /* DumpRenderTree.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = DumpRenderTree.mm; path = mac/DumpRenderTree.mm; sourceTree = "<group>"; };
+ BCB281EE0CFA713D007E533E /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = Base.xcconfig; path = mac/Configurations/Base.xcconfig; sourceTree = "<group>"; };
+ BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = DumpRenderTree.xcconfig; path = mac/Configurations/DumpRenderTree.xcconfig; sourceTree = "<group>"; };
+ BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = DebugRelease.xcconfig; path = mac/Configurations/DebugRelease.xcconfig; sourceTree = "<group>"; };
+ BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = ImageDiff.xcconfig; path = mac/Configurations/ImageDiff.xcconfig; sourceTree = "<group>"; };
+ BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = TestNetscapePlugIn.xcconfig; path = mac/Configurations/TestNetscapePlugIn.xcconfig; sourceTree = "<group>"; };
+ BCB284880CFA8202007E533E /* PixelDumpSupportCG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PixelDumpSupportCG.cpp; path = cg/PixelDumpSupportCG.cpp; sourceTree = "<group>"; };
+ BCB284890CFA8202007E533E /* PixelDumpSupportCG.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PixelDumpSupportCG.h; path = cg/PixelDumpSupportCG.h; sourceTree = "<group>"; };
+ BCB2848A0CFA820F007E533E /* PixelDumpSupport.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PixelDumpSupport.h; sourceTree = "<group>"; };
+ BCB2848C0CFA8221007E533E /* PixelDumpSupportMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = PixelDumpSupportMac.mm; path = mac/PixelDumpSupportMac.mm; sourceTree = "<group>"; };
+ BCB284B20CFA82CB007E533E /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = "<absolute>"; };
+ BCB284F30CFA84F2007E533E /* ImageDiffCG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ImageDiffCG.cpp; path = cg/ImageDiffCG.cpp; sourceTree = "<group>"; };
+ BCD08A580E10496B00A7D0C1 /* AccessibilityController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityController.h; sourceTree = "<group>"; };
+ BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityController.cpp; sourceTree = "<group>"; };
+ BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityControllerMac.mm; path = mac/AccessibilityControllerMac.mm; sourceTree = "<group>"; };
+ BCF6C64F0C98E9C000AC063E /* GCController.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = GCController.cpp; sourceTree = "<group>"; };
+ C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPPSetWindowCalledDuringDestruction.cpp; sourceTree = "<group>"; };
+ C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PassDifferentNPPStruct.cpp; sourceTree = "<group>"; };
+ C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EvaluateJSAfterRemovingPluginElement.cpp; sourceTree = "<group>"; };
+ C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NullNPPGetValuePointer.cpp; sourceTree = "<group>"; };
+ E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MockGeolocationProvider.h; path = mac/MockGeolocationProvider.h; sourceTree = "<group>"; };
+ E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MockGeolocationProvider.mm; path = mac/MockGeolocationProvider.mm; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 141BF21D096A441D00E0753C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 141BF439096A455900E0753C /* Carbon.framework in Frameworks */,
+ 141BF436096A455900E0753C /* Cocoa.framework in Frameworks */,
+ 141BF438096A455900E0753C /* JavaScriptCore.framework in Frameworks */,
+ 141BF435096A455900E0753C /* WebKit.framework in Frameworks */,
+ 0F37A4AA11E6629100275F54 /* QuartzCore.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 9340994F08540CAE007F3BC8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5DE8AE4413A2C15900D6A37D /* libWebCoreTestSupport.dylib in Frameworks */,
+ AE8259F308D22463000507AB /* Carbon.framework in Frameworks */,
+ A84F608A08B136DA00E9745F /* Cocoa.framework in Frameworks */,
+ A817090408B164D300CCB9FB /* JavaScriptCore.framework in Frameworks */,
+ 23BCB8900EA57623003C6289 /* OpenGL.framework in Frameworks */,
+ 9340995108540CAE007F3BC8 /* WebKit.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B5A7525F08AF4A4A00138E45 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AE8259F408D22463000507AB /* Carbon.framework in Frameworks */,
+ A817090008B163EF00CCB9FB /* Cocoa.framework in Frameworks */,
+ B5A752A208AF5D1F00138E45 /* QuartzCore.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* DumpRenderTree */ = {
+ isa = PBXGroup;
+ children = (
+ 32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */,
+ 1422A2750AF6F4BD00E1A883 /* Delegates */,
+ 1422A2690AF6F45200E1A883 /* Controllers */,
+ BCB284870CFA81ED007E533E /* PixelDump */,
+ A803FF7409CAAD08009B2A37 /* DumpRenderTree.h */,
+ BCA18C460C9B5B9400114369 /* DumpRenderTree.mm */,
+ A8B91BF70CF522B4008F91FF /* CheckedMalloc.cpp */,
+ A8B91BF90CF522B4008F91FF /* CheckedMalloc.h */,
+ BC4741290D038A4C0072B006 /* JavaScriptThreading.h */,
+ BC4741400D038A570072B006 /* JavaScriptThreadingPthreads.cpp */,
+ BCA18C0A0C9B59EF00114369 /* DumpRenderTreeMac.h */,
+ BCA18B730C9B08F100114369 /* DumpRenderTreeDraggingInfo.h */,
+ BCA18B740C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm */,
+ A8D79CE80FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h */,
+ A8D79CE90FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m */,
+ 44A997820FCDE86400580F10 /* WebArchiveDumpSupport.h */,
+ 44A997830FCDE86400580F10 /* WebArchiveDumpSupport.cpp */,
+ 440590701268453800CFD48D /* WebArchiveDumpSupportMac.mm */,
+ BC9D90210C97472D0099A4A3 /* WorkQueue.cpp */,
+ BC9D90220C97472E0099A4A3 /* WorkQueue.h */,
+ BC9D90230C97472E0099A4A3 /* WorkQueueItem.h */,
+ A8B91AD20CF3B305008F91FF /* AppKit Overrides */,
+ A8B91AC40CF3B170008F91FF /* ObjCPlugin */,
+ 141BF1F5096A439800E0753C /* TestNetscapePlugIn */,
+ 9345229B0BD12B2C0086EDA0 /* Resources */,
+ 417DA9181373674D007C57FB /* WebCoreTestSupport */,
+ A803FF6409CAACC1009B2A37 /* Frameworks */,
+ 9340995508540CAF007F3BC8 /* Products */,
+ BCB281ED0CFA711D007E533E /* Configurations */,
+ );
+ name = DumpRenderTree;
+ sourceTree = "<group>";
+ };
+ 141BF1F5096A439800E0753C /* TestNetscapePlugIn */ = {
+ isa = PBXGroup;
+ children = (
+ 1A215A6E11F25FF1008AD0F5 /* Tests */,
+ 141BF448096A45C800E0753C /* Info.plist */,
+ 1AC6C77F0D07589B00CD3161 /* main.cpp */,
+ 1AC6C7800D07589B00CD3161 /* PluginObject.cpp */,
+ 0F37A4A611E6628700275F54 /* PluginObjectMac.mm */,
+ 141BF447096A45C800E0753C /* PluginObject.h */,
+ 1A215A7F11F2609C008AD0F5 /* PluginTest.cpp */,
+ 1A215A8011F2609C008AD0F5 /* PluginTest.h */,
+ 1AC6C7810D07589B00CD3161 /* TestObject.cpp */,
+ 1A8F024C0BB9B056008CFA34 /* TestObject.h */,
+ );
+ path = TestNetscapePlugIn;
+ sourceTree = "<group>";
+ };
+ 1422A2690AF6F45200E1A883 /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ 80045AEB147718E7008290A8 /* AccessibilityNotificationHandler.h */,
+ 80045AEC147718E7008290A8 /* AccessibilityNotificationHandler.mm */,
+ BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */,
+ BCD08A580E10496B00A7D0C1 /* AccessibilityController.h */,
+ BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */,
+ 29CFBA0F122736E600BC30C0 /* AccessibilityTextMarker.cpp */,
+ 29CFBA0E122736E600BC30C0 /* AccessibilityTextMarker.h */,
+ 29CFBA2D12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm */,
+ BC0E24DF0E2D9451001B6BC2 /* AccessibilityUIElement.cpp */,
+ BC0E24DE0E2D9451001B6BC2 /* AccessibilityUIElement.h */,
+ BC0E26140E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm */,
+ BCA18B360C9B021900114369 /* AppleScriptController.h */,
+ BCA18B370C9B021900114369 /* AppleScriptController.m */,
+ BCA18B6B0C9B08DB00114369 /* EventSendingController.h */,
+ BCA18B6C0C9B08DB00114369 /* EventSendingController.mm */,
+ BCF6C64F0C98E9C000AC063E /* GCController.cpp */,
+ 14770FE00A22ADF7009342EE /* GCController.h */,
+ BCA18B210C9B014B00114369 /* GCControllerMac.mm */,
+ BC0131D80C9772010087317D /* LayoutTestController.cpp */,
+ BC0131D90C9772010087317D /* LayoutTestController.h */,
+ BCA18B220C9B014B00114369 /* LayoutTestControllerMac.mm */,
+ E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */,
+ E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */,
+ BCA18B6D0C9B08DB00114369 /* NavigationController.h */,
+ BCA18B6E0C9B08DB00114369 /* NavigationController.m */,
+ BCA18B2F0C9B01B400114369 /* ObjCController.h */,
+ BCA18B300C9B01B400114369 /* ObjCController.m */,
+ 933BF5A90F93FA5C000F0441 /* PlainTextController.h */,
+ 933BF5AA0F93FA5C000F0441 /* PlainTextController.mm */,
+ BCA18B3A0C9B024900114369 /* TextInputController.h */,
+ BCA18B480C9B02C400114369 /* TextInputController.m */,
+ );
+ name = Controllers;
+ sourceTree = "<group>";
+ usesTabs = 0;
+ };
+ 1422A2750AF6F4BD00E1A883 /* Delegates */ = {
+ isa = PBXGroup;
+ children = (
+ BCA18B570C9B08C200114369 /* EditingDelegate.h */,
+ BCA18B580C9B08C200114369 /* EditingDelegate.mm */,
+ BCA18B590C9B08C200114369 /* FrameLoadDelegate.h */,
+ BCA18B5A0C9B08C200114369 /* FrameLoadDelegate.mm */,
+ 5185F69E10714A57007AA393 /* HistoryDelegate.h */,
+ 5185F69F10714A57007AA393 /* HistoryDelegate.mm */,
+ BCA18B5B0C9B08C200114369 /* PolicyDelegate.h */,
+ BCA18B5C0C9B08C200114369 /* PolicyDelegate.mm */,
+ BCA18B5D0C9B08C200114369 /* ResourceLoadDelegate.h */,
+ BCA18B5E0C9B08C200114369 /* ResourceLoadDelegate.mm */,
+ BCA18B5F0C9B08C200114369 /* UIDelegate.h */,
+ BCA18B600C9B08C200114369 /* UIDelegate.mm */,
+ 3A5626C0131C8B17002BE6D9 /* StorageTrackerDelegate.h */,
+ 3A5626C1131C8B17002BE6D9 /* StorageTrackerDelegate.mm */,
+ );
+ name = Delegates;
+ sourceTree = "<group>";
+ };
+ 1A215A6E11F25FF1008AD0F5 /* Tests */ = {
+ isa = PBXGroup;
+ children = (
+ 1A31EB3613466AC100017372 /* mac */,
+ 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */,
+ C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */,
+ 4AD6A11313C8124000EA9737 /* FormValue.cpp */,
+ 1AFF66BB137DEA8300791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp */,
+ 1A5CC1F3137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp */,
+ 1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */,
+ 1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */,
+ 1ACF898B132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp */,
+ C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */,
+ 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */,
+ 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */,
+ C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */,
+ C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */,
+ 1AD9D2FD12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp */,
+ 1A1E4296141141C400388758 /* PrivateBrowsing.cpp */,
+ );
+ path = Tests;
+ sourceTree = "<group>";
+ };
+ 1A31EB3613466AC100017372 /* mac */ = {
+ isa = PBXGroup;
+ children = (
+ 1A31EB3713466AC100017372 /* ConvertPoint.cpp */,
+ 1A14C8A31406DE0400B254F7 /* SupportsCarbonEventModel.cpp */,
+ 1A66C34F14576A920099A115 /* ContentsScaleFactor.cpp */,
+ );
+ path = mac;
+ sourceTree = "<group>";
+ };
+ 417DA9181373674D007C57FB /* WebCoreTestSupport */ = {
+ isa = PBXGroup;
+ children = (
+ 417DAA1C137B3E24007C57FB /* WebCoreTestSupport.h */,
+ );
+ name = WebCoreTestSupport;
+ sourceTree = "<group>";
+ };
+ 9340995508540CAF007F3BC8 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 9340995408540CAF007F3BC8 /* DumpRenderTree */,
+ B5A7526708AF4A4A00138E45 /* ImageDiff */,
+ 141BF233096A44CF00E0753C /* TestNetscapePlugIn.plugin */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 9345229B0BD12B2C0086EDA0 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */,
+ 375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */,
+ 375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */,
+ 375F09730DAC3CB600C8B4E5 /* WebKitWeightWatcher300.ttf */,
+ 375F09740DAC3CB600C8B4E5 /* WebKitWeightWatcher400.ttf */,
+ 375F09750DAC3CB600C8B4E5 /* WebKitWeightWatcher500.ttf */,
+ 375F09760DAC3CB600C8B4E5 /* WebKitWeightWatcher600.ttf */,
+ 375F09770DAC3CB600C8B4E5 /* WebKitWeightWatcher700.ttf */,
+ 375F09780DAC3CB600C8B4E5 /* WebKitWeightWatcher800.ttf */,
+ 375F09790DAC3CB600C8B4E5 /* WebKitWeightWatcher900.ttf */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ A803FF6409CAACC1009B2A37 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 5DE8AE4313A2C15800D6A37D /* libWebCoreTestSupport.dylib */,
+ BCB284B20CFA82CB007E533E /* ApplicationServices.framework */,
+ AE8257EF08D22389000507AB /* Carbon.framework */,
+ A84F608908B136DA00E9745F /* Cocoa.framework */,
+ A817090308B164D300CCB9FB /* JavaScriptCore.framework */,
+ 23BCB88F0EA57623003C6289 /* OpenGL.framework */,
+ B5A752A108AF5D1F00138E45 /* QuartzCore.framework */,
+ 9335435F03D75502008635CE /* WebKit.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ A8B91AC40CF3B170008F91FF /* ObjCPlugin */ = {
+ isa = PBXGroup;
+ children = (
+ BCA18B760C9B08F100114369 /* ObjCPlugin.h */,
+ BCA18B770C9B08F100114369 /* ObjCPlugin.m */,
+ BCA18B780C9B08F100114369 /* ObjCPluginFunction.h */,
+ BCA18B790C9B08F100114369 /* ObjCPluginFunction.m */,
+ BCA18B250C9B015C00114369 /* WorkQueueItemMac.mm */,
+ );
+ name = ObjCPlugin;
+ sourceTree = "<group>";
+ };
+ A8B91AD20CF3B305008F91FF /* AppKit Overrides */ = {
+ isa = PBXGroup;
+ children = (
+ A8B91ADF0CF3B372008F91FF /* DumpRenderTreePasteboard.h */,
+ A8B91AD70CF3B32F008F91FF /* DumpRenderTreePasteboard.m */,
+ A8B91ADD0CF3B372008F91FF /* DumpRenderTreeWindow.h */,
+ A8B91AD90CF3B32F008F91FF /* DumpRenderTreeWindow.mm */,
+ );
+ name = "AppKit Overrides";
+ sourceTree = "<group>";
+ };
+ BCB281ED0CFA711D007E533E /* Configurations */ = {
+ isa = PBXGroup;
+ children = (
+ BCB281EE0CFA713D007E533E /* Base.xcconfig */,
+ BC646A4B136905DE00B35DED /* CompilerVersion.xcconfig */,
+ BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */,
+ BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */,
+ BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */,
+ BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */,
+ );
+ name = Configurations;
+ sourceTree = "<group>";
+ };
+ BCB284870CFA81ED007E533E /* PixelDump */ = {
+ isa = PBXGroup;
+ children = (
+ 53CBB830134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp */,
+ 53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */,
+ BCB284F30CFA84F2007E533E /* ImageDiffCG.cpp */,
+ 8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */,
+ BCB2848A0CFA820F007E533E /* PixelDumpSupport.h */,
+ BCB284880CFA8202007E533E /* PixelDumpSupportCG.cpp */,
+ BCB284890CFA8202007E533E /* PixelDumpSupportCG.h */,
+ BCB2848C0CFA8221007E533E /* PixelDumpSupportMac.mm */,
+ );
+ name = PixelDump;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 141BF44E096A45DD00E0753C /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 141BF453096A45EB00E0753C /* PluginObject.h in Headers */,
+ 1A8F02E80BB9B4EC008CFA34 /* TestObject.h in Headers */,
+ 1A215A8211F2609C008AD0F5 /* PluginTest.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 9340994B08540CAE007F3BC8 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC0E24E00E2D9451001B6BC2 /* AccessibilityUIElement.h in Headers */,
+ BCA18B380C9B021900114369 /* AppleScriptController.h in Headers */,
+ A8B91BFF0CF522B4008F91FF /* CheckedMalloc.h in Headers */,
+ 53CBB833134E42F3001CE6A4 /* CyclicRedundancyCheck.h in Headers */,
+ BCA18B7A0C9B08F100114369 /* DumpRenderTreeDraggingInfo.h in Headers */,
+ A8D79CEA0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h in Headers */,
+ BCA18C0B0C9B59EF00114369 /* DumpRenderTreeMac.h in Headers */,
+ A8B91AE20CF3B372008F91FF /* DumpRenderTreePasteboard.h in Headers */,
+ 9340994C08540CAE007F3BC8 /* DumpRenderTreePrefix.h in Headers */,
+ A8B91AE00CF3B372008F91FF /* DumpRenderTreeWindow.h in Headers */,
+ BCA18B610C9B08C200114369 /* EditingDelegate.h in Headers */,
+ BCA18B6F0C9B08DB00114369 /* EventSendingController.h in Headers */,
+ BCA18B630C9B08C200114369 /* FrameLoadDelegate.h in Headers */,
+ 14770FE20A22ADF7009342EE /* GCController.h in Headers */,
+ BC47412A0D038A4C0072B006 /* JavaScriptThreading.h in Headers */,
+ BC0131DB0C9772010087317D /* LayoutTestController.h in Headers */,
+ BCA18B710C9B08DB00114369 /* NavigationController.h in Headers */,
+ BCA18B310C9B01B400114369 /* ObjCController.h in Headers */,
+ BCA18B7D0C9B08F100114369 /* ObjCPlugin.h in Headers */,
+ BCA18B7F0C9B08F100114369 /* ObjCPluginFunction.h in Headers */,
+ BCB284C70CFA83C4007E533E /* PixelDumpSupport.h in Headers */,
+ BCB284D00CFA83CC007E533E /* PixelDumpSupportCG.h in Headers */,
+ 933BF5AB0F93FA5C000F0441 /* PlainTextController.h in Headers */,
+ BCA18B650C9B08C200114369 /* PolicyDelegate.h in Headers */,
+ BCA18B670C9B08C200114369 /* ResourceLoadDelegate.h in Headers */,
+ BCA18B3C0C9B024900114369 /* TextInputController.h in Headers */,
+ BCA18B690C9B08C200114369 /* UIDelegate.h in Headers */,
+ 4437730F125CBC4D00AAE02C /* WebArchiveDumpSupport.h in Headers */,
+ BC9D90250C97472E0099A4A3 /* WorkQueue.h in Headers */,
+ BC9D90260C97472E0099A4A3 /* WorkQueueItem.h in Headers */,
+ 5185F6B310714E12007AA393 /* HistoryDelegate.h in Headers */,
+ E1B7816711AF31C3007E1BC2 /* MockGeolocationProvider.h in Headers */,
+ 29CFBA10122736E600BC30C0 /* AccessibilityTextMarker.h in Headers */,
+ 3A5626CC131CA036002BE6D9 /* StorageTrackerDelegate.h in Headers */,
+ 417DAA1D137B3E24007C57FB /* WebCoreTestSupport.h in Headers */,
+ 80045AED147718E7008290A8 /* AccessibilityNotificationHandler.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B5A7525B08AF4A4A00138E45 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXLegacyTarget section */
+ 5DC82A661023C8DE00FD1D3B /* DumpRenderTree Perl Support */ = {
+ isa = PBXLegacyTarget;
+ buildArgumentsString = "$(ACTION)";
+ buildConfigurationList = 5DC82A6E1023C92A00FD1D3B /* Build configuration list for PBXLegacyTarget "DumpRenderTree Perl Support" */;
+ buildPhases = (
+ );
+ buildToolPath = /usr/bin/make;
+ buildWorkingDirectory = "$(SRCROOT)/mac/PerlSupport";
+ dependencies = (
+ );
+ name = "DumpRenderTree Perl Support";
+ passBuildSettingsInEnvironment = 1;
+ productName = "DumpRenderTree Perl Support";
+ };
+/* End PBXLegacyTarget section */
+
+/* Begin PBXNativeTarget section */
+ 141BF21E096A441D00E0753C /* TestNetscapePlugIn */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 141BF221096A441E00E0753C /* Build configuration list for PBXNativeTarget "TestNetscapePlugIn" */;
+ buildPhases = (
+ 141BF21B096A441D00E0753C /* Resources */,
+ 141BF44E096A45DD00E0753C /* Headers */,
+ 141BF21C096A441D00E0753C /* Sources */,
+ 141BF21D096A441D00E0753C /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = TestNetscapePlugIn;
+ productName = TestNetscapePlugIn.plugin;
+ productReference = 141BF233096A44CF00E0753C /* TestNetscapePlugIn.plugin */;
+ productType = "com.apple.product-type.bundle";
+ };
+ 9340994A08540CAE007F3BC8 /* DumpRenderTree */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 149C29BF08902C6D008A9EFC /* Build configuration list for PBXNativeTarget "DumpRenderTree" */;
+ buildPhases = (
+ 9340994B08540CAE007F3BC8 /* Headers */,
+ 9340994D08540CAE007F3BC8 /* Sources */,
+ 9340994F08540CAE007F3BC8 /* Frameworks */,
+ 5DB9ACAA0F722C4400684641 /* Copy Font Files */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = DumpRenderTree;
+ productInstallPath = "$(HOME)/bin";
+ productName = DumpRenderTree;
+ productReference = 9340995408540CAF007F3BC8 /* DumpRenderTree */;
+ productType = "com.apple.product-type.tool";
+ };
+ B5A7525A08AF4A4A00138E45 /* ImageDiff */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B5A7526408AF4A4A00138E45 /* Build configuration list for PBXNativeTarget "ImageDiff" */;
+ buildPhases = (
+ B5A7525B08AF4A4A00138E45 /* Headers */,
+ B5A7525D08AF4A4A00138E45 /* Sources */,
+ B5A7525F08AF4A4A00138E45 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ImageDiff;
+ productInstallPath = "$(HOME)/bin";
+ productName = DumpRenderTree;
+ productReference = B5A7526708AF4A4A00138E45 /* ImageDiff */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 149C29C308902C6D008A9EFC /* Build configuration list for PBXProject "DumpRenderTree" */;
+ compatibilityVersion = "Xcode 2.4";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 08FB7794FE84155DC02AAC07 /* DumpRenderTree */;
+ productRefGroup = 9340995508540CAF007F3BC8 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ A84F608D08B1370600E9745F /* All */,
+ 9340994A08540CAE007F3BC8 /* DumpRenderTree */,
+ B5A7525A08AF4A4A00138E45 /* ImageDiff */,
+ 141BF21E096A441D00E0753C /* TestNetscapePlugIn */,
+ 5DC82A661023C8DE00FD1D3B /* DumpRenderTree Perl Support */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 141BF21B096A441D00E0753C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 141BF21C096A441D00E0753C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1AC6C8490D07638600CD3161 /* main.cpp in Sources */,
+ 1AC6C84A0D07638600CD3161 /* PluginObject.cpp in Sources */,
+ 1AC6C84B0D07638600CD3161 /* TestObject.cpp in Sources */,
+ 0F37A4A711E6628700275F54 /* PluginObjectMac.mm in Sources */,
+ 1A215A8111F2609C008AD0F5 /* PluginTest.cpp in Sources */,
+ 1A215BE711F27658008AD0F5 /* DocumentOpenInDestroyStream.cpp in Sources */,
+ 1AD9D2FE12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp in Sources */,
+ 1AC77DCF120605B6005C19EF /* NPRuntimeRemoveProperty.cpp in Sources */,
+ 1A24BAA9120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp in Sources */,
+ C06F9ABC1267A7060058E1F6 /* PassDifferentNPPStruct.cpp in Sources */,
+ C0EC3C9C12787F0500939164 /* NullNPPGetValuePointer.cpp in Sources */,
+ C0E720751281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp in Sources */,
+ 1AD4CB2212A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp in Sources */,
+ 1A3E28AA1311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp in Sources */,
+ 1ACF898D132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp in Sources */,
+ 1A31EB3813466AC100017372 /* ConvertPoint.cpp in Sources */,
+ C031182B134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp in Sources */,
+ 1A5CC1F5137DD2EC00A5D7E7 /* GetURLWithJavaScriptURL.cpp in Sources */,
+ 1AFF66BC137DEFD200791696 /* GetURLNotifyWithURLThatFailsToLoad.cpp in Sources */,
+ 4AD6A11413C8124000EA9737 /* FormValue.cpp in Sources */,
+ 1A14C8A51406DE0400B254F7 /* SupportsCarbonEventModel.cpp in Sources */,
+ 1A1E4298141141C400388758 /* PrivateBrowsing.cpp in Sources */,
+ 1A66C35114576A920099A115 /* ContentsScaleFactor.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 9340994D08540CAE007F3BC8 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BCD08B3A0E1057EF00A7D0C1 /* AccessibilityController.cpp in Sources */,
+ BCD08B710E1059D200A7D0C1 /* AccessibilityControllerMac.mm in Sources */,
+ BC0E24E10E2D9451001B6BC2 /* AccessibilityUIElement.cpp in Sources */,
+ BC0E26150E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm in Sources */,
+ BCA18B390C9B021900114369 /* AppleScriptController.m in Sources */,
+ A8B91BFD0CF522B4008F91FF /* CheckedMalloc.cpp in Sources */,
+ 53CBB832134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp in Sources */,
+ BCA18C470C9B5B9400114369 /* DumpRenderTree.mm in Sources */,
+ BCA18B7B0C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm in Sources */,
+ A8D79CEB0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m in Sources */,
+ A8B91ADA0CF3B32F008F91FF /* DumpRenderTreePasteboard.m in Sources */,
+ A8B91ADC0CF3B32F008F91FF /* DumpRenderTreeWindow.mm in Sources */,
+ BCA18B620C9B08C200114369 /* EditingDelegate.mm in Sources */,
+ BCA18B700C9B08DB00114369 /* EventSendingController.mm in Sources */,
+ BCA18B640C9B08C200114369 /* FrameLoadDelegate.mm in Sources */,
+ BCF6C6500C98E9C000AC063E /* GCController.cpp in Sources */,
+ BCA18B230C9B014B00114369 /* GCControllerMac.mm in Sources */,
+ BC4741410D038A570072B006 /* JavaScriptThreadingPthreads.cpp in Sources */,
+ BC0131DA0C9772010087317D /* LayoutTestController.cpp in Sources */,
+ BCA18B240C9B014B00114369 /* LayoutTestControllerMac.mm in Sources */,
+ BCA18B720C9B08DB00114369 /* NavigationController.m in Sources */,
+ BCA18B320C9B01B400114369 /* ObjCController.m in Sources */,
+ BCA18B7E0C9B08F100114369 /* ObjCPlugin.m in Sources */,
+ BCA18B800C9B08F100114369 /* ObjCPluginFunction.m in Sources */,
+ 8465E2C70FFA8DF2003B8342 /* PixelDumpSupport.cpp in Sources */,
+ BCB284CD0CFA83C8007E533E /* PixelDumpSupportCG.cpp in Sources */,
+ BCB284D60CFA83D1007E533E /* PixelDumpSupportMac.mm in Sources */,
+ 933BF5AC0F93FA5C000F0441 /* PlainTextController.mm in Sources */,
+ BCA18B660C9B08C200114369 /* PolicyDelegate.mm in Sources */,
+ BCA18B680C9B08C200114369 /* ResourceLoadDelegate.mm in Sources */,
+ BCA18B490C9B02C400114369 /* TextInputController.m in Sources */,
+ BCA18B6A0C9B08C200114369 /* UIDelegate.mm in Sources */,
+ 4437730E125CBC3600AAE02C /* WebArchiveDumpSupport.cpp in Sources */,
+ 440590711268453800CFD48D /* WebArchiveDumpSupportMac.mm in Sources */,
+ BC9D90240C97472E0099A4A3 /* WorkQueue.cpp in Sources */,
+ BCA18B260C9B015C00114369 /* WorkQueueItemMac.mm in Sources */,
+ 5185F6B210714E07007AA393 /* HistoryDelegate.mm in Sources */,
+ E1B7816511AF31B7007E1BC2 /* MockGeolocationProvider.mm in Sources */,
+ 29CFBA11122736E600BC30C0 /* AccessibilityTextMarker.cpp in Sources */,
+ 29CFBA2E12273A1000BC30C0 /* AccessibilityTextMarkerMac.mm in Sources */,
+ 3A5626CB131CA02A002BE6D9 /* StorageTrackerDelegate.mm in Sources */,
+ 80045AEE147718E7008290A8 /* AccessibilityNotificationHandler.mm in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B5A7525D08AF4A4A00138E45 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BCB284F60CFA84F8007E533E /* ImageDiffCG.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 141BF238096A451E00E0753C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 141BF21E096A441D00E0753C /* TestNetscapePlugIn */;
+ targetProxy = 141BF237096A451E00E0753C /* PBXContainerItemProxy */;
+ };
+ 5DC82A701023C93D00FD1D3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5DC82A661023C8DE00FD1D3B /* DumpRenderTree Perl Support */;
+ targetProxy = 5DC82A6F1023C93D00FD1D3B /* PBXContainerItemProxy */;
+ };
+ A84F608F08B1370E00E9745F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B5A7525A08AF4A4A00138E45 /* ImageDiff */;
+ targetProxy = A84F608E08B1370E00E9745F /* PBXContainerItemProxy */;
+ };
+ A84F609108B1370E00E9745F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 9340994A08540CAE007F3BC8 /* DumpRenderTree */;
+ targetProxy = A84F609008B1370E00E9745F /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 141BF222096A441E00E0753C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */;
+ buildSettings = {
+ INFOPLIST_FILE = TestNetscapePlugIn/mac/Info.plist;
+ };
+ name = Debug;
+ };
+ 141BF223096A441E00E0753C /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */;
+ buildSettings = {
+ INFOPLIST_FILE = TestNetscapePlugIn/mac/Info.plist;
+ };
+ name = Release;
+ };
+ 149C29C008902C6D008A9EFC /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ 149C29C108902C6D008A9EFC /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ 149C29C408902C6D008A9EFC /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */;
+ buildSettings = {
+ GCC_OPTIMIZATION_LEVEL = 0;
+ };
+ name = Debug;
+ };
+ 149C29C508902C6D008A9EFC /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ 5DC82A671023C8DE00FD1D3B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "DumpRenderTree Perl Support";
+ };
+ name = Debug;
+ };
+ 5DC82A681023C8DE00FD1D3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "DumpRenderTree Perl Support";
+ };
+ name = Release;
+ };
+ 5DC82A691023C8DE00FD1D3B /* Production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "DumpRenderTree Perl Support";
+ };
+ name = Production;
+ };
+ 90CBC3500F748B1300A712B7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB281EE0CFA713D007E533E /* Base.xcconfig */;
+ buildSettings = {
+ WEBKIT_FRAMEWORK_RESOURCES_PATH = WebKit.framework/Versions/A/Resources;
+ };
+ name = Production;
+ };
+ 90CBC3510F748B1300A712B7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)";
+ PRODUCT_NAME = All;
+ };
+ name = Production;
+ };
+ 90CBC3520F748B1300A712B7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */;
+ buildSettings = {
+ INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)";
+ SKIP_INSTALL = NO;
+ };
+ name = Production;
+ };
+ 90CBC3530F748B1300A712B7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */;
+ buildSettings = {
+ INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)";
+ SKIP_INSTALL = NO;
+ };
+ name = Production;
+ };
+ 90CBC3540F748B1300A712B7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */;
+ buildSettings = {
+ INFOPLIST_FILE = TestNetscapePlugIn/mac/Info.plist;
+ INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)";
+ SKIP_INSTALL = NO;
+ };
+ name = Production;
+ };
+ A84F609308B1371400E9745F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ OTHER_CFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = All;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ };
+ name = Debug;
+ };
+ A84F609408B1371400E9745F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ OTHER_CFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = All;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ };
+ name = Release;
+ };
+ B5A7526508AF4A4A00138E45 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ B5A7526608AF4A4A00138E45 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 141BF221096A441E00E0753C /* Build configuration list for PBXNativeTarget "TestNetscapePlugIn" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 141BF222096A441E00E0753C /* Debug */,
+ 141BF223096A441E00E0753C /* Release */,
+ 90CBC3540F748B1300A712B7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 149C29BF08902C6D008A9EFC /* Build configuration list for PBXNativeTarget "DumpRenderTree" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 149C29C008902C6D008A9EFC /* Debug */,
+ 149C29C108902C6D008A9EFC /* Release */,
+ 90CBC3520F748B1300A712B7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 149C29C308902C6D008A9EFC /* Build configuration list for PBXProject "DumpRenderTree" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 149C29C408902C6D008A9EFC /* Debug */,
+ 149C29C508902C6D008A9EFC /* Release */,
+ 90CBC3500F748B1300A712B7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 5DC82A6E1023C92A00FD1D3B /* Build configuration list for PBXLegacyTarget "DumpRenderTree Perl Support" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5DC82A671023C8DE00FD1D3B /* Debug */,
+ 5DC82A681023C8DE00FD1D3B /* Release */,
+ 5DC82A691023C8DE00FD1D3B /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ A84F609208B1371400E9745F /* Build configuration list for PBXAggregateTarget "All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ A84F609308B1371400E9745F /* Debug */,
+ A84F609408B1371400E9745F /* Release */,
+ 90CBC3510F748B1300A712B7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ B5A7526408AF4A4A00138E45 /* Build configuration list for PBXNativeTarget "ImageDiff" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B5A7526508AF4A4A00138E45 /* Debug */,
+ B5A7526608AF4A4A00138E45 /* Release */,
+ 90CBC3530F748B1300A712B7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h
new file mode 100644
index 000000000..e2f45d67c
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2009, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Cocoa/Cocoa.h>
+
+// An implementation of NSDraggingSource for use with DumpRenderTreeDraggingInfo when dragging files
+// Used by -[EventSendingController beginDragWithFiles:]
+
+@interface DumpRenderTreeFileDraggingSource : NSObject {
+}
+
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag;
+
+@end
diff --git a/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m
new file mode 100644
index 000000000..449d9185e
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m
@@ -0,0 +1,38 @@
+// Copyright (c) 2009, Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "DumpRenderTreeFileDraggingSource.h"
+
+@implementation DumpRenderTreeFileDraggingSource
+
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
+{
+ return NSDragOperationCopy;
+}
+
+@end
diff --git a/Tools/DumpRenderTree/DumpRenderTreePrefix.h b/Tools/DumpRenderTree/DumpRenderTreePrefix.h
new file mode 100644
index 000000000..1344754a6
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTreePrefix.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#ifdef __OBJC__
+
+#import <Foundation/Foundation.h>
+
+#endif
+
+// If we don't define these, they get defined in windef.h.
+// We want to use std::min and std::max
+#define max max
+#define min min
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h
new file mode 100755
index 000000000..4c5dcb983
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/runtime/JSExportMacros.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/JSExportMacros.h> \ No newline at end of file
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h
new file mode 100644
index 000000000..f2258d298
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/ASCIICType.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h
new file mode 100644
index 000000000..e83483e4d
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Alignment.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Assertions.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Assertions.h
new file mode 100644
index 000000000..214441049
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Assertions.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Assertions.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Atomics.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Atomics.h
new file mode 100644
index 000000000..37b18926f
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Atomics.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Atomics.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Compiler.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Compiler.h
new file mode 100644
index 000000000..340d8c989
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Compiler.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Compiler.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h
new file mode 100644
index 000000000..a31a23d25
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/CurrentTime.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h
new file mode 100644
index 000000000..1280da80d
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/DynamicAnnotations.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/ExportMacros.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ExportMacros.h
new file mode 100755
index 000000000..50be070ba
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ExportMacros.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/ExportMacros.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h
new file mode 100644
index 000000000..421c04026
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/FastAllocBase.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h
new file mode 100644
index 000000000..1701231ee
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/FastMalloc.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashMap.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashMap.h
new file mode 100644
index 000000000..9f262e2ea
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashMap.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/HashMap.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashSet.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashSet.h
new file mode 100644
index 000000000..cfe2d80f8
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashSet.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/HashSet.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashTraits.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashTraits.h
new file mode 100644
index 000000000..412fa9856
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/HashTraits.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/HashTraits.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Locker.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Locker.h
new file mode 100644
index 000000000..75b0acd59
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Locker.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Locker.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/MainThread.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/MainThread.h
new file mode 100644
index 000000000..ff75971f8
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/MainThread.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/MainThread.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/MathExtras.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/MathExtras.h
new file mode 100644
index 000000000..29557867a
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/MathExtras.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/MathExtras.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Noncopyable.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Noncopyable.h
new file mode 100644
index 000000000..f8484d288
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Noncopyable.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Noncopyable.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnArrayPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnArrayPtr.h
new file mode 100644
index 000000000..595817ddb
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnArrayPtr.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/OwnArrayPtr.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h
new file mode 100644
index 000000000..9211d3859
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/OwnPtr.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtrCommon.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtrCommon.h
new file mode 100644
index 000000000..6064e88dc
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtrCommon.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/PassOwnPtr.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassOwnPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassOwnPtr.h
new file mode 100644
index 000000000..6064e88dc
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassOwnPtr.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/PassOwnPtr.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h
new file mode 100644
index 000000000..aafd1a236
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/PassRefPtr.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Platform.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Platform.h
new file mode 100644
index 000000000..3b229552a
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Platform.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Platform.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefCounted.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefCounted.h
new file mode 100644
index 000000000..628a63b6e
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefCounted.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/RefCounted.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h
new file mode 100644
index 000000000..0ff621398
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/RefPtr.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/RetainPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RetainPtr.h
new file mode 100644
index 000000000..65fc27bc9
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RetainPtr.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/RetainPtr.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/StdLibExtras.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StdLibExtras.h
new file mode 100644
index 000000000..3222ec1f1
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StdLibExtras.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/StdLibExtras.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h
new file mode 100644
index 000000000..063d500ec
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/StringExtras.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/TemporaryChange.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/TemporaryChange.h
new file mode 100644
index 000000000..3367eb2d2
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/TemporaryChange.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/TemporaryChange.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeRefCounted.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeRefCounted.h
new file mode 100644
index 000000000..48a54cc77
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeRefCounted.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/ThreadSafeRefCounted.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Threading.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Threading.h
new file mode 100644
index 000000000..17359e5d2
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Threading.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Threading.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadingPrimitives.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadingPrimitives.h
new file mode 100644
index 000000000..a7ee1170f
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadingPrimitives.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/ThreadingPrimitives.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Vector.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Vector.h
new file mode 100644
index 000000000..c6d15fd05
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Vector.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Vector.h>
diff --git a/Tools/DumpRenderTree/GCController.cpp b/Tools/DumpRenderTree/GCController.cpp
new file mode 100644
index 000000000..06a04fbca
--- /dev/null
+++ b/Tools/DumpRenderTree/GCController.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h"
+
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+
+GCController::GCController()
+{
+}
+
+GCController::~GCController()
+{
+}
+
+// Static Functions
+
+static JSValueRef collectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ GCController* controller = static_cast<GCController*>(JSObjectGetPrivate(thisObject));
+ controller->collect();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef collectOnAlternateThreadCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ bool waitUntilDone = false;
+ if (argumentCount > 0)
+ waitUntilDone = JSValueToBoolean(context, arguments[0]);
+
+ GCController* controller = static_cast<GCController*>(JSObjectGetPrivate(thisObject));
+ controller->collectOnAlternateThread(waitUntilDone);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef getJSObjectCountCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ GCController* controller = static_cast<GCController*>(JSObjectGetPrivate(thisObject));
+ size_t jsObjectCount = controller->getJSObjectCount();
+
+ return JSValueMakeNumber(context, jsObjectCount);
+}
+
+// Object Creation
+
+void GCController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> gcControllerStr(Adopt, JSStringCreateWithUTF8CString("GCController"));
+
+ JSClassRef classRef = getJSClass();
+ JSValueRef gcControllerObject = JSObjectMake(context, classRef, this);
+ JSClassRelease(classRef);
+
+ JSObjectSetProperty(context, windowObject, gcControllerStr.get(), gcControllerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
+}
+
+JSClassRef GCController::getJSClass()
+{
+ static JSStaticFunction staticFunctions[] = {
+ { "collect", collectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "collectOnAlternateThread", collectOnAlternateThreadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "getJSObjectCount", getJSObjectCountCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+ };
+
+ static JSClassDefinition classDefinition = {
+ 0, kJSClassAttributeNone, "GCController", 0, 0, staticFunctions,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ return JSClassCreate(&classDefinition);
+}
diff --git a/Tools/DumpRenderTree/GCController.h b/Tools/DumpRenderTree/GCController.h
new file mode 100644
index 000000000..afc1de087
--- /dev/null
+++ b/Tools/DumpRenderTree/GCController.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 GCController_h
+#define GCController_h
+
+#include <JavaScriptCore/JSObjectRef.h>
+
+class GCController {
+public:
+ GCController();
+ ~GCController();
+
+ void makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception);
+
+ // Controller Methods - platfrom independant implementations
+ void collect() const;
+ void collectOnAlternateThread(bool waitUntilDone) const;
+ size_t getJSObjectCount() const;
+
+private:
+ static JSClassRef getJSClass();
+};
+
+#endif // GCController_h
diff --git a/Tools/DumpRenderTree/JavaScriptThreading.h b/Tools/DumpRenderTree/JavaScriptThreading.h
new file mode 100644
index 000000000..43795a1a2
--- /dev/null
+++ b/Tools/DumpRenderTree/JavaScriptThreading.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 JavaScriptThreading_h
+#define JavaScriptThreading_h
+
+/* These functions start/stop threads used to abuse the JavaScript interpreter
+ and assure that our JS implementation remains threadsafe */
+
+void startJavaScriptThreads();
+void stopJavaScriptThreads();
+
+#endif // JavaScriptThreading_h
diff --git a/Tools/DumpRenderTree/LayoutTestController.cpp b/Tools/DumpRenderTree/LayoutTestController.cpp
new file mode 100644
index 000000000..6c13d9309
--- /dev/null
+++ b/Tools/DumpRenderTree/LayoutTestController.cpp
@@ -0,0 +1,2607 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Joone Hur <joone@kldp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "LayoutTestController.h"
+
+#include "WorkQueue.h"
+#include "WorkQueueItem.h"
+#include <cstring>
+#include <JavaScriptCore/JSContextRef.h>
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <locale.h>
+#include <stdio.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/RefPtr.h>
+
+LayoutTestController::LayoutTestController(const std::string& testPathOrURL, const std::string& expectedPixelHash)
+ : m_disallowIncreaseForApplicationCacheQuota(false)
+ , m_dumpApplicationCacheDelegateCallbacks(false)
+ , m_dumpAsAudio(false)
+ , m_dumpAsPDF(false)
+ , m_dumpAsText(false)
+ , m_dumpBackForwardList(false)
+ , m_dumpChildFrameScrollPositions(false)
+ , m_dumpChildFramesAsText(false)
+ , m_dumpDOMAsWebArchive(false)
+ , m_dumpDatabaseCallbacks(false)
+ , m_dumpEditingCallbacks(false)
+ , m_dumpFrameLoadCallbacks(false)
+ , m_dumpProgressFinishedCallback(false)
+ , m_dumpUserGestureInFrameLoadCallbacks(false)
+ , m_dumpHistoryDelegateCallbacks(false)
+ , m_dumpResourceLoadCallbacks(false)
+ , m_dumpResourceResponseMIMETypes(false)
+ , m_dumpSelectionRect(false)
+ , m_dumpSourceAsWebArchive(false)
+ , m_dumpStatusCallbacks(false)
+ , m_dumpTitleChanges(false)
+ , m_dumpIconChanges(false)
+ , m_dumpVisitedLinksCallback(false)
+ , m_dumpWillCacheResponse(false)
+ , m_generatePixelResults(true)
+ , m_callCloseOnWebViews(true)
+ , m_canOpenWindows(false)
+ , m_closeRemainingWindowsWhenComplete(true)
+ , m_newWindowsCopyBackForwardList(false)
+ , m_stopProvisionalFrameLoads(false)
+ , m_testOnscreen(false)
+ , m_testRepaint(false)
+ , m_testRepaintSweepHorizontally(false)
+ , m_waitToDump(false)
+ , m_willSendRequestReturnsNull(false)
+ , m_willSendRequestReturnsNullOnRedirect(false)
+ , m_windowIsKey(true)
+ , m_alwaysAcceptCookies(false)
+ , m_globalFlag(false)
+ , m_isGeolocationPermissionSet(false)
+ , m_geolocationPermission(false)
+ , m_handlesAuthenticationChallenges(false)
+ , m_isPrinting(false)
+ , m_deferMainResourceDataLoad(true)
+ , m_shouldPaintBrokenImage(true)
+ , m_shouldStayOnPageAfterHandlingBeforeUnload(false)
+ , m_areDesktopNotificationPermissionRequestsIgnored(false)
+ , m_testPathOrURL(testPathOrURL)
+ , m_expectedPixelHash(expectedPixelHash)
+{
+}
+
+PassRefPtr<LayoutTestController> LayoutTestController::create(const std::string& testPathOrURL, const std::string& expectedPixelHash)
+{
+ return adoptRef(new LayoutTestController(testPathOrURL, expectedPixelHash));
+}
+
+// Static Functions
+
+static JSValueRef disallowIncreaseForApplicationCacheQuotaCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDisallowIncreaseForApplicationCacheQuota(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpApplicationCacheDelegateCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpApplicationCacheDelegateCallbacks(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpAsPDFCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpAsPDF(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpAsTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpAsText(true);
+
+ // Optional paramater, describing whether it's allowed to dump pixel results in dumpAsText mode.
+ controller->setGeneratePixelResults(argumentCount > 0 ? JSValueToBoolean(context, arguments[0]) : false);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpBackForwardListCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpBackForwardList(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpChildFramesAsTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpChildFramesAsText(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpChildFrameScrollPositionsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpChildFrameScrollPositions(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpConfigurationForViewportCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+
+ double deviceDPI = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+ double deviceWidth = JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!*exception);
+ double deviceHeight = JSValueToNumber(context, arguments[2], exception);
+ ASSERT(!*exception);
+ double availableWidth = JSValueToNumber(context, arguments[3], exception);
+ ASSERT(!*exception);
+ double availableHeight = JSValueToNumber(context, arguments[4], exception);
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->dumpConfigurationForViewport(static_cast<int>(deviceDPI), static_cast<int>(deviceWidth), static_cast<int>(deviceHeight), static_cast<int>(availableWidth), static_cast<int>(availableHeight));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpDatabaseCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpDatabaseCallbacks(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpDOMAsWebArchiveCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpDOMAsWebArchive(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpEditingCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpEditingCallbacks(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpFrameLoadCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpFrameLoadCallbacks(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpProgressFinishedCallbackCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpProgressFinishedCallback(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpUserGestureInFrameLoadCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpUserGestureInFrameLoadCallbacks(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpResourceLoadCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpResourceLoadCallbacks(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpResourceResponseMIMETypesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpResourceResponseMIMETypes(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpSelectionRectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpSelectionRect(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpSourceAsWebArchiveCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpSourceAsWebArchive(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpStatusCallbacksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpStatusCallbacks(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpTitleChangesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpTitleChanges(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpIconChangesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpIconChanges(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dumpWillCacheResponseCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpWillCacheResponse(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef pathToLocalResourceCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ JSRetainPtr<JSStringRef> localPath(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ JSRetainPtr<JSStringRef> convertedPath(Adopt, controller->pathToLocalResource(context, localPath.get()));
+ if (!convertedPath)
+ return JSValueMakeUndefined(context);
+
+ return JSValueMakeString(context, convertedPath.get());
+}
+
+static JSValueRef removeAllVisitedLinksCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDumpVisitedLinksCallback(true);
+ controller->removeAllVisitedLinks();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef repaintSweepHorizontallyCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setTestRepaintSweepHorizontally(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setCallCloseOnWebViewsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setCallCloseOnWebViews(JSValueToBoolean(context, arguments[0]));
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setCanOpenWindowsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setCanOpenWindows(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setCloseRemainingWindowsWhenCompleteCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setCloseRemainingWindowsWhenComplete(JSValueToBoolean(context, arguments[0]));
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setEncodedAudioDataCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> encodedAudioData(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(encodedAudioData.get());
+ OwnArrayPtr<char> encodedAudioDataBuffer = adoptArrayPtr(new char[maxLength + 1]);
+ JSStringGetUTF8CString(encodedAudioData.get(), encodedAudioDataBuffer.get(), maxLength + 1);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setEncodedAudioData(encodedAudioDataBuffer.get());
+ controller->setDumpAsAudio(true);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef testOnscreenCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setTestOnscreen(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef testRepaintCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setTestRepaint(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef addDisallowedURLCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->addDisallowedURL(url.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef addURLToRedirectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> origin(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ JSRetainPtr<JSStringRef> destination(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(origin.get());
+ OwnArrayPtr<char> originBuffer = adoptArrayPtr(new char[maxLength + 1]);
+ JSStringGetUTF8CString(origin.get(), originBuffer.get(), maxLength + 1);
+
+ maxLength = JSStringGetMaximumUTF8CStringSize(destination.get());
+ OwnArrayPtr<char> destinationBuffer = adoptArrayPtr(new char[maxLength + 1]);
+ JSStringGetUTF8CString(destination.get(), destinationBuffer.get(), maxLength + 1);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->addURLToRedirect(originBuffer.get(), destinationBuffer.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef callShouldCloseOnWebViewCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ return JSValueMakeBoolean(context, controller->callShouldCloseOnWebView());
+}
+
+static JSValueRef clearAllApplicationCachesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->clearAllApplicationCaches();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef clearApplicationCacheForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> originURL(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->clearApplicationCacheForOrigin(originURL.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef applicationCacheDiskUsageForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> originURL(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ return JSValueMakeNumber(context, controller->applicationCacheDiskUsageForOrigin(originURL.get()));
+}
+
+static JSValueRef originsWithApplicationCacheCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return controller->originsWithApplicationCache(context);
+}
+
+static JSValueRef clearAllDatabasesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->clearAllDatabases();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef syncLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ controller->syncLocalStorage();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef observeStorageTrackerNotificationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ unsigned numNotifications = JSValueToNumber(context, arguments[0], exception);
+
+ ASSERT(!*exception);
+
+ controller->observeStorageTrackerNotifications(numNotifications);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef deleteAllLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->deleteAllLocalStorage();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef deleteLocalStorageForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ controller->deleteLocalStorageForOrigin(url.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef localStorageDiskUsageForOriginCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> originURL(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ return JSValueMakeNumber(context, controller->localStorageDiskUsageForOrigin(originURL.get()));
+}
+
+static JSValueRef originsWithLocalStorageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return controller->originsWithLocalStorage(context);
+}
+
+static JSValueRef clearBackForwardListCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->clearBackForwardList();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef clearPersistentUserStyleSheetCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->clearPersistentUserStyleSheet();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef decodeHostNameCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> name(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ JSRetainPtr<JSStringRef> decodedHostName(Adopt, controller->copyDecodedHostName(name.get()));
+ return JSValueMakeString(context, decodedHostName.get());
+}
+
+static JSValueRef disableImageLoadingCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation, needs windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->disableImageLoading();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef dispatchPendingLoadRequestsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation, needs windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->dispatchPendingLoadRequests();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef displayCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->display();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef displayInvalidatedRegionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ // LayoutTestController::display() only renders the invalidated region so
+ // we can just use that.
+ controller->display();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef encodeHostNameCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> name(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ JSRetainPtr<JSStringRef> encodedHostName(Adopt, controller->copyEncodedHostName(name.get()));
+ return JSValueMakeString(context, encodedHostName.get());
+}
+
+static JSValueRef execCommandCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac & Windows implementations.
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> name(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ // Ignoring the second parameter (userInterface), as this command emulates a manual action.
+
+ JSRetainPtr<JSStringRef> value;
+ if (argumentCount >= 3) {
+ value.adopt(JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+ } else
+ value.adopt(JSStringCreateWithUTF8CString(""));
+
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->execCommand(name.get(), value.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef findStringCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac implementation.
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> target(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ JSObjectRef options = JSValueToObject(context, arguments[1], exception);
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeBoolean(context, controller->findString(context, target.get(), options));
+}
+
+static JSValueRef counterValueForElementByIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ if (*exception)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ JSRetainPtr<JSStringRef> counterValue(controller->counterValueForElementById(elementId.get()));
+ if (!counterValue.get())
+ return JSValueMakeUndefined(context);
+ return JSValueMakeString(context, counterValue.get());
+}
+
+static JSValueRef goBackCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->goBack();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef grantDesktopNotificationPermissionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ controller->grantDesktopNotificationPermission(JSValueToStringCopy(context, arguments[0], NULL));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef isCommandEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac implementation.
+
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> name(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ return JSValueMakeBoolean(context, controller->isCommandEnabled(name.get()));
+}
+
+static JSValueRef overridePreferenceCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> key(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> value(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->overridePreference(key.get(), value.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef keepWebHistoryCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->keepWebHistory();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef computedStyleIncludingVisitedInfoCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 1)
+ return JSValueMakeUndefined(context);
+
+ // Has mac implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return controller->computedStyleIncludingVisitedInfo(context, arguments[0]);
+}
+
+static JSValueRef nodesFromRectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 8)
+ return JSValueMakeUndefined(context);
+
+ int x = JSValueToNumber(context, arguments[1], NULL);
+ int y = JSValueToNumber(context, arguments[2], NULL);
+ int top = static_cast<unsigned>(JSValueToNumber(context, arguments[3], NULL));
+ int right = static_cast<unsigned>(JSValueToNumber(context, arguments[4], NULL));
+ int bottom = static_cast<unsigned>(JSValueToNumber(context, arguments[5], NULL));
+ int left = static_cast<unsigned>(JSValueToNumber(context, arguments[6], NULL));
+ bool ignoreClipping = JSValueToBoolean(context, arguments[7]);
+
+ // Has mac implementation.
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return controller->nodesFromRect(context, arguments[0], x, y, top, right, bottom, left, ignoreClipping);
+}
+
+static JSValueRef layerTreeAsTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeString(context, controller->layerTreeAsText().get());
+}
+
+static JSValueRef notifyDoneCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ // May be able to be made platform independant by using shared WorkQueue
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->notifyDone();
+ return JSValueMakeUndefined(context);
+}
+
+static bool parsePageParameters(JSContextRef context, int argumentCount, const JSValueRef* arguments, JSValueRef* exception, float& pageWidthInPixels, float& pageHeightInPixels)
+{
+ pageWidthInPixels = LayoutTestController::maxViewWidth;
+ pageHeightInPixels = LayoutTestController::maxViewHeight;
+ switch (argumentCount) {
+ case 2:
+ pageWidthInPixels = static_cast<float>(JSValueToNumber(context, arguments[0], exception));
+ if (*exception)
+ return false;
+ pageHeightInPixels = static_cast<float>(JSValueToNumber(context, arguments[1], exception));
+ if (*exception)
+ return false;
+ case 0: // Fall through.
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+// Caller needs to delete[] propertyName.
+static bool parsePagePropertyParameters(JSContextRef context, int argumentCount, const JSValueRef* arguments, JSValueRef* exception, char*& propertyName, int& pageNumber)
+{
+ pageNumber = 0;
+ switch (argumentCount) {
+ case 2:
+ pageNumber = static_cast<float>(JSValueToNumber(context, arguments[1], exception));
+ if (*exception)
+ return false;
+ // Fall through.
+ case 1: {
+ JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ if (*exception)
+ return false;
+
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(propertyNameString.get());
+ propertyName = new char[maxLength + 1];
+ JSStringGetUTF8CString(propertyNameString.get(), propertyName, maxLength + 1);
+ return true;
+ }
+ case 0:
+ default:
+ return false;
+ }
+}
+
+static bool parsePageNumber(JSContextRef context, int argumentCount, const JSValueRef* arguments, JSValueRef* exception, int& pageNumber)
+{
+ pageNumber = 0;
+ switch (argumentCount) {
+ case 1:
+ pageNumber = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+ if (*exception)
+ return false;
+ // Fall through.
+ case 0:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool parsePageNumberSizeMarings(JSContextRef context, int argumentCount, const JSValueRef* arguments, JSValueRef* exception, int& pageNumber, int& width, int& height, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft)
+{
+ pageNumber = 0;
+ width = height = 0;
+ marginTop = marginRight = marginBottom = marginLeft = 0;
+
+ switch (argumentCount) {
+ case 7:
+ marginLeft = static_cast<int>(JSValueToNumber(context, arguments[6], exception));
+ if (*exception)
+ return false;
+ // Fall through.
+ case 6:
+ marginBottom = static_cast<int>(JSValueToNumber(context, arguments[5], exception));
+ if (*exception)
+ return false;
+ // Fall through.
+ case 5:
+ marginRight = static_cast<int>(JSValueToNumber(context, arguments[4], exception));
+ if (*exception)
+ return false;
+ // Fall through.
+ case 4:
+ marginTop = static_cast<int>(JSValueToNumber(context, arguments[3], exception));
+ if (*exception)
+ return false;
+ // Fall through.
+ case 3:
+ height = static_cast<int>(JSValueToNumber(context, arguments[2], exception));
+ if (*exception)
+ return false;
+ // Fall through.
+ case 2:
+ width = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
+ if (*exception)
+ return false;
+ // Fall through.
+ case 1:
+ pageNumber = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+ if (*exception)
+ return false;
+ // Fall through.
+ return true;
+ default:
+ return false;
+ }
+}
+
+static JSValueRef pageNumberForElementByIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ float pageWidthInPixels = 0;
+ float pageHeightInPixels = 0;
+ if (!parsePageParameters(context, argumentCount - 1, arguments + 1, exception, pageWidthInPixels, pageHeightInPixels))
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ if (*exception)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ int pageNumber = controller->pageNumberForElementById(elementId.get(), pageWidthInPixels, pageHeightInPixels);
+ return JSValueMakeNumber(context, pageNumber);
+}
+
+static JSValueRef numberOfPagesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ float pageWidthInPixels = 0;
+ float pageHeightInPixels = 0;
+ if (!parsePageParameters(context, argumentCount, arguments, exception, pageWidthInPixels, pageHeightInPixels))
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeNumber(context, controller->numberOfPages(pageWidthInPixels, pageHeightInPixels));
+}
+
+static JSValueRef numberOfPendingGeolocationPermissionRequestsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeNumber(context, controller->numberOfPendingGeolocationPermissionRequests());
+}
+
+static JSValueRef pagePropertyCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ char* propertyName = 0;
+ int pageNumber = 0;
+ if (!parsePagePropertyParameters(context, argumentCount, arguments, exception, propertyName, pageNumber))
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ JSValueRef value = JSValueMakeString(context, controller->pageProperty(propertyName, pageNumber).get());
+
+ delete[] propertyName;
+ return value;
+}
+
+static JSValueRef isPageBoxVisibleCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int pageNumber = 0;
+ if (!parsePageNumber(context, argumentCount, arguments, exception, pageNumber))
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeBoolean(context, controller->isPageBoxVisible(pageNumber));
+}
+
+static JSValueRef pageSizeAndMarginsInPixelsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int pageNumber = 0;
+ int width = 0, height = 0;
+ int marginTop = 0, marginRight = 0, marginBottom = 0, marginLeft = 0;
+ if (!parsePageNumberSizeMarings(context, argumentCount, arguments, exception, pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft))
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeString(context, controller->pageSizeAndMarginsInPixels(pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft).get());
+}
+
+static JSValueRef queueBackNavigationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ // May be able to be made platform independant by using shared WorkQueue
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ double howFarBackDouble = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->queueBackNavigation(static_cast<int>(howFarBackDouble));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef queueForwardNavigationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ // May be able to be made platform independant by using shared WorkQueue
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ double howFarForwardDouble = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->queueForwardNavigation(static_cast<int>(howFarForwardDouble));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef queueLoadCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ // May be able to be made platform independant by using shared WorkQueue
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ JSRetainPtr<JSStringRef> target;
+ if (argumentCount >= 2) {
+ target.adopt(JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+ } else
+ target.adopt(JSStringCreateWithUTF8CString(""));
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->queueLoad(url.get(), target.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef queueLoadHTMLStringCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac & Windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> content(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ JSRetainPtr<JSStringRef> baseURL;
+ if (argumentCount >= 2) {
+ baseURL.adopt(JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+ } else
+ baseURL.adopt(JSStringCreateWithUTF8CString(""));
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ if (argumentCount >= 3) {
+ JSRetainPtr<JSStringRef> unreachableURL;
+ unreachableURL.adopt(JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+ controller->queueLoadAlternateHTMLString(content.get(), baseURL.get(), unreachableURL.get());
+ return JSValueMakeUndefined(context);
+ }
+
+ controller->queueLoadHTMLString(content.get(), baseURL.get());
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef queueReloadCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ // May be able to be made platform independant by using shared WorkQueue
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->queueReload();
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef queueLoadingScriptCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ // May be able to be made platform independant by using shared WorkQueue
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->queueLoadingScript(script.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef queueNonLoadingScriptCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ // May be able to be made platform independant by using shared WorkQueue
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->queueNonLoadingScript(script.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAcceptsEditingCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAcceptsEditing(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAlwaysAcceptCookiesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAlwaysAcceptCookies(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAppCacheMaximumSizeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ double size = JSValueToNumber(context, arguments[0], NULL);
+ if (!isnan(size))
+ controller->setAppCacheMaximumSize(static_cast<unsigned long long>(size));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setApplicationCacheOriginQuotaCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ double size = JSValueToNumber(context, arguments[0], NULL);
+ if (!isnan(size))
+ controller->setApplicationCacheOriginQuota(static_cast<unsigned long long>(size));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAuthenticationPasswordCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> password(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(password.get());
+ char* passwordBuffer = new char[maxLength + 1];
+ JSStringGetUTF8CString(password.get(), passwordBuffer, maxLength + 1);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAuthenticationPassword(passwordBuffer);
+ delete[] passwordBuffer;
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAuthenticationUsernameCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> username(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(username.get());
+ char* usernameBuffer = new char[maxLength + 1];
+ JSStringGetUTF8CString(username.get(), usernameBuffer, maxLength + 1);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAuthenticationUsername(usernameBuffer);
+ delete[] usernameBuffer;
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAuthorAndUserStylesEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAuthorAndUserStylesEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAutofilledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 2 || !arguments[0])
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAutofilled(context, arguments[0], JSValueToBoolean(context, arguments[1]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setCacheModelCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac implementation.
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ int cacheModel = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setCacheModel(cacheModel);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setCustomPolicyDelegateCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ bool permissive = false;
+ if (argumentCount >= 2)
+ permissive = JSValueToBoolean(context, arguments[1]);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setCustomPolicyDelegate(JSValueToBoolean(context, arguments[0]), permissive);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setDatabaseQuotaCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ double quota = JSValueToNumber(context, arguments[0], NULL);
+ if (!isnan(quota))
+ controller->setDatabaseQuota(static_cast<unsigned long long>(quota));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setDeferMainResourceDataLoadCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac and Windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDeferMainResourceDataLoad(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setDefersLoadingCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setDefersLoading(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setDomainRelaxationForbiddenForURLSchemeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac and Windows implementation
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ bool forbidden = JSValueToBoolean(context, arguments[0]);
+ JSRetainPtr<JSStringRef> scheme(Adopt, JSValueToStringCopy(context, arguments[1], 0));
+ controller->setDomainRelaxationForbiddenForURLScheme(forbidden, scheme.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setMockDeviceOrientationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 6)
+ return JSValueMakeUndefined(context);
+
+ bool canProvideAlpha = JSValueToBoolean(context, arguments[0]);
+ double alpha = JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!*exception);
+ bool canProvideBeta = JSValueToBoolean(context, arguments[2]);
+ double beta = JSValueToNumber(context, arguments[3], exception);
+ ASSERT(!*exception);
+ bool canProvideGamma = JSValueToBoolean(context, arguments[4]);
+ double gamma = JSValueToNumber(context, arguments[5], exception);
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = reinterpret_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setMockGeolocationPositionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 3)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = reinterpret_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setMockGeolocationPosition(JSValueToNumber(context, arguments[0], NULL), // latitude
+ JSValueToNumber(context, arguments[1], NULL), // longitude
+ JSValueToNumber(context, arguments[2], NULL)); // accuracy
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setMockGeolocationErrorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ int code = JSValueToNumber(context, arguments[0], NULL);
+ JSRetainPtr<JSStringRef> message(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = reinterpret_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setMockGeolocationError(code, message.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef addMockSpeechInputResultCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 3)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> result(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ double confidence = JSValueToNumber(context, arguments[1], exception);
+
+ JSRetainPtr<JSStringRef> language(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->addMockSpeechInputResult(result.get(), confidence, language.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setNewWindowsCopyBackForwardListCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setNewWindowsCopyBackForwardList(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setGeolocationPermissionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setGeolocationPermission(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setHandlesAuthenticationChallengesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setHandlesAuthenticationChallenges(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setPOSIXLocaleCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ JSRetainPtr<JSStringRef> locale(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ controller->setPOSIXLocale(locale.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setIconDatabaseEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setIconDatabaseEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setJavaScriptProfilingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setJavaScriptProfilingEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setMainFrameIsFirstResponderCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setMainFrameIsFirstResponder(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setPersistentUserStyleSheetLocationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> path(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setPersistentUserStyleSheetLocation(path.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setPrivateBrowsingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setPrivateBrowsingEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setJavaScriptCanAccessClipboardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setJavaScriptCanAccessClipboard(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setXSSAuditorEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setXSSAuditorEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setSpatialNavigationEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation.
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setSpatialNavigationEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setPrintingCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setIsPrinting(true);
+ return JSValueMakeUndefined(context);
+}
+
+
+static JSValueRef setFrameFlatteningEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setFrameFlatteningEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAllowUniversalAccessFromFileURLsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAllowUniversalAccessFromFileURLs(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAllowFileAccessFromFileURLsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAllowFileAccessFromFileURLs(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setTabKeyCyclesThroughElementsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setTabKeyCyclesThroughElements(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setUseDashboardCompatibilityModeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setUseDashboardCompatibilityMode(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setUserStyleSheetEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setUserStyleSheetEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setUserStyleSheetLocationCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> path(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setUserStyleSheetLocation(path.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setValueForUserCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount != 2)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> value(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setValueForUser(context, arguments[0], value.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setViewModeMediaFeatureCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> mode(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setViewModeMediaFeature(mode.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setWillSendRequestClearHeaderCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> header(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(header.get());
+ OwnArrayPtr<char> headerBuffer = adoptArrayPtr(new char[maxLength + 1]);
+ JSStringGetUTF8CString(header.get(), headerBuffer.get(), maxLength + 1);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setWillSendRequestClearHeader(headerBuffer.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setWillSendRequestReturnsNullCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has cross-platform implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setWillSendRequestReturnsNull(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setWillSendRequestReturnsNullOnRedirectCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has cross-platform implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setWillSendRequestReturnsNullOnRedirect(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setWindowIsKeyCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setWindowIsKey(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef waitUntilDoneCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setWaitToDump(true);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef windowCountCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ int windows = controller->windowCount();
+ return JSValueMakeNumber(context, windows);
+}
+
+static JSValueRef setPopupBlockingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setPopupBlockingEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setPluginsEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setPluginsEnabled(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setPageVisibilityCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> visibility(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(visibility.get());
+ char* visibilityBuffer = new char[maxLength + 1];
+ JSStringGetUTF8CString(visibility.get(), visibilityBuffer, maxLength + 1);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setPageVisibility(visibilityBuffer);
+ delete[] visibilityBuffer;
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef resetPageVisibilityCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->resetPageVisibility();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setSmartInsertDeleteEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setSmartInsertDeleteEnabled(JSValueToBoolean(context, arguments[0]));
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setSelectTrailingWhitespaceEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setSelectTrailingWhitespaceEnabled(JSValueToBoolean(context, arguments[0]));
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setStopProvisionalFrameLoadsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setStopProvisionalFrameLoads(true);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setAsynchronousSpellCheckingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAsynchronousSpellCheckingEnabled(JSValueToBoolean(context, arguments[0]));
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef showWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->showWebInspector();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef closeWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->closeWebInspector();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef evaluateInWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ double callId = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+
+ controller->evaluateInWebInspector(static_cast<long>(callId), script.get());
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef evaluateScriptInIsolatedWorldCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ double worldID = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+
+ controller->evaluateScriptInIsolatedWorld(static_cast<unsigned>(worldID), JSContextGetGlobalObject(context), script.get());
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef elementDoesAutoCompleteForElementWithIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ bool autoCompletes = controller->elementDoesAutoCompleteForElementWithId(elementId.get());
+
+ return JSValueMakeBoolean(context, autoCompletes);
+}
+
+static JSValueRef pauseAnimationAtTimeOnElementWithIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 3)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> animationName(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ double time = JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeBoolean(context, controller->pauseAnimationAtTimeOnElementWithId(animationName.get(), time, elementId.get()));
+}
+
+static JSValueRef pauseTransitionAtTimeOnElementWithIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 3)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> propertyName(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ double time = JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeBoolean(context, controller->pauseTransitionAtTimeOnElementWithId(propertyName.get(), time, elementId.get()));
+}
+
+static JSValueRef sampleSVGAnimationForElementAtTimeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 3)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> animationId(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ double time = JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeBoolean(context, controller->sampleSVGAnimationForElementAtTime(animationId.get(), time, elementId.get()));
+}
+
+static JSValueRef numberOfActiveAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 0)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeNumber(context, controller->numberOfActiveAnimations());
+}
+
+static JSValueRef suspendAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->suspendAnimations();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef resumeAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->resumeAnimations();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef waitForPolicyDelegateCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->waitForPolicyDelegate();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef addOriginAccessWhitelistEntryCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 4)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> sourceOrigin(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> destinationProtocol(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> destinationHost(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+ bool allowDestinationSubdomains = JSValueToBoolean(context, arguments[3]);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->addOriginAccessWhitelistEntry(sourceOrigin.get(), destinationProtocol.get(), destinationHost.get(), allowDestinationSubdomains);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef removeOriginAccessWhitelistEntryCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 4)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> sourceOrigin(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> destinationProtocol(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> destinationHost(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+ bool allowDestinationSubdomains = JSValueToBoolean(context, arguments[3]);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->removeOriginAccessWhitelistEntry(sourceOrigin.get(), destinationProtocol.get(), destinationHost.get(), allowDestinationSubdomains);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setScrollbarPolicyCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 2)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> orientation(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> policy(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setScrollbarPolicy(orientation.get(), policy.get());
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef addUserScriptCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 3)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> source(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ bool runAtStart = JSValueToBoolean(context, arguments[1]);
+ bool allFrames = JSValueToBoolean(context, arguments[2]);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->addUserScript(source.get(), runAtStart, allFrames);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef addUserStyleSheetCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 2)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> source(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ bool allFrames = JSValueToBoolean(context, arguments[1]);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->addUserStyleSheet(source.get(), allFrames);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setShouldPaintBrokenImageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setShouldPaintBrokenImage(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef apiTestNewWindowDataLoadBaseURLCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 2)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> utf8Data(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ JSRetainPtr<JSStringRef> baseURL(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->apiTestNewWindowDataLoadBaseURL(utf8Data.get(), baseURL.get());
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef apiTestGoToCurrentBackForwardItemCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->apiTestGoToCurrentBackForwardItem();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setWebViewEditableCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has Mac implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setWebViewEditable(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+
+static JSValueRef abortModalCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->abortModal();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef hasSpellingMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 2)
+ return JSValueMakeUndefined(context);
+
+ int from = JSValueToNumber(context, arguments[0], 0);
+ int length = JSValueToNumber(context, arguments[1], 0);
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ bool ok = controller->hasSpellingMarker(from, length);
+
+ return JSValueMakeBoolean(context, ok);
+}
+
+static JSValueRef hasGrammarMarkerCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 2)
+ return JSValueMakeUndefined(context);
+
+ int from = JSValueToNumber(context, arguments[0], 0);
+ int length = JSValueToNumber(context, arguments[1], 0);
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ bool ok = controller->hasGrammarMarker(from, length);
+
+ return JSValueMakeBoolean(context, ok);
+}
+
+static JSValueRef markerTextForListItemCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+ return JSValueMakeString(context, controller->markerTextForListItem(context, arguments[0]).get());
+}
+
+static JSValueRef authenticateSessionCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // authenticateSession(url, username, password)
+ if (argumentCount != 3)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> url(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> username(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> password(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->authenticateSession(url.get(), username.get(), password.get());
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setEditingBehaviorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // The editing behavior string.
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> editingBehavior(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+
+ size_t maxLength = JSStringGetMaximumUTF8CStringSize(editingBehavior.get());
+ char* behaviorBuffer = new char[maxLength + 1];
+ JSStringGetUTF8CString(editingBehavior.get(), behaviorBuffer, maxLength);
+
+ if (strcmp(behaviorBuffer, "mac") && strcmp(behaviorBuffer, "win") && strcmp(behaviorBuffer, "unix")) {
+ JSRetainPtr<JSStringRef> invalidArgument(JSStringCreateWithUTF8CString("Passed invalid editing behavior. Must be 'mac', 'win', or 'unix'."));
+ *exception = JSValueMakeString(context, invalidArgument.get());
+ return JSValueMakeUndefined(context);
+ }
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setEditingBehavior(behaviorBuffer);
+
+ delete [] behaviorBuffer;
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setSerializeHTTPLoadsCallback(JSContextRef context, JSObjectRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ bool serialize = true;
+ if (argumentCount == 1)
+ serialize = JSValueToBoolean(context, arguments[0]);
+
+ LayoutTestController::setSerializeHTTPLoads(serialize);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef allowRoundingHacksCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ controller->allowRoundingHacks();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setShouldStayOnPageAfterHandlingBeforeUnloadCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+
+ if (argumentCount == 1)
+ controller->setShouldStayOnPageAfterHandlingBeforeUnload(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef addChromeInputFieldCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->addChromeInputField();
+ // the first argument is a callback that is called once the input field has been added
+ if (argumentCount == 1)
+ JSObjectCallAsFunction(context, JSValueToObject(context, arguments[0], 0), thisObject, 0, 0, 0);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef removeChromeInputFieldCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->removeChromeInputField();
+ // the first argument is a callback that is called once the input field has been added
+ if (argumentCount == 1)
+ JSObjectCallAsFunction(context, JSValueToObject(context, arguments[0], 0), thisObject, 0, 0, 0);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef focusWebViewCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->focusWebView();
+ // the first argument is a callback that is called once the input field has been added
+ if (argumentCount == 1)
+ JSObjectCallAsFunction(context, JSValueToObject(context, arguments[0], 0), thisObject, 0, 0, 0);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setBackingScaleFactorCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 2)
+ return JSValueMakeUndefined(context);
+
+ double backingScaleFactor = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setBackingScaleFactor(backingScaleFactor);
+
+ // The second argument is a callback that is called once the backing scale factor has been set.
+ JSObjectCallAsFunction(context, JSValueToObject(context, arguments[1], 0), thisObject, 0, 0, 0);
+ return JSValueMakeUndefined(context);
+}
+
+// Static Values
+
+static JSValueRef getGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeBoolean(context, controller->globalFlag());
+}
+
+static JSValueRef getWebHistoryItemCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeNumber(context, controller->webHistoryItemCount());
+}
+
+static JSValueRef getWorkerThreadCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeNumber(context, controller->workerThreadCount());
+}
+
+#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WIN)
+static JSValueRef getPlatformNameCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ JSRetainPtr<JSStringRef> platformName(controller->platformName());
+ if (!platformName.get())
+ return JSValueMakeUndefined(context);
+ return JSValueMakeString(context, platformName.get());
+}
+#endif
+
+static bool setGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setGlobalFlag(JSValueToBoolean(context, value));
+ return true;
+}
+
+static JSValueRef ignoreDesktopNotificationPermissionRequestsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->ignoreDesktopNotificationPermissionRequests();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef simulateDesktopNotificationClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ JSRetainPtr<JSStringRef> title(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ controller->simulateDesktopNotificationClick(title.get());
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setMinimumTimerIntervalCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ double minimum = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setMinimumTimerInterval(minimum);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef setTextDirectionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount == 1) {
+ JSRetainPtr<JSStringRef> direction(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setTextDirection(direction.get());
+ }
+
+ return JSValueMakeUndefined(context);
+}
+
+static void layoutTestControllerObjectFinalize(JSObjectRef object)
+{
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(object));
+ controller->deref();
+}
+
+// Object Creation
+
+void LayoutTestController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> layoutTestContollerStr(Adopt, JSStringCreateWithUTF8CString("layoutTestController"));
+ ref();
+
+ JSClassRef classRef = getJSClass();
+ JSValueRef layoutTestContollerObject = JSObjectMake(context, classRef, this);
+ JSClassRelease(classRef);
+
+ JSObjectSetProperty(context, windowObject, layoutTestContollerStr.get(), layoutTestContollerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
+}
+
+JSClassRef LayoutTestController::getJSClass()
+{
+ static JSStaticValue* staticValues = LayoutTestController::staticValues();
+ static JSStaticFunction* staticFunctions = LayoutTestController::staticFunctions();
+ static JSClassDefinition classDefinition = {
+ 0, kJSClassAttributeNone, "LayoutTestController", 0, staticValues, staticFunctions,
+ 0, layoutTestControllerObjectFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ return JSClassCreate(&classDefinition);
+}
+
+JSStaticValue* LayoutTestController::staticValues()
+{
+ static JSStaticValue staticValues[] = {
+ { "globalFlag", getGlobalFlagCallback, setGlobalFlagCallback, kJSPropertyAttributeNone },
+ { "webHistoryItemCount", getWebHistoryItemCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "workerThreadCount", getWorkerThreadCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WIN)
+ { "platformName", getPlatformNameCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+#endif
+ { 0, 0, 0, 0 }
+ };
+ return staticValues;
+}
+
+JSStaticFunction* LayoutTestController::staticFunctions()
+{
+ static JSStaticFunction staticFunctions[] = {
+ { "abortModal", abortModalCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addDisallowedURL", addDisallowedURLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addURLToRedirect", addURLToRedirectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addUserScript", addUserScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addUserStyleSheet", addUserStyleSheetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "apiTestNewWindowDataLoadBaseURL", apiTestNewWindowDataLoadBaseURLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "apiTestGoToCurrentBackForwardItem", apiTestGoToCurrentBackForwardItemCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "applicationCacheDiskUsageForOrigin", applicationCacheDiskUsageForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "callShouldCloseOnWebView", callShouldCloseOnWebViewCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "clearAllApplicationCaches", clearAllApplicationCachesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "clearAllDatabases", clearAllDatabasesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "clearApplicationCacheForOrigin", clearApplicationCacheForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "clearBackForwardList", clearBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "clearPersistentUserStyleSheet", clearPersistentUserStyleSheetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "closeWebInspector", closeWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "computedStyleIncludingVisitedInfo", computedStyleIncludingVisitedInfoCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "nodesFromRect", nodesFromRectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "decodeHostName", decodeHostNameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "disableImageLoading", disableImageLoadingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "disallowIncreaseForApplicationCacheQuota", disallowIncreaseForApplicationCacheQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dispatchPendingLoadRequests", dispatchPendingLoadRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "display", displayCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "displayInvalidatedRegion", displayInvalidatedRegionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpApplicationCacheDelegateCallbacks", dumpApplicationCacheDelegateCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpAsText", dumpAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpBackForwardList", dumpBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpChildFrameScrollPositions", dumpChildFrameScrollPositionsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpChildFramesAsText", dumpChildFramesAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpConfigurationForViewport", dumpConfigurationForViewportCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpDOMAsWebArchive", dumpDOMAsWebArchiveCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpDatabaseCallbacks", dumpDatabaseCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpEditingCallbacks", dumpEditingCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpFrameLoadCallbacks", dumpFrameLoadCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpProgressFinishedCallback", dumpProgressFinishedCallbackCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpUserGestureInFrameLoadCallbacks", dumpUserGestureInFrameLoadCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpResourceLoadCallbacks", dumpResourceLoadCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpResourceResponseMIMETypes", dumpResourceResponseMIMETypesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpSelectionRect", dumpSelectionRectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpSourceAsWebArchive", dumpSourceAsWebArchiveCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpStatusCallbacks", dumpStatusCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpTitleChanges", dumpTitleChangesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpIconChanges", dumpIconChangesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dumpWillCacheResponse", dumpWillCacheResponseCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "elementDoesAutoCompleteForElementWithId", elementDoesAutoCompleteForElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "encodeHostName", encodeHostNameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "evaluateInWebInspector", evaluateInWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "evaluateScriptInIsolatedWorld", evaluateScriptInIsolatedWorldCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "execCommand", execCommandCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "findString", findStringCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "counterValueForElementById", counterValueForElementByIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "originsWithApplicationCache", originsWithApplicationCacheCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "goBack", goBackCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "grantDesktopNotificationPermission", grantDesktopNotificationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "hasSpellingMarker", hasSpellingMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "hasGrammarMarker", hasGrammarMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ignoreDesktopNotificationPermissionRequests", ignoreDesktopNotificationPermissionRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isCommandEnabled", isCommandEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isPageBoxVisible", isPageBoxVisibleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "keepWebHistory", keepWebHistoryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "layerTreeAsText", layerTreeAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "numberOfPages", numberOfPagesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "numberOfPendingGeolocationPermissionRequests", numberOfPendingGeolocationPermissionRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "markerTextForListItem", markerTextForListItemCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "notifyDone", notifyDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "numberOfActiveAnimations", numberOfActiveAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "suspendAnimations", suspendAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "resumeAnimations", resumeAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "overridePreference", overridePreferenceCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "pageNumberForElementById", pageNumberForElementByIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "pageSizeAndMarginsInPixels", pageSizeAndMarginsInPixelsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "pageProperty", pagePropertyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "pathToLocalResource", pathToLocalResourceCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "pauseAnimationAtTimeOnElementWithId", pauseAnimationAtTimeOnElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "pauseTransitionAtTimeOnElementWithId", pauseTransitionAtTimeOnElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "sampleSVGAnimationForElementAtTime", sampleSVGAnimationForElementAtTimeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "printToPDF", dumpAsPDFCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "queueBackNavigation", queueBackNavigationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "queueForwardNavigation", queueForwardNavigationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "queueLoad", queueLoadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "queueLoadHTMLString", queueLoadHTMLStringCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "queueLoadingScript", queueLoadingScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "queueNonLoadingScript", queueNonLoadingScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "queueReload", queueReloadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "removeAllVisitedLinks", removeAllVisitedLinksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "removeOriginAccessWhitelistEntry", removeOriginAccessWhitelistEntryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "repaintSweepHorizontally", repaintSweepHorizontallyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "resetPageVisibility", resetPageVisibilityCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAcceptsEditing", setAcceptsEditingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAllowUniversalAccessFromFileURLs", setAllowUniversalAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAllowFileAccessFromFileURLs", setAllowFileAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAlwaysAcceptCookies", setAlwaysAcceptCookiesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAppCacheMaximumSize", setAppCacheMaximumSizeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setApplicationCacheOriginQuota", setApplicationCacheOriginQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setEncodedAudioData", setEncodedAudioDataCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAuthenticationPassword", setAuthenticationPasswordCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAuthenticationUsername", setAuthenticationUsernameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAuthorAndUserStylesEnabled", setAuthorAndUserStylesEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAutofilled", setAutofilledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setCacheModel", setCacheModelCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setCallCloseOnWebViews", setCallCloseOnWebViewsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setCanOpenWindows", setCanOpenWindowsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setCloseRemainingWindowsWhenComplete", setCloseRemainingWindowsWhenCompleteCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setCustomPolicyDelegate", setCustomPolicyDelegateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setDatabaseQuota", setDatabaseQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setDeferMainResourceDataLoad", setDeferMainResourceDataLoadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setDefersLoading", setDefersLoadingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setDomainRelaxationForbiddenForURLScheme", setDomainRelaxationForbiddenForURLSchemeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setEditingBehavior", setEditingBehaviorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setFrameFlatteningEnabled", setFrameFlatteningEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setGeolocationPermission", setGeolocationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setHandlesAuthenticationChallenges", setHandlesAuthenticationChallengesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setIconDatabaseEnabled", setIconDatabaseEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setJavaScriptProfilingEnabled", setJavaScriptProfilingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setMainFrameIsFirstResponder", setMainFrameIsFirstResponderCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setMinimumTimerInterval", setMinimumTimerIntervalCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setMockDeviceOrientation", setMockDeviceOrientationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setMockGeolocationError", setMockGeolocationErrorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setMockGeolocationPosition", setMockGeolocationPositionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addMockSpeechInputResult", addMockSpeechInputResultCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setNewWindowsCopyBackForwardList", setNewWindowsCopyBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setPageVisibility", setPageVisibilityCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setPOSIXLocale", setPOSIXLocaleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setPersistentUserStyleSheetLocation", setPersistentUserStyleSheetLocationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setPopupBlockingEnabled", setPopupBlockingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setPluginsEnabled", setPluginsEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setPrinting", setPrintingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setPrivateBrowsingEnabled", setPrivateBrowsingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSelectTrailingWhitespaceEnabled", setSelectTrailingWhitespaceEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSerializeHTTPLoads", setSerializeHTTPLoadsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSmartInsertDeleteEnabled", setSmartInsertDeleteEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSpatialNavigationEnabled", setSpatialNavigationEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setStopProvisionalFrameLoads", setStopProvisionalFrameLoadsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setTabKeyCyclesThroughElements", setTabKeyCyclesThroughElementsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setUseDashboardCompatibilityMode", setUseDashboardCompatibilityModeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setUserStyleSheetEnabled", setUserStyleSheetEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setUserStyleSheetLocation", setUserStyleSheetLocationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setValueForUser", setValueForUserCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setViewModeMediaFeature", setViewModeMediaFeatureCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setWebViewEditable", setWebViewEditableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setWillSendRequestClearHeader", setWillSendRequestClearHeaderCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setWillSendRequestReturnsNull", setWillSendRequestReturnsNullCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setWillSendRequestReturnsNullOnRedirect", setWillSendRequestReturnsNullOnRedirectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setWindowIsKey", setWindowIsKeyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setJavaScriptCanAccessClipboard", setJavaScriptCanAccessClipboardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setXSSAuditorEnabled", setXSSAuditorEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAsynchronousSpellCheckingEnabled", setAsynchronousSpellCheckingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "showWebInspector", showWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "simulateDesktopNotificationClick", simulateDesktopNotificationClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "testOnscreen", testOnscreenCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "testRepaint", testRepaintCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "waitForPolicyDelegate", waitForPolicyDelegateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "waitUntilDone", waitUntilDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "windowCount", windowCountCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addOriginAccessWhitelistEntry", addOriginAccessWhitelistEntryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setScrollbarPolicy", setScrollbarPolicyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "authenticateSession", authenticateSessionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "deleteAllLocalStorage", deleteAllLocalStorageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "syncLocalStorage", syncLocalStorageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "observeStorageTrackerNotifications", observeStorageTrackerNotificationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "deleteLocalStorageForOrigin", deleteLocalStorageForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "localStorageDiskUsageForOrigin", localStorageDiskUsageForOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "originsWithLocalStorage", originsWithLocalStorageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setShouldPaintBrokenImage", setShouldPaintBrokenImageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setTextDirection", setTextDirectionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "allowRoundingHacks", allowRoundingHacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setShouldStayOnPageAfterHandlingBeforeUnload", setShouldStayOnPageAfterHandlingBeforeUnloadCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addChromeInputField", addChromeInputFieldCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "removeChromeInputField", removeChromeInputFieldCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "focusWebView", focusWebViewCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setBackingScaleFactor", setBackingScaleFactorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+ };
+
+ return staticFunctions;
+}
+
+void LayoutTestController::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL)
+{
+ WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL));
+}
+
+void LayoutTestController::queueLoadAlternateHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL)
+{
+ WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL, unreachableURL));
+}
+
+void LayoutTestController::queueBackNavigation(int howFarBack)
+{
+ WorkQueue::shared()->queue(new BackItem(howFarBack));
+}
+
+void LayoutTestController::queueForwardNavigation(int howFarForward)
+{
+ WorkQueue::shared()->queue(new ForwardItem(howFarForward));
+}
+
+void LayoutTestController::queueLoadingScript(JSStringRef script)
+{
+ WorkQueue::shared()->queue(new LoadingScriptItem(script));
+}
+
+void LayoutTestController::queueNonLoadingScript(JSStringRef script)
+{
+ WorkQueue::shared()->queue(new NonLoadingScriptItem(script));
+}
+
+void LayoutTestController::queueReload()
+{
+ WorkQueue::shared()->queue(new ReloadItem);
+}
+
+void LayoutTestController::grantDesktopNotificationPermission(JSStringRef origin)
+{
+ m_desktopNotificationAllowedOrigins.push_back(JSStringRetain(origin));
+}
+
+bool LayoutTestController::checkDesktopNotificationPermission(JSStringRef origin)
+{
+ std::vector<JSStringRef>::iterator i;
+ for (i = m_desktopNotificationAllowedOrigins.begin();
+ i != m_desktopNotificationAllowedOrigins.end();
+ ++i) {
+ if (JSStringIsEqual(*i, origin))
+ return true;
+ }
+ return false;
+}
+
+void LayoutTestController::ignoreDesktopNotificationPermissionRequests()
+{
+ m_areDesktopNotificationPermissionRequestsIgnored = false;
+}
+
+void LayoutTestController::waitToDumpWatchdogTimerFired()
+{
+ const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
+ fprintf(stderr, "%s", message);
+ fprintf(stdout, "%s", message);
+ notifyDone();
+}
+
+void LayoutTestController::setGeolocationPermissionCommon(bool allow)
+{
+ m_isGeolocationPermissionSet = true;
+ m_geolocationPermission = allow;
+}
+
+void LayoutTestController::setPOSIXLocale(JSStringRef locale)
+{
+ char localeBuf[32];
+ JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf));
+ setlocale(LC_ALL, localeBuf);
+}
+
+void LayoutTestController::addURLToRedirect(std::string origin, std::string destination)
+{
+ m_URLsToRedirect[origin] = destination;
+}
+
+const std::string& LayoutTestController::redirectionDestinationForURL(std::string origin)
+{
+ return m_URLsToRedirect[origin];
+}
+
+void LayoutTestController::setShouldPaintBrokenImage(bool shouldPaintBrokenImage)
+{
+ m_shouldPaintBrokenImage = shouldPaintBrokenImage;
+}
+
+const unsigned LayoutTestController::maxViewWidth = 800;
+const unsigned LayoutTestController::maxViewHeight = 600;
diff --git a/Tools/DumpRenderTree/LayoutTestController.h b/Tools/DumpRenderTree/LayoutTestController.h
new file mode 100644
index 000000000..9f4db4983
--- /dev/null
+++ b/Tools/DumpRenderTree/LayoutTestController.h
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 LayoutTestController_h
+#define LayoutTestController_h
+
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+class LayoutTestController : public RefCounted<LayoutTestController> {
+public:
+ static PassRefPtr<LayoutTestController> create(const std::string& testPathOrURL, const std::string& expectedPixelHash);
+ ~LayoutTestController();
+
+ void makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception);
+
+ void addDisallowedURL(JSStringRef url);
+ void addURLToRedirect(std::string origin, std::string destination);
+ const std::string& redirectionDestinationForURL(std::string);
+ void clearAllApplicationCaches();
+ void clearAllDatabases();
+ void clearApplicationCacheForOrigin(JSStringRef name);
+ void clearBackForwardList();
+ void clearPersistentUserStyleSheet();
+ bool callShouldCloseOnWebView();
+ JSStringRef copyDecodedHostName(JSStringRef name);
+ JSStringRef copyEncodedHostName(JSStringRef name);
+ JSRetainPtr<JSStringRef> counterValueForElementById(JSStringRef id);
+ void disableImageLoading();
+ void dispatchPendingLoadRequests();
+ void display();
+ void displayInvalidatedRegion();
+ void execCommand(JSStringRef name, JSStringRef value);
+ bool findString(JSContextRef, JSStringRef, JSObjectRef optionsArray);
+ void goBack();
+ JSValueRef originsWithApplicationCache(JSContextRef);
+ long long applicationCacheDiskUsageForOrigin(JSStringRef name);
+ bool isCommandEnabled(JSStringRef name);
+ void keepWebHistory();
+ JSValueRef computedStyleIncludingVisitedInfo(JSContextRef, JSValueRef);
+ JSValueRef nodesFromRect(JSContextRef, JSValueRef, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping);
+ void notifyDone();
+ int numberOfPages(float pageWidthInPixels, float pageHeightInPixels);
+ int numberOfPendingGeolocationPermissionRequests();
+ void overridePreference(JSStringRef key, JSStringRef value);
+ int pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels);
+ JSRetainPtr<JSStringRef> pageProperty(const char* propertyName, int pageNumber) const;
+ JSRetainPtr<JSStringRef> pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const;
+ bool isPageBoxVisible(int pageNumber) const;
+ JSStringRef pathToLocalResource(JSContextRef, JSStringRef url);
+ void queueBackNavigation(int howFarBackward);
+ void queueForwardNavigation(int howFarForward);
+ void queueLoad(JSStringRef url, JSStringRef target);
+ void queueLoadHTMLString(JSStringRef content, JSStringRef baseURL);
+ void queueLoadAlternateHTMLString(JSStringRef content, JSStringRef baseURL, JSStringRef unreachableURL);
+ void queueLoadingScript(JSStringRef script);
+ void queueNonLoadingScript(JSStringRef script);
+ void queueReload();
+ void removeAllVisitedLinks();
+ void setAcceptsEditing(bool acceptsEditing);
+ void setAllowUniversalAccessFromFileURLs(bool);
+ void setAllowFileAccessFromFileURLs(bool);
+ void setAppCacheMaximumSize(unsigned long long quota);
+ void setApplicationCacheOriginQuota(unsigned long long quota);
+ void setAuthorAndUserStylesEnabled(bool);
+ void setAutofilled(JSContextRef, JSValueRef nodeObject, bool autofilled);
+ void setCacheModel(int);
+ void setCustomPolicyDelegate(bool setDelegate, bool permissive);
+ void setDatabaseQuota(unsigned long long quota);
+ void setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme);
+ void setDefersLoading(bool);
+ void setIconDatabaseEnabled(bool iconDatabaseEnabled);
+ void setJavaScriptProfilingEnabled(bool profilingEnabled);
+ void setJavaScriptCanAccessClipboard(bool flag);
+ void setMainFrameIsFirstResponder(bool flag);
+ void setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma);
+ void setMockGeolocationError(int code, JSStringRef message);
+ void setMockGeolocationPosition(double latitude, double longitude, double accuracy);
+ void addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language);
+ void setPersistentUserStyleSheetLocation(JSStringRef path);
+ void setPluginsEnabled(bool flag);
+ void setPopupBlockingEnabled(bool flag);
+ void setPrivateBrowsingEnabled(bool flag);
+ void setSelectTrailingWhitespaceEnabled(bool flag);
+ void setSmartInsertDeleteEnabled(bool flag);
+ void setTabKeyCyclesThroughElements(bool cycles);
+ void setUseDashboardCompatibilityMode(bool flag);
+ void setUserStyleSheetEnabled(bool flag);
+ void setUserStyleSheetLocation(JSStringRef path);
+ void setValueForUser(JSContextRef, JSValueRef nodeObject, JSStringRef value);
+ void setViewModeMediaFeature(JSStringRef mode);
+ void setXSSAuditorEnabled(bool flag);
+ void setFrameFlatteningEnabled(bool enable);
+ void setSpatialNavigationEnabled(bool enable);
+ void setScrollbarPolicy(JSStringRef orientation, JSStringRef policy);
+ void setEditingBehavior(const char* editingBehavior);
+ void startSpeechInput(JSContextRef inputElement);
+
+ void setPageVisibility(const char* visibility) { }
+ void resetPageVisibility() { }
+
+ void waitForPolicyDelegate();
+ size_t webHistoryItemCount();
+ unsigned workerThreadCount() const;
+ int windowCount();
+
+#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WIN)
+ JSRetainPtr<JSStringRef> platformName() const;
+#endif
+
+ void grantDesktopNotificationPermission(JSStringRef origin);
+ bool checkDesktopNotificationPermission(JSStringRef origin);
+ void ignoreDesktopNotificationPermissionRequests();
+ bool areDesktopNotificationPermissionRequestsIgnored() const { return m_areDesktopNotificationPermissionRequestsIgnored; }
+ void simulateDesktopNotificationClick(JSStringRef title);
+
+ bool elementDoesAutoCompleteForElementWithId(JSStringRef id);
+
+ bool dumpAsAudio() const { return m_dumpAsAudio; }
+ void setDumpAsAudio(bool dumpAsAudio) { m_dumpAsAudio = dumpAsAudio; }
+
+ bool dumpAsPDF() const { return m_dumpAsPDF; }
+ void setDumpAsPDF(bool dumpAsPDF) { m_dumpAsPDF = dumpAsPDF; }
+
+ bool dumpAsText() const { return m_dumpAsText; }
+ void setDumpAsText(bool dumpAsText) { m_dumpAsText = dumpAsText; }
+
+ bool generatePixelResults() const { return m_generatePixelResults; }
+ void setGeneratePixelResults(bool generatePixelResults) { m_generatePixelResults = generatePixelResults; }
+
+ bool disallowIncreaseForApplicationCacheQuota() const { return m_disallowIncreaseForApplicationCacheQuota; }
+ void setDisallowIncreaseForApplicationCacheQuota(bool disallowIncrease) { m_disallowIncreaseForApplicationCacheQuota = disallowIncrease; }
+
+ bool dumpApplicationCacheDelegateCallbacks() const { return m_dumpApplicationCacheDelegateCallbacks; }
+ void setDumpApplicationCacheDelegateCallbacks(bool dumpCallbacks) { m_dumpApplicationCacheDelegateCallbacks = dumpCallbacks; }
+
+ bool dumpBackForwardList() const { return m_dumpBackForwardList; }
+ void setDumpBackForwardList(bool dumpBackForwardList) { m_dumpBackForwardList = dumpBackForwardList; }
+
+ bool dumpChildFrameScrollPositions() const { return m_dumpChildFrameScrollPositions; }
+ void setDumpChildFrameScrollPositions(bool dumpChildFrameScrollPositions) { m_dumpChildFrameScrollPositions = dumpChildFrameScrollPositions; }
+
+ bool dumpChildFramesAsText() const { return m_dumpChildFramesAsText; }
+ void setDumpChildFramesAsText(bool dumpChildFramesAsText) { m_dumpChildFramesAsText = dumpChildFramesAsText; }
+
+ bool dumpDatabaseCallbacks() const { return m_dumpDatabaseCallbacks; }
+ void setDumpDatabaseCallbacks(bool dumpDatabaseCallbacks) { m_dumpDatabaseCallbacks = dumpDatabaseCallbacks; }
+
+ bool dumpDOMAsWebArchive() const { return m_dumpDOMAsWebArchive; }
+ void setDumpDOMAsWebArchive(bool dumpDOMAsWebArchive) { m_dumpDOMAsWebArchive = dumpDOMAsWebArchive; }
+
+ bool dumpEditingCallbacks() const { return m_dumpEditingCallbacks; }
+ void setDumpEditingCallbacks(bool dumpEditingCallbacks) { m_dumpEditingCallbacks = dumpEditingCallbacks; }
+
+ bool dumpFrameLoadCallbacks() const { return m_dumpFrameLoadCallbacks; }
+ void setDumpFrameLoadCallbacks(bool dumpFrameLoadCallbacks) { m_dumpFrameLoadCallbacks = dumpFrameLoadCallbacks; }
+
+ bool dumpProgressFinishedCallback() const { return m_dumpProgressFinishedCallback; }
+ void setDumpProgressFinishedCallback(bool dumpProgressFinishedCallback) { m_dumpProgressFinishedCallback = dumpProgressFinishedCallback; }
+
+ bool dumpUserGestureInFrameLoadCallbacks() const { return m_dumpUserGestureInFrameLoadCallbacks; }
+ void setDumpUserGestureInFrameLoadCallbacks(bool dumpUserGestureInFrameLoadCallbacks) { m_dumpUserGestureInFrameLoadCallbacks = dumpUserGestureInFrameLoadCallbacks; }
+
+ bool dumpHistoryDelegateCallbacks() const { return m_dumpHistoryDelegateCallbacks; }
+ void setDumpHistoryDelegateCallbacks(bool dumpHistoryDelegateCallbacks) { m_dumpHistoryDelegateCallbacks = dumpHistoryDelegateCallbacks; }
+
+ bool dumpResourceLoadCallbacks() const { return m_dumpResourceLoadCallbacks; }
+ void setDumpResourceLoadCallbacks(bool dumpResourceLoadCallbacks) { m_dumpResourceLoadCallbacks = dumpResourceLoadCallbacks; }
+
+ bool dumpResourceResponseMIMETypes() const { return m_dumpResourceResponseMIMETypes; }
+ void setDumpResourceResponseMIMETypes(bool dumpResourceResponseMIMETypes) { m_dumpResourceResponseMIMETypes = dumpResourceResponseMIMETypes; }
+
+ bool dumpSelectionRect() const { return m_dumpSelectionRect; }
+ void setDumpSelectionRect(bool dumpSelectionRect) { m_dumpSelectionRect = dumpSelectionRect; }
+
+ bool dumpSourceAsWebArchive() const { return m_dumpSourceAsWebArchive; }
+ void setDumpSourceAsWebArchive(bool dumpSourceAsWebArchive) { m_dumpSourceAsWebArchive = dumpSourceAsWebArchive; }
+
+ bool dumpStatusCallbacks() const { return m_dumpStatusCallbacks; }
+ void setDumpStatusCallbacks(bool dumpStatusCallbacks) { m_dumpStatusCallbacks = dumpStatusCallbacks; }
+
+ bool dumpTitleChanges() const { return m_dumpTitleChanges; }
+ void setDumpTitleChanges(bool dumpTitleChanges) { m_dumpTitleChanges = dumpTitleChanges; }
+
+ bool dumpIconChanges() const { return m_dumpIconChanges; }
+ void setDumpIconChanges(bool dumpIconChanges) { m_dumpIconChanges = dumpIconChanges; }
+
+ bool dumpVisitedLinksCallback() const { return m_dumpVisitedLinksCallback; }
+ void setDumpVisitedLinksCallback(bool dumpVisitedLinksCallback) { m_dumpVisitedLinksCallback = dumpVisitedLinksCallback; }
+
+ bool dumpWillCacheResponse() const { return m_dumpWillCacheResponse; }
+ void setDumpWillCacheResponse(bool dumpWillCacheResponse) { m_dumpWillCacheResponse = dumpWillCacheResponse; }
+
+ bool callCloseOnWebViews() const { return m_callCloseOnWebViews; }
+ void setCallCloseOnWebViews(bool callCloseOnWebViews) { m_callCloseOnWebViews = callCloseOnWebViews; }
+
+ bool canOpenWindows() const { return m_canOpenWindows; }
+ void setCanOpenWindows(bool canOpenWindows) { m_canOpenWindows = canOpenWindows; }
+
+ bool closeRemainingWindowsWhenComplete() const { return m_closeRemainingWindowsWhenComplete; }
+ void setCloseRemainingWindowsWhenComplete(bool closeRemainingWindowsWhenComplete) { m_closeRemainingWindowsWhenComplete = closeRemainingWindowsWhenComplete; }
+
+ bool newWindowsCopyBackForwardList() const { return m_newWindowsCopyBackForwardList; }
+ void setNewWindowsCopyBackForwardList(bool newWindowsCopyBackForwardList) { m_newWindowsCopyBackForwardList = newWindowsCopyBackForwardList; }
+
+ bool stopProvisionalFrameLoads() const { return m_stopProvisionalFrameLoads; }
+ void setStopProvisionalFrameLoads(bool stopProvisionalFrameLoads) { m_stopProvisionalFrameLoads = stopProvisionalFrameLoads; }
+
+ bool testOnscreen() const { return m_testOnscreen; }
+ void setTestOnscreen(bool testOnscreen) { m_testOnscreen = testOnscreen; }
+
+ bool testRepaint() const { return m_testRepaint; }
+ void setTestRepaint(bool testRepaint) { m_testRepaint = testRepaint; }
+
+ bool testRepaintSweepHorizontally() const { return m_testRepaintSweepHorizontally; }
+ void setTestRepaintSweepHorizontally(bool testRepaintSweepHorizontally) { m_testRepaintSweepHorizontally = testRepaintSweepHorizontally; }
+
+ bool waitToDump() const { return m_waitToDump; }
+ void setWaitToDump(bool waitToDump);
+ void waitToDumpWatchdogTimerFired();
+
+ const std::set<std::string>& willSendRequestClearHeaders() const { return m_willSendRequestClearHeaders; }
+ void setWillSendRequestClearHeader(std::string header) { m_willSendRequestClearHeaders.insert(header); }
+
+ bool willSendRequestReturnsNull() const { return m_willSendRequestReturnsNull; }
+ void setWillSendRequestReturnsNull(bool returnsNull) { m_willSendRequestReturnsNull = returnsNull; }
+
+ bool willSendRequestReturnsNullOnRedirect() const { return m_willSendRequestReturnsNullOnRedirect; }
+ void setWillSendRequestReturnsNullOnRedirect(bool returnsNull) { m_willSendRequestReturnsNullOnRedirect = returnsNull; }
+
+ bool windowIsKey() const { return m_windowIsKey; }
+ void setWindowIsKey(bool windowIsKey);
+
+ bool alwaysAcceptCookies() const { return m_alwaysAcceptCookies; }
+ void setAlwaysAcceptCookies(bool alwaysAcceptCookies);
+
+ bool handlesAuthenticationChallenges() const { return m_handlesAuthenticationChallenges; }
+ void setHandlesAuthenticationChallenges(bool handlesAuthenticationChallenges) { m_handlesAuthenticationChallenges = handlesAuthenticationChallenges; }
+
+ bool isPrinting() const { return m_isPrinting; }
+ void setIsPrinting(bool isPrinting) { m_isPrinting = isPrinting; }
+
+ const std::string& authenticationUsername() const { return m_authenticationUsername; }
+ void setAuthenticationUsername(std::string username) { m_authenticationUsername = username; }
+
+ const std::string& authenticationPassword() const { return m_authenticationPassword; }
+ void setAuthenticationPassword(std::string password) { m_authenticationPassword = password; }
+
+ bool globalFlag() const { return m_globalFlag; }
+ void setGlobalFlag(bool globalFlag) { m_globalFlag = globalFlag; }
+
+ bool deferMainResourceDataLoad() const { return m_deferMainResourceDataLoad; }
+ void setDeferMainResourceDataLoad(bool flag) { m_deferMainResourceDataLoad = flag; }
+
+ const std::string& testPathOrURL() const { return m_testPathOrURL; }
+ const std::string& expectedPixelHash() const { return m_expectedPixelHash; }
+
+ const std::string& encodedAudioData() const { return m_encodedAudioData; }
+ void setEncodedAudioData(const std::string& encodedAudioData) { m_encodedAudioData = encodedAudioData; }
+
+ bool pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId);
+ bool pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId);
+ bool sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId);
+ unsigned numberOfActiveAnimations() const;
+ void suspendAnimations() const;
+ void resumeAnimations() const;
+
+ void addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains);
+ void removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains);
+
+ void addUserScript(JSStringRef source, bool runAtStart, bool allFrames);
+ void addUserStyleSheet(JSStringRef source, bool allFrames);
+
+ void setGeolocationPermission(bool allow);
+ bool isGeolocationPermissionSet() const { return m_isGeolocationPermissionSet; }
+ bool geolocationPermission() const { return m_geolocationPermission; }
+
+ void setDeveloperExtrasEnabled(bool);
+ void setAsynchronousSpellCheckingEnabled(bool);
+ void showWebInspector();
+ void closeWebInspector();
+ void evaluateInWebInspector(long callId, JSStringRef script);
+ void evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script);
+ void allowRoundingHacks();
+
+ bool shouldStayOnPageAfterHandlingBeforeUnload() const { return m_shouldStayOnPageAfterHandlingBeforeUnload; }
+ void setShouldStayOnPageAfterHandlingBeforeUnload(bool shouldStayOnPageAfterHandlingBeforeUnload) { m_shouldStayOnPageAfterHandlingBeforeUnload = shouldStayOnPageAfterHandlingBeforeUnload; }
+
+ void addChromeInputField();
+ void removeChromeInputField();
+ void focusWebView();
+
+ void setBackingScaleFactor(double);
+
+ void setPOSIXLocale(JSStringRef locale);
+
+ void setWebViewEditable(bool);
+
+ void abortModal();
+
+ bool hasSpellingMarker(int from, int length);
+ bool hasGrammarMarker(int from, int length);
+
+ void dumpConfigurationForViewport(int deviceDPI, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight);
+
+ static void setSerializeHTTPLoads(bool serialize);
+
+ // The following API test functions should probably be moved to platform-specific
+ // unit tests outside of DRT once they exist.
+ void apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL);
+ void apiTestGoToCurrentBackForwardItem();
+
+ // Simulate a request an embedding application could make, populating per-session credential storage.
+ void authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password);
+
+ JSRetainPtr<JSStringRef> layerTreeAsText() const;
+
+ JSRetainPtr<JSStringRef> markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const;
+
+ JSValueRef originsWithLocalStorage(JSContextRef);
+ void deleteAllLocalStorage();
+ void deleteLocalStorageForOrigin(JSStringRef originIdentifier);
+ long long localStorageDiskUsageForOrigin(JSStringRef originIdentifier);
+ void observeStorageTrackerNotifications(unsigned number);
+ void syncLocalStorage();
+
+ void setShouldPaintBrokenImage(bool);
+ bool shouldPaintBrokenImage() const { return m_shouldPaintBrokenImage; }
+
+ static const unsigned maxViewWidth;
+ static const unsigned maxViewHeight;
+
+ void setMinimumTimerInterval(double);
+
+ void setTextDirection(JSStringRef);
+
+private:
+ LayoutTestController(const std::string& testPathOrURL, const std::string& expectedPixelHash);
+
+ void setGeolocationPermissionCommon(bool allow);
+
+ bool m_disallowIncreaseForApplicationCacheQuota;
+ bool m_dumpApplicationCacheDelegateCallbacks;
+ bool m_dumpAsAudio;
+ bool m_dumpAsPDF;
+ bool m_dumpAsText;
+ bool m_dumpBackForwardList;
+ bool m_dumpChildFrameScrollPositions;
+ bool m_dumpChildFramesAsText;
+ bool m_dumpDOMAsWebArchive;
+ bool m_dumpDatabaseCallbacks;
+ bool m_dumpEditingCallbacks;
+ bool m_dumpFrameLoadCallbacks;
+ bool m_dumpProgressFinishedCallback;
+ bool m_dumpUserGestureInFrameLoadCallbacks;
+ bool m_dumpHistoryDelegateCallbacks;
+ bool m_dumpResourceLoadCallbacks;
+ bool m_dumpResourceResponseMIMETypes;
+ bool m_dumpSelectionRect;
+ bool m_dumpSourceAsWebArchive;
+ bool m_dumpStatusCallbacks;
+ bool m_dumpTitleChanges;
+ bool m_dumpIconChanges;
+ bool m_dumpVisitedLinksCallback;
+ bool m_dumpWillCacheResponse;
+ bool m_generatePixelResults;
+ bool m_callCloseOnWebViews;
+ bool m_canOpenWindows;
+ bool m_closeRemainingWindowsWhenComplete;
+ bool m_newWindowsCopyBackForwardList;
+ bool m_stopProvisionalFrameLoads;
+ bool m_testOnscreen;
+ bool m_testRepaint;
+ bool m_testRepaintSweepHorizontally;
+ bool m_waitToDump; // True if waitUntilDone() has been called, but notifyDone() has not yet been called.
+ bool m_willSendRequestReturnsNull;
+ bool m_willSendRequestReturnsNullOnRedirect;
+ bool m_windowIsKey;
+ bool m_alwaysAcceptCookies;
+ bool m_globalFlag;
+ bool m_isGeolocationPermissionSet;
+ bool m_geolocationPermission;
+ bool m_handlesAuthenticationChallenges;
+ bool m_isPrinting;
+ bool m_deferMainResourceDataLoad;
+ bool m_shouldPaintBrokenImage;
+ bool m_shouldStayOnPageAfterHandlingBeforeUnload;
+ bool m_areDesktopNotificationPermissionRequestsIgnored;
+
+ std::string m_authenticationUsername;
+ std::string m_authenticationPassword;
+ std::string m_testPathOrURL;
+ std::string m_expectedPixelHash; // empty string if no hash
+
+ std::set<std::string> m_willSendRequestClearHeaders;
+
+ // base64 encoded WAV audio data is stored here.
+ std::string m_encodedAudioData;
+
+ // origins which have been granted desktop notification access
+ std::vector<JSStringRef> m_desktopNotificationAllowedOrigins;
+
+ std::map<std::string, std::string> m_URLsToRedirect;
+
+ static JSClassRef getJSClass();
+ static JSStaticValue* staticValues();
+ static JSStaticFunction* staticFunctions();
+};
+
+#endif // LayoutTestController_h
diff --git a/Tools/DumpRenderTree/Makefile b/Tools/DumpRenderTree/Makefile
new file mode 100644
index 000000000..1f1dbbcb3
--- /dev/null
+++ b/Tools/DumpRenderTree/Makefile
@@ -0,0 +1,2 @@
+SCRIPTS_PATH = ../Scripts
+include ../../Makefile.shared
diff --git a/Tools/DumpRenderTree/PixelDumpSupport.cpp b/Tools/DumpRenderTree/PixelDumpSupport.cpp
new file mode 100644
index 000000000..ee38c235c
--- /dev/null
+++ b/Tools/DumpRenderTree/PixelDumpSupport.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2009 Apple, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "PixelDumpSupport.h"
+
+#include "CyclicRedundancyCheck.h"
+#include "DumpRenderTree.h"
+#include "LayoutTestController.h"
+#include <cstdio>
+#include <wtf/Assertions.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+#if USE(CG)
+#include "PixelDumpSupportCG.h"
+#elif USE(CAIRO)
+#include "PixelDumpSupportCairo.h"
+#endif
+
+void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash)
+{
+ RefPtr<BitmapContext> context;
+#if PLATFORM(MAC)
+ if (gLayoutTestController->isPrinting())
+ context = createPagedBitmapContext();
+ else
+#endif
+ context = createBitmapContextFromWebView(gLayoutTestController->testOnscreen(), gLayoutTestController->testRepaint(), gLayoutTestController->testRepaintSweepHorizontally(), gLayoutTestController->dumpSelectionRect());
+ ASSERT(context);
+
+ // Compute the hash of the bitmap context pixels
+ char actualHash[33];
+ computeMD5HashStringForBitmapContext(context.get(), actualHash);
+ printf("\nActualHash: %s\n", actualHash); // FIXME: No need for the leading newline.
+
+ // Check the computed hash against the expected one and dump image on mismatch
+ bool dumpImage = true;
+ if (expectedHash.length() > 0) {
+ ASSERT(expectedHash.length() == 32);
+
+ printf("\nExpectedHash: %s\n", expectedHash.c_str()); // FIXME: No need for the leading newline.
+
+ if (expectedHash == actualHash) // FIXME: do case insensitive compare
+ dumpImage = false;
+ }
+
+ if (dumpImage)
+ dumpBitmap(context.get(), actualHash);
+}
+
+static void appendIntToVector(unsigned number, Vector<unsigned char>& vector)
+{
+ size_t offset = vector.size();
+ vector.grow(offset + 4);
+ vector[offset] = ((number >> 24) & 0xff);
+ vector[offset + 1] = ((number >> 16) & 0xff);
+ vector[offset + 2] = ((number >> 8) & 0xff);
+ vector[offset + 3] = (number & 0xff);
+}
+
+static void convertChecksumToPNGComment(const char* checksum, Vector<unsigned char>& bytesToAdd)
+{
+ // Chunks of PNG files are <length>, <type>, <data>, <crc>.
+ static const char textCommentPrefix[] = "\x00\x00\x00\x29tEXtchecksum\x00";
+ static const size_t prefixLength = sizeof(textCommentPrefix) - 1; // The -1 is for the null at the end of the char[].
+ static const size_t checksumLength = 32;
+
+ bytesToAdd.append(textCommentPrefix, prefixLength);
+ bytesToAdd.append(checksum, checksumLength);
+
+ Vector<unsigned char> dataToCrc;
+ dataToCrc.append(textCommentPrefix + 4, prefixLength - 4); // Don't include the chunk length in the crc.
+ dataToCrc.append(checksum, checksumLength);
+ unsigned crc32 = computeCrc(dataToCrc);
+
+ appendIntToVector(crc32, bytesToAdd);
+}
+
+static size_t offsetAfterIHDRChunk(const unsigned char* data, const size_t dataLength)
+{
+ const int pngHeaderLength = 8;
+ const int pngIHDRChunkLength = 25; // chunk length + "IHDR" + 13 bytes of data + checksum
+ return pngHeaderLength + pngIHDRChunkLength;
+}
+
+void printPNG(const unsigned char* data, const size_t dataLength, const char* checksum)
+{
+ Vector<unsigned char> bytesToAdd;
+ convertChecksumToPNGComment(checksum, bytesToAdd);
+
+ printf("Content-Type: %s\n", "image/png");
+ printf("Content-Length: %lu\n", static_cast<unsigned long>(dataLength + bytesToAdd.size()));
+
+ size_t insertOffset = offsetAfterIHDRChunk(data, dataLength);
+
+ fwrite(data, 1, insertOffset, stdout);
+ fwrite(bytesToAdd.data(), 1, bytesToAdd.size(), stdout);
+
+ const size_t bytesToWriteInOneChunk = 1 << 15;
+ data += insertOffset;
+ size_t dataRemainingToWrite = dataLength - insertOffset;
+ while (dataRemainingToWrite) {
+ size_t bytesToWriteInThisChunk = std::min(dataRemainingToWrite, bytesToWriteInOneChunk);
+ size_t bytesWritten = fwrite(data, 1, bytesToWriteInThisChunk, stdout);
+ if (bytesWritten != bytesToWriteInThisChunk)
+ break;
+ dataRemainingToWrite -= bytesWritten;
+ data += bytesWritten;
+ }
+}
diff --git a/Tools/DumpRenderTree/PixelDumpSupport.h b/Tools/DumpRenderTree/PixelDumpSupport.h
new file mode 100644
index 000000000..87e640243
--- /dev/null
+++ b/Tools/DumpRenderTree/PixelDumpSupport.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PixelDumpSupport_h
+#define PixelDumpSupport_h
+
+#include <string>
+
+#include <wtf/PassRefPtr.h>
+
+class BitmapContext;
+
+void computeMD5HashStringForBitmapContext(BitmapContext*, char hashString[33]);
+PassRefPtr<BitmapContext> createPagedBitmapContext();
+PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect);
+void dumpBitmap(BitmapContext*, const char* checksum);
+void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash);
+void printPNG(const unsigned char* data, const size_t dataLength, const char* checksum);
+
+#if PLATFORM(MAC)
+
+// Can be used as a signal handler
+void restoreMainDisplayColorProfile(int ignored);
+
+// May change your color space, requiring a call to restoreMainDisplayColorProfile
+void setupMainDisplayColorProfile();
+
+#endif
+
+#endif // PixelDumpSupport_h
diff --git a/Tools/DumpRenderTree/StorageTrackerDelegate.h b/Tools/DumpRenderTree/StorageTrackerDelegate.h
new file mode 100644
index 000000000..e025a4476
--- /dev/null
+++ b/Tools/DumpRenderTree/StorageTrackerDelegate.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+class LayoutTestController;
+
+@interface StorageTrackerDelegate : NSObject {
+ unsigned numberOfNotificationsToLog;
+ LayoutTestController* controllerToNotifyDone;
+}
+
+- (void)logNotifications:(unsigned)number controller:(LayoutTestController*)controller;
+- (void)originModified:(NSNotification *)notification;
+- (void)setControllerToNotifyDone:(LayoutTestController*)controller;
+
+@end
diff --git a/Tools/DumpRenderTree/StorageTrackerDelegate.mm b/Tools/DumpRenderTree/StorageTrackerDelegate.mm
new file mode 100644
index 000000000..343880ba1
--- /dev/null
+++ b/Tools/DumpRenderTree/StorageTrackerDelegate.mm
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "StorageTrackerDelegate.h"
+
+#import "LayoutTestController.h"
+#import <WebKit/WebSecurityOriginPrivate.h>
+#import <WebKit/WebStorageManagerPrivate.h>
+
+@implementation StorageTrackerDelegate
+
+- (id)init
+{
+ self = [super init];
+ if (!self)
+ return nil;
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(originModified:) name:WebStorageDidModifyOriginNotification object:nil];
+
+ return self;
+}
+
+- (void)logNotifications:(unsigned)number controller:(LayoutTestController*)controller
+{
+ controllerToNotifyDone = controller;
+
+ numberOfNotificationsToLog = number;
+}
+
+- (void)originModified:(NSNotification *)notification
+{
+ if (!numberOfNotificationsToLog)
+ return;
+
+ numberOfNotificationsToLog--;
+
+ if (numberOfNotificationsToLog == 0 && controllerToNotifyDone) {
+ NSArray *origins = [[WebStorageManager sharedWebStorageManager] origins];
+ for (WebSecurityOrigin *origin in origins)
+ printf("Origin identifier: '%s'\n", [[origin databaseIdentifier] UTF8String]);
+
+ controllerToNotifyDone->notifyDone();
+ }
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:WebStorageDidModifyOriginNotification object:nil];
+
+ [super dealloc];
+}
+
+- (void)setControllerToNotifyDone:(LayoutTestController*)controller
+{
+ controllerToNotifyDone = controller;
+}
+
+
+@end
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
new file mode 100644
index 000000000..544218015
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
@@ -0,0 +1,1267 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginObject.h"
+
+#include "PluginTest.h"
+#include "TestObject.h"
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Helper function which takes in the plugin window object for logging to the console object.
+static void pluginLogWithWindowObject(NPObject* windowObject, NPP instance, const char* message)
+{
+ NPVariant consoleVariant;
+ if (!browser->getproperty(instance, windowObject, browser->getstringidentifier("console"), &consoleVariant)) {
+ fprintf(stderr, "Failed to retrieve console object while logging: %s\n", message);
+ return;
+ }
+
+ NPObject* consoleObject = NPVARIANT_TO_OBJECT(consoleVariant);
+
+ NPVariant messageVariant;
+ STRINGZ_TO_NPVARIANT(message, messageVariant);
+
+ NPVariant result;
+ if (!browser->invoke(instance, consoleObject, browser->getstringidentifier("log"), &messageVariant, 1, &result)) {
+ fprintf(stderr, "Failed to invoke console.log while logging: %s\n", message);
+ browser->releaseobject(consoleObject);
+ return;
+ }
+
+ browser->releasevariantvalue(&result);
+ browser->releaseobject(consoleObject);
+}
+
+// Helper function which takes in the plugin window object for logging to the console object. This function supports variable
+// arguments.
+static void pluginLogWithWindowObjectVariableArgs(NPObject* windowObject, NPP instance, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ char message[2048] = "PLUGIN: ";
+ vsprintf(message + strlen(message), format, args);
+ va_end(args);
+
+ pluginLogWithWindowObject(windowObject, instance, message);
+}
+
+void pluginLogWithArguments(NPP instance, const char* format, va_list args)
+{
+ char message[2048] = "PLUGIN: ";
+ vsprintf(message + strlen(message), format, args);
+
+ NPObject* windowObject = 0;
+ NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
+ if (error != NPERR_NO_ERROR) {
+ fprintf(stderr, "Failed to retrieve window object while logging: %s\n", message);
+ return;
+ }
+
+ pluginLogWithWindowObject(windowObject, instance, message);
+ browser->releaseobject(windowObject);
+}
+
+// Helper function to log to the console object.
+void pluginLog(NPP instance, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ pluginLogWithArguments(instance, format, args);
+ va_end(args);
+}
+
+static void pluginInvalidate(NPObject*);
+static bool pluginHasProperty(NPObject*, NPIdentifier name);
+static bool pluginHasMethod(NPObject*, NPIdentifier name);
+static bool pluginGetProperty(NPObject*, NPIdentifier name, NPVariant*);
+static bool pluginSetProperty(NPObject*, NPIdentifier name, const NPVariant*);
+static bool pluginInvoke(NPObject*, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static NPObject* pluginAllocate(NPP npp, NPClass*);
+static void pluginDeallocate(NPObject*);
+
+NPNetscapeFuncs* browser;
+NPPluginFuncs* pluginFunctions;
+
+static NPClass pluginClass = {
+ NP_CLASS_STRUCT_VERSION,
+ pluginAllocate,
+ pluginDeallocate,
+ pluginInvalidate,
+ pluginHasMethod,
+ pluginInvoke,
+ 0, // NPClass::invokeDefault,
+ pluginHasProperty,
+ pluginGetProperty,
+ pluginSetProperty,
+ 0, // NPClass::removeProperty
+ 0, // NPClass::enumerate
+ 0, // NPClass::construct
+};
+
+NPClass* getPluginClass(void)
+{
+ return &pluginClass;
+}
+
+static bool identifiersInitialized = false;
+
+enum {
+ ID_PROPERTY_PROPERTY = 0,
+ ID_PROPERTY_EVENT_LOGGING,
+ ID_PROPERTY_HAS_STREAM,
+ ID_PROPERTY_TEST_OBJECT,
+ ID_PROPERTY_LOG_DESTROY,
+ ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM,
+ ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE,
+ ID_PROPERTY_THROW_EXCEPTION_PROPERTY,
+ ID_LAST_SET_WINDOW_ARGUMENTS,
+ ID_PROPERTY_WINDOWED_PLUGIN,
+ ID_PROPERTY_TEST_OBJECT_COUNT,
+ NUM_PROPERTY_IDENTIFIERS
+};
+
+static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
+static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
+ "property",
+ "eventLoggingEnabled",
+ "hasStream",
+ "testObject",
+ "logDestroy",
+ "returnErrorFromNewStream",
+ "returnNegativeOneFromWrite",
+ "testThrowExceptionProperty",
+ "lastSetWindowArguments",
+ "windowedPlugin",
+ "testObjectCount",
+};
+
+enum {
+ ID_TEST_CALLBACK_METHOD = 0,
+ ID_TEST_CALLBACK_METHOD_RETURN,
+ ID_TEST_GETURL,
+ ID_TEST_DOM_ACCESS,
+ ID_TEST_GET_URL_NOTIFY,
+ ID_TEST_INVOKE_DEFAULT,
+ ID_DESTROY_STREAM,
+ ID_TEST_ENUMERATE,
+ ID_TEST_GETINTIDENTIFIER,
+ ID_TEST_GET_PROPERTY,
+ ID_TEST_HAS_PROPERTY,
+ ID_TEST_HAS_METHOD,
+ ID_TEST_EVALUATE,
+ ID_TEST_GET_PROPERTY_RETURN_VALUE,
+ ID_TEST_IDENTIFIER_TO_STRING,
+ ID_TEST_IDENTIFIER_TO_INT,
+ ID_TEST_PASS_TEST_OBJECT,
+ ID_TEST_POSTURL_FILE,
+ ID_TEST_CONSTRUCT,
+ ID_TEST_THROW_EXCEPTION_METHOD,
+ ID_TEST_FAIL_METHOD,
+ ID_TEST_CLONE_OBJECT,
+ ID_TEST_SCRIPT_OBJECT_INVOKE,
+ ID_TEST_CREATE_TEST_OBJECT,
+ ID_DESTROY_NULL_STREAM,
+ ID_TEST_RELOAD_PLUGINS_NO_PAGES,
+ ID_TEST_RELOAD_PLUGINS_AND_PAGES,
+ ID_TEST_GET_BROWSER_PROPERTY,
+ ID_TEST_SET_BROWSER_PROPERTY,
+ ID_REMEMBER,
+ ID_GET_REMEMBERED_OBJECT,
+ ID_GET_AND_FORGET_REMEMBERED_OBJECT,
+ ID_REF_COUNT,
+ ID_SET_STATUS,
+ ID_RESIZE_TO,
+ ID_NORMALIZE,
+ ID_INVALIDATE_RECT,
+ ID_OBJECTS_ARE_SAME,
+ NUM_METHOD_IDENTIFIERS
+};
+
+static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
+static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
+ "testCallback",
+ "testCallbackReturn",
+ "getURL",
+ "testDOMAccess",
+ "getURLNotify",
+ "testInvokeDefault",
+ "destroyStream",
+ "testEnumerate",
+ "testGetIntIdentifier",
+ "testGetProperty",
+ "testHasProperty",
+ "testHasMethod",
+ "testEvaluate",
+ "testGetPropertyReturnValue",
+ "testIdentifierToString",
+ "testIdentifierToInt",
+ "testPassTestObject",
+ "testPostURLFile",
+ "testConstruct",
+ "testThrowException",
+ "testFail",
+ "testCloneObject",
+ "testScriptObjectInvoke",
+ "testCreateTestObject",
+ "destroyNullStream",
+ "reloadPluginsNoPages",
+ "reloadPluginsAndPages",
+ "testGetBrowserProperty",
+ "testSetBrowserProperty",
+ "remember",
+ "getRememberedObject",
+ "getAndForgetRememberedObject",
+ "refCount",
+ "setStatus",
+ "resizeTo",
+ "normalize",
+ "invalidateRect",
+ "objectsAreSame"
+};
+
+static NPUTF8* createCStringFromNPVariant(const NPVariant* variant)
+{
+ size_t length = NPVARIANT_TO_STRING(*variant).UTF8Length;
+ NPUTF8* result = (NPUTF8*)malloc(length + 1);
+ memcpy(result, NPVARIANT_TO_STRING(*variant).UTF8Characters, length);
+ result[length] = '\0';
+ return result;
+}
+
+static void initializeIdentifiers(void)
+{
+ browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers);
+ browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers);
+}
+
+static bool pluginHasProperty(NPObject *obj, NPIdentifier name)
+{
+ for (int i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++)
+ if (name == pluginPropertyIdentifiers[i])
+ return true;
+ return false;
+}
+
+static bool pluginHasMethod(NPObject *obj, NPIdentifier name)
+{
+ for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++)
+ if (name == pluginMethodIdentifiers[i])
+ return true;
+ return false;
+}
+
+static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* result)
+{
+ PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_PROPERTY]) {
+ static const char* originalString = "property";
+ char* buf = static_cast<char*>(browser->memalloc(strlen(originalString) + 1));
+ strcpy(buf, originalString);
+ STRINGZ_TO_NPVARIANT(buf, *result);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
+ BOOLEAN_TO_NPVARIANT(plugin->eventLogging, *result);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
+ BOOLEAN_TO_NPVARIANT(plugin->logDestroy, *result);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) {
+ BOOLEAN_TO_NPVARIANT(plugin->stream, *result);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) {
+ NPObject* testObject = plugin->testObject;
+ browser->retainobject(testObject);
+ OBJECT_TO_NPVARIANT(testObject, *result);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) {
+ BOOLEAN_TO_NPVARIANT(plugin->returnErrorFromNewStream, *result);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) {
+ BOOLEAN_TO_NPVARIANT(plugin->returnNegativeOneFromWrite, *result);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) {
+ browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS");
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_LAST_SET_WINDOW_ARGUMENTS]) {
+ char* buf = static_cast<char*>(browser->memalloc(256));
+ snprintf(buf, 256, "x: %d, y: %d, width: %u, height: %u, clipRect: (%u, %u, %u, %u)", (int)plugin->lastWindow.x, (int)plugin->lastWindow.y, (unsigned)plugin->lastWindow.width, (unsigned)plugin->lastWindow.height,
+ plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.top, plugin->lastWindow.clipRect.right - plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.bottom - plugin->lastWindow.clipRect.top);
+
+ STRINGZ_TO_NPVARIANT(buf, *result);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT_COUNT]) {
+ INT32_TO_NPVARIANT(getTestObjectCount(), *result);
+ return true;
+ }
+
+ return false;
+}
+
+static bool pluginSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant)
+{
+ PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
+ plugin->eventLogging = NPVARIANT_TO_BOOLEAN(*variant);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
+ plugin->logDestroy = NPVARIANT_TO_BOOLEAN(*variant);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) {
+ plugin->returnErrorFromNewStream = NPVARIANT_TO_BOOLEAN(*variant);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) {
+ plugin->returnNegativeOneFromWrite = NPVARIANT_TO_BOOLEAN(*variant);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) {
+ browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS");
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_WINDOWED_PLUGIN]) {
+ browser->setvalue(plugin->npp, NPPVpluginWindowBool, (void *)NPVARIANT_TO_BOOLEAN(*variant));
+ return true;
+ }
+
+ return false;
+}
+
+static bool testDOMAccess(PluginObject* obj, const NPVariant*, uint32_t, NPVariant* result)
+{
+ // Get plug-in's DOM element
+ NPObject* elementObject;
+ if (browser->getvalue(obj->npp, NPNVPluginElementNPObject, &elementObject) == NPERR_NO_ERROR) {
+ // Get style
+ NPVariant styleVariant;
+ NPIdentifier styleIdentifier = browser->getstringidentifier("style");
+ if (browser->getproperty(obj->npp, elementObject, styleIdentifier, &styleVariant) && NPVARIANT_IS_OBJECT(styleVariant)) {
+ // Set style.border
+ NPIdentifier borderIdentifier = browser->getstringidentifier("border");
+ NPVariant borderVariant;
+ STRINGZ_TO_NPVARIANT("3px solid red", borderVariant);
+ browser->setproperty(obj->npp, NPVARIANT_TO_OBJECT(styleVariant), borderIdentifier, &borderVariant);
+ browser->releasevariantvalue(&styleVariant);
+ }
+
+ browser->releaseobject(elementObject);
+ }
+ VOID_TO_NPVARIANT(*result);
+ return true;
+}
+
+static NPIdentifier stringVariantToIdentifier(NPVariant variant)
+{
+ assert(NPVARIANT_IS_STRING(variant));
+ NPUTF8* utf8String = createCStringFromNPVariant(&variant);
+ NPIdentifier identifier = browser->getstringidentifier(utf8String);
+ free(utf8String);
+ return identifier;
+}
+
+static NPIdentifier int32VariantToIdentifier(NPVariant variant)
+{
+ assert(NPVARIANT_IS_INT32(variant));
+ int32_t integer = NPVARIANT_TO_INT32(variant);
+ return browser->getintidentifier(integer);
+}
+
+static NPIdentifier doubleVariantToIdentifier(NPVariant variant)
+{
+ assert(NPVARIANT_IS_DOUBLE(variant));
+ double value = NPVARIANT_TO_DOUBLE(variant);
+ // Sadly there is no "getdoubleidentifier"
+ int32_t integer = static_cast<int32_t>(value);
+ return browser->getintidentifier(integer);
+}
+
+static NPIdentifier variantToIdentifier(NPVariant variant)
+{
+ if (NPVARIANT_IS_STRING(variant))
+ return stringVariantToIdentifier(variant);
+ if (NPVARIANT_IS_INT32(variant))
+ return int32VariantToIdentifier(variant);
+ if (NPVARIANT_IS_DOUBLE(variant))
+ return doubleVariantToIdentifier(variant);
+ return 0;
+}
+
+static bool testIdentifierToString(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 1)
+ return true;
+ NPIdentifier identifier = variantToIdentifier(args[0]);
+ if (!identifier)
+ return true;
+ NPUTF8* utf8String = browser->utf8fromidentifier(identifier);
+ if (!utf8String)
+ return true;
+ STRINGZ_TO_NPVARIANT(utf8String, *result);
+ return true;
+}
+
+static bool testIdentifierToInt(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 1)
+ return false;
+ NPIdentifier identifier = variantToIdentifier(args[0]);
+ if (!identifier)
+ return false;
+ int32_t integer = browser->intfromidentifier(identifier);
+ INT32_TO_NPVARIANT(integer, *result);
+ return true;
+}
+
+static bool testPassTestObject(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 2 || !NPVARIANT_IS_STRING(args[0]))
+ return false;
+
+ NPObject* windowScriptObject;
+ browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
+
+ NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
+ NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
+ free(callbackString);
+
+ NPVariant browserResult;
+ browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, &args[1], 1, &browserResult);
+ browser->releasevariantvalue(&browserResult);
+
+ VOID_TO_NPVARIANT(*result);
+ return true;
+}
+
+static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (!argCount || !NPVARIANT_IS_STRING(args[0]))
+ return false;
+
+ NPObject* windowScriptObject;
+ browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
+
+ NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
+ NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
+ free(callbackString);
+
+ NPVariant browserResult;
+ if (browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult))
+ browser->releasevariantvalue(&browserResult);
+
+ browser->releaseobject(windowScriptObject);
+
+ VOID_TO_NPVARIANT(*result);
+ return true;
+}
+
+static bool testCallbackReturn(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
+ return false;
+
+ NPObject* windowScriptObject;
+ browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
+
+ NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
+ NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
+ free(callbackString);
+
+ NPVariant callbackArgs[1];
+ OBJECT_TO_NPVARIANT(windowScriptObject, callbackArgs[0]);
+
+ NPVariant browserResult;
+ browser->invoke(obj->npp, windowScriptObject, callbackIdentifier,
+ callbackArgs, 1, &browserResult);
+
+ if (NPVARIANT_IS_OBJECT(browserResult))
+ OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(browserResult), *result);
+ else {
+ browser->releasevariantvalue(&browserResult);
+ VOID_TO_NPVARIANT(*result);
+ }
+
+ return true;
+}
+
+static bool getURL(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount == 2 && NPVARIANT_IS_STRING(args[0]) && NPVARIANT_IS_STRING(args[1])) {
+ NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
+ NPUTF8* targetString = createCStringFromNPVariant(&args[1]);
+ NPError npErr = browser->geturl(obj->npp, urlString, targetString);
+ free(urlString);
+ free(targetString);
+
+ INT32_TO_NPVARIANT(npErr, *result);
+ return true;
+ }
+ if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) {
+ NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
+ NPError npErr = browser->geturl(obj->npp, urlString, 0);
+ free(urlString);
+
+ INT32_TO_NPVARIANT(npErr, *result);
+ return true;
+ }
+ return false;
+}
+
+static bool getURLNotify(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 3 || !NPVARIANT_IS_STRING(args[0])
+ || (!NPVARIANT_IS_STRING(args[1]) && !NPVARIANT_IS_NULL(args[1]))
+ || !NPVARIANT_IS_STRING(args[2]))
+ return false;
+
+ NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
+ NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : 0);
+ NPUTF8* callbackString = createCStringFromNPVariant(&args[2]);
+
+ NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
+ browser->geturlnotify(obj->npp, urlString, targetString, callbackIdentifier);
+
+ free(urlString);
+ free(targetString);
+ free(callbackString);
+
+ VOID_TO_NPVARIANT(*result);
+ return true;
+}
+
+static bool testInvokeDefault(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (!NPVARIANT_IS_OBJECT(args[0]))
+ return false;
+
+ NPObject* callback = NPVARIANT_TO_OBJECT(args[0]);
+
+ NPVariant invokeArgs[1];
+ NPVariant browserResult;
+
+ STRINGZ_TO_NPVARIANT("test", invokeArgs[0]);
+ bool retval = browser->invokeDefault(obj->npp, callback, invokeArgs, 1, &browserResult);
+
+ if (retval)
+ browser->releasevariantvalue(&browserResult);
+
+ BOOLEAN_TO_NPVARIANT(retval, *result);
+ return true;
+}
+
+static bool destroyStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ NPError npError = browser->destroystream(obj->npp, obj->stream, NPRES_USER_BREAK);
+ INT32_TO_NPVARIANT(npError, *result);
+ return true;
+}
+
+static bool destroyNullStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ NPError npError = browser->destroystream(obj->npp, 0, NPRES_USER_BREAK);
+ INT32_TO_NPVARIANT(npError, *result);
+ return true;
+}
+
+static bool testEnumerate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1]))
+ return false;
+
+ uint32_t count;
+ NPIdentifier* identifiers;
+ if (browser->enumerate(obj->npp, NPVARIANT_TO_OBJECT(args[0]), &identifiers, &count)) {
+ NPObject* outArray = NPVARIANT_TO_OBJECT(args[1]);
+ NPIdentifier pushIdentifier = browser->getstringidentifier("push");
+
+ for (uint32_t i = 0; i < count; i++) {
+ NPUTF8* string = browser->utf8fromidentifier(identifiers[i]);
+
+ if (!string)
+ continue;
+
+ NPVariant args[1];
+ STRINGZ_TO_NPVARIANT(string, args[0]);
+ NPVariant browserResult;
+ if (browser->invoke(obj->npp, outArray, pushIdentifier, args, 1, &browserResult))
+ browser->releasevariantvalue(&browserResult);
+ browser->memfree(string);
+ }
+
+ browser->memfree(identifiers);
+ }
+
+ VOID_TO_NPVARIANT(*result);
+ return true;
+}
+
+static bool testGetIntIdentifier(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 1 || !NPVARIANT_IS_DOUBLE(args[0]))
+ return false;
+
+ NPIdentifier identifier = browser->getintidentifier((int)NPVARIANT_TO_DOUBLE(args[0]));
+ INT32_TO_NPVARIANT((int32_t)(long long)identifier, *result);
+ return true;
+}
+
+static bool testGetProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (!argCount)
+ return false;
+
+ NPObject* object;
+ browser->getvalue(obj->npp, NPNVWindowNPObject, &object);
+
+ for (uint32_t i = 0; i < argCount; i++) {
+ assert(NPVARIANT_IS_STRING(args[i]));
+ NPUTF8* propertyString = createCStringFromNPVariant(&args[i]);
+ NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
+ free(propertyString);
+
+ NPVariant variant;
+ bool retval = browser->getproperty(obj->npp, object, propertyIdentifier, &variant);
+ browser->releaseobject(object);
+
+ if (!retval)
+ break;
+
+ if (i + 1 < argCount) {
+ assert(NPVARIANT_IS_OBJECT(variant));
+ object = NPVARIANT_TO_OBJECT(variant);
+ } else {
+ *result = variant;
+ return true;
+ }
+ }
+
+ VOID_TO_NPVARIANT(*result);
+ return false;
+}
+
+static bool testHasProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
+ return false;
+
+ NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
+ NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
+ free(propertyString);
+
+ bool retval = browser->hasproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier);
+
+ BOOLEAN_TO_NPVARIANT(retval, *result);
+ return true;
+}
+
+static bool testHasMethod(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
+ return false;
+
+ NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
+ NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
+ free(propertyString);
+
+ bool retval = browser->hasmethod(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier);
+
+ BOOLEAN_TO_NPVARIANT(retval, *result);
+ return true;
+}
+
+static bool testEvaluate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
+ return false;
+ NPObject* windowScriptObject;
+ browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
+
+ NPString s = NPVARIANT_TO_STRING(args[0]);
+
+ bool retval = browser->evaluate(obj->npp, windowScriptObject, &s, result);
+ browser->releaseobject(windowScriptObject);
+ return retval;
+}
+
+static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
+ return false;
+
+ NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
+ NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
+ free(propertyString);
+
+ NPVariant variant;
+ bool retval = browser->getproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier, &variant);
+ if (retval)
+ browser->releasevariantvalue(&variant);
+
+ BOOLEAN_TO_NPVARIANT(retval, *result);
+ return true;
+}
+
+static char* toCString(const NPString& string)
+{
+ char* result = static_cast<char*>(malloc(string.UTF8Length + 1));
+ memcpy(result, string.UTF8Characters, string.UTF8Length);
+ result[string.UTF8Length] = '\0';
+
+ return result;
+}
+
+static bool testPostURLFile(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 4 || !NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1]) || !NPVARIANT_IS_STRING(args[2]) || !NPVARIANT_IS_STRING(args[3]))
+ return false;
+
+ NPString urlString = NPVARIANT_TO_STRING(args[0]);
+ char* url = toCString(urlString);
+
+ NPString targetString = NPVARIANT_TO_STRING(args[1]);
+ char* target = toCString(targetString);
+
+ NPString pathString = NPVARIANT_TO_STRING(args[2]);
+ char* path = toCString(pathString);
+
+ NPString contentsString = NPVARIANT_TO_STRING(args[3]);
+
+ FILE* tempFile = fopen(path, "w");
+ if (!tempFile)
+ return false;
+
+ if (!fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile))
+ return false;
+
+ fclose(tempFile);
+
+ NPError error = browser->posturl(obj->npp, url, target, pathString.UTF8Length, path, TRUE);
+
+ free(path);
+ free(target);
+ free(url);
+
+ BOOLEAN_TO_NPVARIANT(error == NPERR_NO_ERROR, *result);
+ return true;
+}
+
+static bool testConstruct(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (!argCount || !NPVARIANT_IS_OBJECT(args[0]))
+ return false;
+
+ return browser->construct(obj->npp, NPVARIANT_TO_OBJECT(args[0]), args + 1, argCount - 1, result);
+}
+
+// Invoke a script callback to get a script NPObject. Then call a method on the
+// script NPObject passing it a freshly created NPObject.
+static bool testScriptObjectInvoke(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 2 || !NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1]))
+ return false;
+ NPObject* windowScriptObject;
+ browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
+
+ // Arg1 is the name of the callback
+ NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
+ NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
+ free(callbackString);
+
+ // Invoke a callback that returns a script object
+ NPVariant object_result;
+ browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, &args[1], 1, &object_result);
+
+ // Script object returned
+ NPObject* script_object = object_result.value.objectValue;
+
+ // Arg2 is the name of the method to be called on the script object
+ NPUTF8* object_mehod_string = createCStringFromNPVariant(&args[1]);
+ NPIdentifier object_method = browser->getstringidentifier(object_mehod_string);
+ free(object_mehod_string);
+
+ // Create a fresh NPObject to be passed as an argument
+ NPObject* object_arg = browser->createobject(obj->npp, &pluginClass);
+ NPVariant invoke_args[1];
+ OBJECT_TO_NPVARIANT(object_arg, invoke_args[0]);
+
+ // Invoke the script method
+ NPVariant object_method_result;
+ browser->invoke(obj->npp, script_object, object_method, invoke_args, 1, &object_method_result);
+
+ browser->releasevariantvalue(&object_result);
+ VOID_TO_NPVARIANT(*result);
+ if (NPVARIANT_IS_OBJECT(object_method_result)) {
+ // Now return the callbacks return value back to our caller.
+ // BUG 897451: This should be the same as the
+ // windowScriptObject, but its not (in Chrome) - or at least, it
+ // has a different refcount. This means Chrome will delete the
+ // object before returning it and the calling JS gets a garbage
+ // value. Firefox handles it fine.
+ OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(object_method_result), *result);
+ } else {
+ browser->releasevariantvalue(&object_method_result);
+ VOID_TO_NPVARIANT(*result);
+ }
+
+ browser->releaseobject(object_arg);
+
+ return true;
+}
+
+// Helper function to notify the layout test controller that the test completed.
+void notifyTestCompletion(NPP npp, NPObject* object)
+{
+ NPVariant result;
+ NPString script;
+ script.UTF8Characters = "javascript:window.layoutTestController.notifyDone();";
+ script.UTF8Length = strlen("javascript:window.layoutTestController.notifyDone();");
+ browser->evaluate(npp, object, &script, &result);
+ browser->releasevariantvalue(&result);
+}
+
+bool testDocumentOpen(NPP npp)
+{
+ NPIdentifier documentId = browser->getstringidentifier("document");
+ NPIdentifier openId = browser->getstringidentifier("open");
+
+ NPObject* windowObject = 0;
+ browser->getvalue(npp, NPNVWindowNPObject, &windowObject);
+ if (!windowObject)
+ return false;
+
+ NPVariant docVariant;
+ browser->getproperty(npp, windowObject, documentId, &docVariant);
+ if (docVariant.type != NPVariantType_Object) {
+ browser->releaseobject(windowObject);
+ return false;
+ }
+
+ NPObject* documentObject = NPVARIANT_TO_OBJECT(docVariant);
+
+ NPVariant openArgs[2];
+ STRINGZ_TO_NPVARIANT("text/html", openArgs[0]);
+ STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
+
+ NPVariant result;
+ if (!browser->invoke(npp, documentObject, openId, openArgs, 2, &result)) {
+ browser->releaseobject(windowObject);
+ browser->releaseobject(documentObject);
+ return false;
+ }
+
+ browser->releaseobject(documentObject);
+
+ if (result.type != NPVariantType_Object) {
+ browser->releaseobject(windowObject);
+ browser->releasevariantvalue(&result);
+ return false;
+ }
+
+ pluginLogWithWindowObjectVariableArgs(windowObject, npp, "DOCUMENT OPEN SUCCESS");
+ notifyTestCompletion(npp, result.value.objectValue);
+ browser->releaseobject(result.value.objectValue);
+ browser->releaseobject(windowObject);
+ return true;
+}
+
+bool testWindowOpen(NPP npp)
+{
+ NPIdentifier openId = browser->getstringidentifier("open");
+
+ NPObject* windowObject = 0;
+ browser->getvalue(npp, NPNVWindowNPObject, &windowObject);
+ if (!windowObject)
+ return false;
+
+ NPVariant openArgs[2];
+ STRINGZ_TO_NPVARIANT("about:blank", openArgs[0]);
+ STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
+
+ NPVariant result;
+ if (!browser->invoke(npp, windowObject, openId, openArgs, 2, &result)) {
+ browser->releaseobject(windowObject);
+ return false;
+ }
+
+ if (result.type != NPVariantType_Object) {
+ browser->releaseobject(windowObject);
+ browser->releasevariantvalue(&result);
+ return false;
+ }
+
+ pluginLogWithWindowObjectVariableArgs(windowObject, npp, "WINDOW OPEN SUCCESS");
+ notifyTestCompletion(npp, result.value.objectValue);
+ browser->releaseobject(result.value.objectValue);
+ browser->releaseobject(windowObject);
+ return true;
+}
+
+static bool testSetStatus(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ char* message = 0;
+ if (argCount && NPVARIANT_IS_STRING(args[0])) {
+ NPString statusString = NPVARIANT_TO_STRING(args[0]);
+ message = toCString(statusString);
+ }
+
+ browser->status(obj->npp, message);
+
+ free(message);
+ return true;
+}
+
+static bool testResizeTo(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ VOID_TO_NPVARIANT(*result);
+
+ NPObject* windowObject;
+ if (NPERR_NO_ERROR != browser->getvalue(obj->npp, NPNVWindowNPObject, &windowObject))
+ return false;
+
+ NPVariant callResult;
+ if (browser->invoke(obj->npp, windowObject, browser->getstringidentifier("resizePlugin"), args, argCount, &callResult))
+ browser->releasevariantvalue(&callResult);
+
+ // Force layout.
+ if (browser->getproperty(obj->npp, windowObject, browser->getstringidentifier("pageYOffset"), &callResult))
+ browser->releasevariantvalue(&callResult);
+
+ return true;
+}
+
+static bool normalizeOverride(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ VOID_TO_NPVARIANT(*result);
+
+ NPObject* windowObject;
+ if (NPERR_NO_ERROR != browser->getvalue(obj->npp, NPNVWindowNPObject, &windowObject))
+ return false;
+
+ NPVariant callResult;
+ if (browser->invoke(obj->npp, windowObject, browser->getstringidentifier("pluginCallback"), args, argCount, &callResult))
+ browser->releasevariantvalue(&callResult);
+
+ return true;
+}
+
+static bool invalidateRect(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 4)
+ return false;
+
+ NPRect rect;
+ rect.left = static_cast<int>(NPVARIANT_TO_DOUBLE(args[0]));
+ rect.top = static_cast<int>(NPVARIANT_TO_DOUBLE(args[1]));
+ rect.right = static_cast<int>(NPVARIANT_TO_DOUBLE(args[2]));
+ rect.bottom = static_cast<int>(NPVARIANT_TO_DOUBLE(args[3]));
+
+ browser->invalidaterect(obj->npp, &rect);
+ return true;
+}
+
+static bool objectsAreSame(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1]))
+ return false;
+
+ BOOLEAN_TO_NPVARIANT(NPVARIANT_TO_OBJECT(args[0]) == NPVARIANT_TO_OBJECT(args[1]), *result);
+ return true;
+}
+
+static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
+ if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD])
+ return testCallback(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD_RETURN])
+ return testCallbackReturn(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_GETURL])
+ return getURL(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_DOM_ACCESS])
+ return testDOMAccess(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_GET_URL_NOTIFY])
+ return getURLNotify(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_INVOKE_DEFAULT])
+ return testInvokeDefault(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_ENUMERATE])
+ return testEnumerate(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_DESTROY_STREAM])
+ return destroyStream(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_GETINTIDENTIFIER])
+ return testGetIntIdentifier(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE])
+ return testEvaluate(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY])
+ return testGetProperty(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY_RETURN_VALUE])
+ return testGetPropertyReturnValue(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_HAS_PROPERTY])
+ return testHasProperty(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_HAS_METHOD])
+ return testHasMethod(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_STRING])
+ return testIdentifierToString(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_INT])
+ return testIdentifierToInt(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_PASS_TEST_OBJECT])
+ return testPassTestObject(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_POSTURL_FILE])
+ return testPostURLFile(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_CONSTRUCT])
+ return testConstruct(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_SCRIPT_OBJECT_INVOKE])
+ return testScriptObjectInvoke(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_THROW_EXCEPTION_METHOD]) {
+ browser->setexception(header, "plugin object testThrowException SUCCESS");
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_TEST_FAIL_METHOD]) {
+ NPObject* windowScriptObject;
+ browser->getvalue(plugin->npp, NPNVWindowNPObject, &windowScriptObject);
+ browser->invoke(plugin->npp, windowScriptObject, name, args, argCount, result);
+ return false;
+ }
+ if (name == pluginMethodIdentifiers[ID_TEST_CLONE_OBJECT]) {
+ NPObject* new_object = browser->createobject(plugin->npp, &pluginClass);
+ assert(new_object->referenceCount == 1);
+ OBJECT_TO_NPVARIANT(new_object, *result);
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_TEST_CREATE_TEST_OBJECT]) {
+ NPObject* testObject = browser->createobject(plugin->npp, getTestClass());
+ assert(testObject->referenceCount == 1);
+ OBJECT_TO_NPVARIANT(testObject, *result);
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_DESTROY_NULL_STREAM])
+ return destroyNullStream(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_NO_PAGES]) {
+ browser->reloadplugins(false);
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_AND_PAGES]) {
+ browser->reloadplugins(true);
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_TEST_GET_BROWSER_PROPERTY]) {
+ browser->getproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), result);
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_TEST_SET_BROWSER_PROPERTY]) {
+ browser->setproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), &args[2]);
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_REMEMBER]) {
+ if (plugin->rememberedObject)
+ browser->releaseobject(plugin->rememberedObject);
+ plugin->rememberedObject = NPVARIANT_TO_OBJECT(args[0]);
+ browser->retainobject(plugin->rememberedObject);
+ VOID_TO_NPVARIANT(*result);
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_GET_REMEMBERED_OBJECT]) {
+ assert(plugin->rememberedObject);
+ browser->retainobject(plugin->rememberedObject);
+ OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result);
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_GET_AND_FORGET_REMEMBERED_OBJECT]) {
+ assert(plugin->rememberedObject);
+ OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result);
+ plugin->rememberedObject = 0;
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_REF_COUNT]) {
+ uint32_t refCount = NPVARIANT_TO_OBJECT(args[0])->referenceCount;
+ INT32_TO_NPVARIANT(refCount, *result);
+ return true;
+ }
+ if (name == pluginMethodIdentifiers[ID_SET_STATUS])
+ return testSetStatus(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_RESIZE_TO])
+ return testResizeTo(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_NORMALIZE])
+ return normalizeOverride(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_INVALIDATE_RECT])
+ return invalidateRect(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_OBJECTS_ARE_SAME])
+ return objectsAreSame(plugin, args, argCount, result);
+
+ return false;
+}
+
+static void pluginInvalidate(NPObject* header)
+{
+ PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
+ plugin->testObject = 0;
+ plugin->rememberedObject = 0;
+}
+
+static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
+{
+ PluginObject* newInstance = (PluginObject*)malloc(sizeof(PluginObject));
+
+ if (!identifiersInitialized) {
+ identifiersInitialized = true;
+ initializeIdentifiers();
+ }
+
+ newInstance->pluginTest = 0;
+ newInstance->npp = npp;
+ newInstance->testObject = browser->createobject(npp, getTestClass());
+ newInstance->rememberedObject = 0;
+ newInstance->eventLogging = FALSE;
+ newInstance->onStreamLoad = 0;
+ newInstance->onStreamDestroy = 0;
+ newInstance->onDestroy = 0;
+ newInstance->onURLNotify = 0;
+ newInstance->onSetWindow = 0;
+ newInstance->onPaintEvent = 0;
+ newInstance->logDestroy = FALSE;
+ newInstance->logSetWindow = FALSE;
+ newInstance->returnErrorFromNewStream = FALSE;
+ newInstance->returnNegativeOneFromWrite = FALSE;
+ newInstance->stream = 0;
+
+ newInstance->firstUrl = 0;
+ newInstance->firstHeaders = 0;
+ newInstance->lastUrl = 0;
+ newInstance->lastHeaders = 0;
+
+ newInstance->testGetURLOnDestroy = FALSE;
+ newInstance->testWindowOpen = FALSE;
+ newInstance->testKeyboardFocusForPlugins = FALSE;
+
+ newInstance->mouseDownForEvaluateScript = FALSE;
+ newInstance->evaluateScriptOnMouseDownOrKeyDown = 0;
+
+ return (NPObject*)newInstance;
+}
+
+static void pluginDeallocate(NPObject* header)
+{
+ PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
+ delete plugin->pluginTest;
+ if (plugin->testObject)
+ browser->releaseobject(plugin->testObject);
+ if (plugin->rememberedObject)
+ browser->releaseobject(plugin->rememberedObject);
+
+ free(plugin->firstUrl);
+ free(plugin->firstHeaders);
+ free(plugin->lastUrl);
+ free(plugin->lastHeaders);
+ free(plugin);
+}
+
+void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData)
+{
+ assert(object);
+
+ NPVariant args[2];
+
+ NPObject* windowScriptObject;
+ browser->getvalue(object->npp, NPNVWindowNPObject, &windowScriptObject);
+
+ NPIdentifier callbackIdentifier = notifyData;
+
+ INT32_TO_NPVARIANT(reason, args[0]);
+
+ char* strHdr = 0;
+ if (object->firstUrl && object->firstHeaders && object->lastUrl && object->lastHeaders) {
+ // Format expected by JavaScript validator: four fields separated by \n\n:
+ // First URL; first header block; last URL; last header block.
+ // Note that header blocks already end with \n due to how NPStream::headers works.
+ int len = strlen(object->firstUrl) + 2
+ + strlen(object->firstHeaders) + 1
+ + strlen(object->lastUrl) + 2
+ + strlen(object->lastHeaders) + 1;
+ strHdr = (char*)malloc(len + 1);
+ snprintf(strHdr, len + 1, "%s\n\n%s\n%s\n\n%s\n",
+ object->firstUrl, object->firstHeaders, object->lastUrl, object->lastHeaders);
+ STRINGN_TO_NPVARIANT(strHdr, len, args[1]);
+ } else
+ NULL_TO_NPVARIANT(args[1]);
+
+ NPVariant browserResult;
+ if (browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult))
+ browser->releasevariantvalue(&browserResult);
+
+ free(strHdr);
+}
+
+void notifyStream(PluginObject* object, const char *url, const char *headers)
+{
+ if (!object->firstUrl) {
+ if (url)
+ object->firstUrl = strdup(url);
+ if (headers)
+ object->firstHeaders = strdup(headers);
+ } else {
+ free(object->lastUrl);
+ free(object->lastHeaders);
+ object->lastUrl = (url ? strdup(url) : 0);
+ object->lastHeaders = (headers ? strdup(headers) : 0);
+ }
+}
+
+void testNPRuntime(NPP npp)
+{
+ NPObject* windowScriptObject;
+ browser->getvalue(npp, NPNVWindowNPObject, &windowScriptObject);
+
+ // Invoke
+ NPIdentifier testNPInvoke = browser->getstringidentifier("testNPInvoke");
+ NPVariant args[7];
+
+ VOID_TO_NPVARIANT(args[0]);
+ NULL_TO_NPVARIANT(args[1]);
+ BOOLEAN_TO_NPVARIANT(true, args[2]);
+ INT32_TO_NPVARIANT(242, args[3]);
+ DOUBLE_TO_NPVARIANT(242.242, args[4]);
+ STRINGZ_TO_NPVARIANT("Hello, World", args[5]);
+ OBJECT_TO_NPVARIANT(windowScriptObject, args[6]);
+
+ NPVariant result;
+ if (browser->invoke(npp, windowScriptObject, testNPInvoke, args, 7, &result))
+ browser->releasevariantvalue(&result);
+
+ browser->releaseobject(windowScriptObject);
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h
new file mode 100644
index 000000000..566537c2e
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginObject_h
+#define PluginObject_h
+
+#include <WebKit/npfunctions.h>
+#include <stdarg.h>
+
+#if defined(XP_MACOSX)
+#if !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+#define BUILDING_ON_LEOPARD 1
+#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+#define BUILDING_ON_SNOW_LEOPARD 1
+#endif
+#endif // XP_MACOSX
+
+class PluginTest;
+
+extern NPNetscapeFuncs *browser;
+extern NPPluginFuncs* pluginFunctions;
+
+typedef struct {
+ NPObject header;
+
+ PluginTest* pluginTest;
+
+ NPP npp;
+ NPBool eventLogging;
+ NPBool logSetWindow;
+ NPBool logDestroy;
+ NPBool returnNegativeOneFromWrite;
+ NPBool returnErrorFromNewStream;
+ NPObject* testObject;
+ NPObject* rememberedObject;
+ NPStream* stream;
+ NPBool testGetURLOnDestroy;
+ NPBool testWindowOpen;
+ NPBool testKeyboardFocusForPlugins;
+ NPBool mouseDownForEvaluateScript;
+ char* onStreamLoad;
+ char* onStreamDestroy;
+ char* onDestroy;
+ char* onURLNotify;
+ char* onSetWindow;
+ char* onPaintEvent;
+ char* firstUrl;
+ char* firstHeaders;
+ char* lastUrl;
+ char* lastHeaders;
+ char* evaluateScriptOnMouseDownOrKeyDown;
+#ifdef XP_MACOSX
+ NPEventModel eventModel;
+#endif
+#ifdef XP_MACOSX
+ void* coreAnimationLayer;
+#endif
+ NPWindow lastWindow;
+} PluginObject;
+
+extern NPClass *getPluginClass(void);
+extern void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData);
+extern void notifyStream(PluginObject* object, const char *url, const char *headers);
+extern void testNPRuntime(NPP npp);
+extern void pluginLog(NPP instance, const char* format, ...);
+extern void pluginLogWithArguments(NPP instance, const char* format, va_list args);
+extern bool testDocumentOpen(NPP npp);
+extern bool testWindowOpen(NPP npp);
+
+#ifdef XP_MACOSX
+extern void* createCoreAnimationLayer();
+#endif
+
+#endif // PluginObject_h
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm
new file mode 100644
index 000000000..e7850e7a9
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginObject.h"
+
+
+#include <QuartzCore/QuartzCore.h>
+
+@interface TestPluginLayer : CALayer
+@end
+
+@implementation TestPluginLayer
+
+- (void)drawInContext:(CGContextRef)context
+{
+ CGRect bounds = [self bounds];
+ const char* text = "Test Plug-in";
+ CGContextSelectFont(context, "Helvetica", 24, kCGEncodingMacRoman);
+ CGContextShowTextAtPoint(context, bounds.origin.x + 3.0f, bounds.origin.y + bounds.size.height - 30.0f, text, strlen(text));
+}
+
+@end
+
+void* createCoreAnimationLayer()
+{
+ CALayer *caLayer = [[TestPluginLayer alloc] init];
+
+ NSNull *nullValue = [NSNull null];
+ NSDictionary *actions = [NSDictionary dictionaryWithObjectsAndKeys:
+ nullValue, @"anchorPoint",
+ nullValue, @"bounds",
+ nullValue, @"contents",
+ nullValue, @"contentsRect",
+ nullValue, @"opacity",
+ nullValue, @"position",
+ nullValue, @"shadowColor",
+ nullValue, @"sublayerTransform",
+ nullValue, @"sublayers",
+ nullValue, @"transform",
+ nullValue, @"zPosition",
+ nil];
+ // Turn off default animations.
+ [caLayer setStyle:[NSDictionary dictionaryWithObject:actions forKey:@"actions"]];
+ [caLayer setNeedsDisplayOnBoundsChange:YES];
+
+ [caLayer setBounds:CGRectMake(0, 0, 200, 100)];
+ [caLayer setAnchorPoint:CGPointZero];
+
+ CGColorRef color = CGColorCreateGenericRGB(0.5, 0.5, 1, 1);
+ [caLayer setBackgroundColor:color];
+ CGColorRelease(color);
+
+ [caLayer setLayoutManager:[CAConstraintLayoutManager layoutManager]];
+
+ CALayer *sublayer = [CALayer layer];
+ // Turn off default animations.
+ [sublayer setStyle:[NSDictionary dictionaryWithObject:actions forKey:@"actions"]];
+
+ color = CGColorCreateGenericRGB(0, 0, 0, 0.75);
+ [sublayer setBackgroundColor:color];
+ CGColorRelease(color);
+ [sublayer setBounds:CGRectMake(0, 0, 180, 20)];
+
+ [sublayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY
+ relativeTo:@"superlayer"
+ attribute:kCAConstraintMinY]];
+ [sublayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinX
+ relativeTo:@"superlayer"
+ attribute:kCAConstraintMinX]];
+ [sublayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxX
+ relativeTo:@"superlayer"
+ attribute:kCAConstraintMaxX]];
+
+ [caLayer addSublayer:sublayer];
+ return caLayer;
+}
+
+
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
new file mode 100644
index 000000000..989e16d8f
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginObject.h"
+#include <assert.h>
+#include <string.h>
+
+#if defined(ANDROID)
+#include <unistd.h>
+#endif
+
+using namespace std;
+extern NPNetscapeFuncs *browser;
+
+static void (*shutdownFunction)();
+
+PluginTest* PluginTest::create(NPP npp, const string& identifier)
+{
+ if (identifier.empty())
+ return new PluginTest(npp, identifier);
+
+ CreateTestFunction createTestFunction = createTestFunctions()[identifier];
+ if (createTestFunction)
+ return createTestFunction(npp, identifier);
+
+ return 0;
+}
+
+PluginTest::PluginTest(NPP npp, const string& identifier)
+ : m_npp(npp)
+ , m_identifier(identifier)
+{
+ // Reset the shutdown function.
+ shutdownFunction = 0;
+}
+
+PluginTest::~PluginTest()
+{
+}
+
+void PluginTest::NP_Shutdown()
+{
+ if (shutdownFunction)
+ shutdownFunction();
+}
+
+void PluginTest::registerNPShutdownFunction(void (*func)())
+{
+ assert(!shutdownFunction);
+ shutdownFunction = func;
+}
+
+void PluginTest::indicateTestFailure()
+{
+ // This should really be an assert, but there's no way for the test framework
+ // to know that the plug-in process crashed, so we'll just sleep for a while
+ // to ensure that the test times out.
+#if defined(XP_WIN)
+ ::Sleep(100000);
+#else
+ sleep(1000);
+#endif
+}
+
+NPError PluginTest::NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
+{
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginTest::NPP_Destroy(NPSavedData**)
+{
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginTest::NPP_SetWindow(NPWindow*)
+{
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginTest::NPP_NewStream(NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
+{
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginTest::NPP_DestroyStream(NPStream *stream, NPReason reason)
+{
+ return NPERR_NO_ERROR;
+}
+
+int32_t PluginTest::NPP_WriteReady(NPStream*)
+{
+ return 4096;
+}
+
+int32_t PluginTest::NPP_Write(NPStream*, int32_t offset, int32_t len, void* buffer)
+{
+ return len;
+}
+
+int16_t PluginTest::NPP_HandleEvent(void*)
+{
+ return 0;
+}
+
+bool PluginTest::NPP_URLNotify(const char* url, NPReason, void* notifyData)
+{
+ // FIXME: Port the code from NPP_URLNotify in main.cpp over to always using
+ // PluginTest, so we don't have to use a return value to indicate whether the "default" NPP_URLNotify implementation should be invoked.
+ return false;
+}
+
+NPError PluginTest::NPP_GetValue(NPPVariable variable, void *value)
+{
+ // We don't know anything about plug-in values so just return NPERR_GENERIC_ERROR.
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError PluginTest::NPP_SetValue(NPNVariable, void *value)
+{
+ return NPERR_GENERIC_ERROR;
+}
+
+// NPN functions.
+
+NPError PluginTest::NPN_GetURL(const char* url, const char* target)
+{
+ return browser->geturl(m_npp, url, target);
+}
+
+NPError PluginTest::NPN_GetURLNotify(const char *url, const char *target, void *notifyData)
+{
+ return browser->geturlnotify(m_npp, url, target, notifyData);
+}
+
+NPError PluginTest::NPN_GetValue(NPNVariable variable, void* value)
+{
+ return browser->getvalue(m_npp, variable, value);
+}
+
+void PluginTest::NPN_InvalidateRect(NPRect* invalidRect)
+{
+ browser->invalidaterect(m_npp, invalidRect);
+}
+
+// NPRuntime NPN functions.
+
+NPIdentifier PluginTest::NPN_GetStringIdentifier(const NPUTF8 *name)
+{
+ return browser->getstringidentifier(name);
+}
+
+NPIdentifier PluginTest::NPN_GetIntIdentifier(int32_t intid)
+{
+ return browser->getintidentifier(intid);
+}
+
+bool PluginTest::NPN_IdentifierIsString(NPIdentifier npIdentifier)
+{
+ return browser->identifierisstring(npIdentifier);
+}
+
+NPUTF8* PluginTest::NPN_UTF8FromIdentifier(NPIdentifier npIdentifier)
+{
+ return browser->utf8fromidentifier(npIdentifier);
+}
+
+int32_t PluginTest::NPN_IntFromIdentifier(NPIdentifier npIdentifier)
+{
+ return browser->intfromidentifier(npIdentifier);
+}
+
+NPObject* PluginTest::NPN_CreateObject(NPClass* npClass)
+{
+ return browser->createobject(m_npp, npClass);
+}
+
+NPObject* PluginTest::NPN_RetainObject(NPObject* npObject)
+{
+ return browser->retainobject(npObject);
+}
+
+void PluginTest::NPN_ReleaseObject(NPObject* npObject)
+{
+ browser->releaseobject(npObject);
+}
+
+bool PluginTest::NPN_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
+{
+ return browser->removeproperty(m_npp, npObject, propertyName);
+}
+
+#ifdef XP_MACOSX
+bool PluginTest::NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace)
+{
+ return browser->convertpoint(m_npp, sourceX, sourceY, sourceSpace, destX, destY, destSpace);
+}
+#endif
+
+bool PluginTest::executeScript(const NPString* script, NPVariant* result)
+{
+ NPObject* windowScriptObject;
+ browser->getvalue(m_npp, NPNVWindowNPObject, &windowScriptObject);
+
+ return browser->evaluate(m_npp, windowScriptObject, const_cast<NPString*>(script), result);
+}
+
+void PluginTest::executeScript(const char* script)
+{
+ NPString npScript;
+ npScript.UTF8Characters = script;
+ npScript.UTF8Length = strlen(script);
+
+ NPVariant browserResult;
+ executeScript(&npScript, &browserResult);
+ browser->releasevariantvalue(&browserResult);
+}
+
+void PluginTest::log(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ pluginLogWithArguments(m_npp, format, args);
+ va_end(args);
+}
+
+void PluginTest::waitUntilDone()
+{
+ executeScript("layoutTestController.waitUntilDone()");
+}
+
+void PluginTest::notifyDone()
+{
+ executeScript("layoutTestController.notifyDone()");
+}
+
+void PluginTest::registerCreateTestFunction(const string& identifier, CreateTestFunction createTestFunction)
+{
+ assert(!createTestFunctions().count(identifier));
+
+ createTestFunctions()[identifier] = createTestFunction;
+}
+
+std::map<std::string, PluginTest::CreateTestFunction>& PluginTest::createTestFunctions()
+{
+ static std::map<std::string, CreateTestFunction> testFunctions;
+
+ return testFunctions;
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h
new file mode 100644
index 000000000..e83e82cfe
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 PluginTest_h
+#define PluginTest_h
+
+#include <WebKit/npfunctions.h>
+#include <assert.h>
+#include <map>
+#include <string>
+
+// Helper classes for implementing has_member
+typedef char (&no_tag)[1];
+typedef char (&yes_tag)[2];
+
+#define DEFINE_HAS_MEMBER_CHECK(member, returnType, argumentTypes) \
+template<typename T, returnType (T::*member) argumentTypes> struct pmf_##member##_helper {}; \
+template<typename T> no_tag has_member_##member##_helper(...); \
+template<typename T> yes_tag has_member_##member##_helper(pmf_##member##_helper<T, &T::member >*); \
+template<typename T> struct has_member_##member { \
+static const bool value = sizeof(has_member_##member##_helper<T>(0)) == sizeof(yes_tag); \
+};
+
+DEFINE_HAS_MEMBER_CHECK(hasMethod, bool, (NPIdentifier methodName));
+DEFINE_HAS_MEMBER_CHECK(invoke, bool, (NPIdentifier methodName, const NPVariant*, uint32_t, NPVariant* result));
+DEFINE_HAS_MEMBER_CHECK(invokeDefault, bool, (const NPVariant*, uint32_t, NPVariant* result));
+DEFINE_HAS_MEMBER_CHECK(hasProperty, bool, (NPIdentifier propertyName));
+DEFINE_HAS_MEMBER_CHECK(getProperty, bool, (NPIdentifier propertyName, NPVariant* result));
+DEFINE_HAS_MEMBER_CHECK(removeProperty, bool, (NPIdentifier propertyName));
+
+class PluginTest {
+public:
+ static PluginTest* create(NPP, const std::string& identifier);
+ virtual ~PluginTest();
+
+ static void NP_Shutdown();
+
+ // NPP functions.
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved);
+ virtual NPError NPP_Destroy(NPSavedData**);
+ virtual NPError NPP_SetWindow(NPWindow*);
+ virtual NPError NPP_NewStream(NPMIMEType, NPStream*, NPBool seekable, uint16_t* stype);
+ virtual NPError NPP_DestroyStream(NPStream*, NPReason);
+ virtual int32_t NPP_WriteReady(NPStream*);
+ virtual int32_t NPP_Write(NPStream*, int32_t offset, int32_t len, void* buffer);
+
+ virtual int16_t NPP_HandleEvent(void* event);
+ virtual bool NPP_URLNotify(const char* url, NPReason, void* notifyData);
+ virtual NPError NPP_GetValue(NPPVariable, void* value);
+ virtual NPError NPP_SetValue(NPNVariable, void *value);
+
+ // NPN functions.
+ NPError NPN_GetURL(const char* url, const char* target);
+ NPError NPN_GetURLNotify(const char* url, const char* target, void* notifyData);
+ NPError NPN_GetValue(NPNVariable, void* value);
+ void NPN_InvalidateRect(NPRect* invalidRect);
+
+ // NPRuntime NPN functions.
+ NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name);
+ NPIdentifier NPN_GetIntIdentifier(int32_t intid);
+ bool NPN_IdentifierIsString(NPIdentifier);
+ NPUTF8* NPN_UTF8FromIdentifier(NPIdentifier);
+ int32_t NPN_IntFromIdentifier(NPIdentifier);
+
+ NPObject* NPN_CreateObject(NPClass*);
+ NPObject* NPN_RetainObject(NPObject*);
+ void NPN_ReleaseObject(NPObject*);
+ bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName);
+
+#ifdef XP_MACOSX
+ bool NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
+#endif
+
+ bool executeScript(const NPString*, NPVariant* result);
+ void executeScript(const char*);
+ void log(const char* format, ...);
+
+ void registerNPShutdownFunction(void (*)());
+
+ static void indicateTestFailure();
+
+ template<typename TestClassTy> class Register {
+ public:
+ Register(const std::string& identifier)
+ {
+ registerCreateTestFunction(identifier, Register::create);
+ }
+
+ private:
+ static PluginTest* create(NPP npp, const std::string& identifier)
+ {
+ return new TestClassTy(npp, identifier);
+ }
+ };
+
+protected:
+ PluginTest(NPP npp, const std::string& identifier);
+
+ // FIXME: A plug-in test shouldn't need to know about it's NPP. Make this private.
+ NPP m_npp;
+
+ const std::string& identifier() const { return m_identifier; }
+
+ void waitUntilDone();
+ void notifyDone();
+
+ // NPObject helper template.
+ template<typename T> struct Object : NPObject {
+ public:
+ static NPObject* create(PluginTest* pluginTest)
+ {
+ Object* object = static_cast<Object*>(pluginTest->NPN_CreateObject(npClass()));
+
+ object->m_pluginTest = pluginTest;
+ return object;
+ }
+
+ // These should never be called.
+ bool hasMethod(NPIdentifier methodName)
+ {
+ assert(false);
+ return false;
+ }
+
+ bool invoke(NPIdentifier methodName, const NPVariant*, uint32_t, NPVariant* result)
+ {
+ assert(false);
+ return false;
+ }
+
+ bool invokeDefault(const NPVariant*, uint32_t, NPVariant* result)
+ {
+ assert(false);
+ return false;
+ }
+
+ bool hasProperty(NPIdentifier propertyName)
+ {
+ assert(false);
+ return false;
+ }
+
+ bool getProperty(NPIdentifier propertyName, NPVariant* result)
+ {
+ assert(false);
+ return false;
+ }
+
+ bool removeProperty(NPIdentifier propertyName)
+ {
+ assert(false);
+ return false;
+ }
+
+ // Helper functions.
+ bool identifierIs(NPIdentifier identifier, const char* value)
+ {
+ return pluginTest()->NPN_GetStringIdentifier(value) == identifier;
+ }
+
+ protected:
+ Object()
+ : m_pluginTest(0)
+ {
+ }
+
+ virtual ~Object()
+ {
+ }
+
+ PluginTest* pluginTest() const { return m_pluginTest; }
+
+ private:
+ static NPObject* NP_Allocate(NPP npp, NPClass* aClass)
+ {
+ return new T;
+ }
+
+ static void NP_Deallocate(NPObject* npObject)
+ {
+ delete static_cast<T*>(npObject);
+ }
+
+ static bool NP_HasMethod(NPObject* npObject, NPIdentifier methodName)
+ {
+ return static_cast<T*>(npObject)->hasMethod(methodName);
+ }
+
+ static bool NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+ {
+ return static_cast<T*>(npObject)->invoke(methodName, arguments, argumentCount, result);
+ }
+
+ static bool NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+ {
+ return static_cast<T*>(npObject)->invokeDefault(arguments, argumentCount, result);
+ }
+
+ static bool NP_HasProperty(NPObject* npObject, NPIdentifier propertyName)
+ {
+ return static_cast<T*>(npObject)->hasProperty(propertyName);
+ }
+
+ static bool NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
+ {
+ return static_cast<T*>(npObject)->getProperty(propertyName, result);
+ }
+
+ static bool NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
+ {
+ return static_cast<T*>(npObject)->removeProperty(propertyName);
+ }
+
+ static NPClass* npClass()
+ {
+ static NPClass npClass = {
+ NP_CLASS_STRUCT_VERSION,
+ NP_Allocate,
+ NP_Deallocate,
+ 0, // NPClass::invalidate
+ has_member_hasMethod<T>::value ? NP_HasMethod : 0,
+ has_member_invoke<T>::value ? NP_Invoke : 0,
+ has_member_invokeDefault<T>::value ? NP_InvokeDefault : 0,
+ has_member_hasProperty<T>::value ? NP_HasProperty : 0,
+ has_member_getProperty<T>::value ? NP_GetProperty : 0,
+ 0, // NPClass::setProperty
+ has_member_removeProperty<T>::value ? NP_RemoveProperty : 0,
+ 0, // NPClass::enumerate
+ 0 // NPClass::construct
+ };
+
+ return &npClass;
+ };
+
+ PluginTest* m_pluginTest;
+ };
+
+private:
+ typedef PluginTest* (*CreateTestFunction)(NPP, const std::string&);
+
+ static void registerCreateTestFunction(const std::string&, CreateTestFunction);
+ static std::map<std::string, CreateTestFunction>& createTestFunctions();
+
+ std::string m_identifier;
+};
+
+#endif // PluginTest_h
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp
new file mode 100644
index 000000000..9e65f1118
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "TestObject.h"
+#include "PluginObject.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+static bool testEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count);
+static bool testHasMethod(NPObject*, NPIdentifier name);
+static bool testInvoke(NPObject*, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool testHasProperty(NPObject*, NPIdentifier name);
+static bool testGetProperty(NPObject*, NPIdentifier name, NPVariant*);
+static NPObject *testAllocate(NPP npp, NPClass *theClass);
+static void testDeallocate(NPObject *obj);
+static bool testConstruct(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+
+static NPClass testClass = {
+ NP_CLASS_STRUCT_VERSION,
+ testAllocate,
+ testDeallocate,
+ 0,
+ testHasMethod,
+ testInvoke,
+ 0,
+ testHasProperty,
+ testGetProperty,
+ 0,
+ 0,
+ testEnumerate,
+ testConstruct
+};
+
+NPClass *getTestClass(void)
+{
+ return &testClass;
+}
+
+static int testObjectCount = 0;
+
+int getTestObjectCount()
+{
+ return testObjectCount;
+}
+
+typedef struct {
+ NPObject header;
+ NPObject* testObject;
+} TestObject;
+
+static bool identifiersInitialized = false;
+
+#define NUM_ENUMERATABLE_TEST_IDENTIFIERS 2
+
+enum {
+ ID_PROPERTY_FOO = 0,
+ ID_PROPERTY_BAR,
+ ID_PROPERTY_OBJECT_POINTER,
+ ID_PROPERTY_TEST_OBJECT,
+ ID_PROPERTY_REF_COUNT,
+ NUM_TEST_IDENTIFIERS,
+};
+
+static NPIdentifier testIdentifiers[NUM_TEST_IDENTIFIERS];
+static const NPUTF8 *testIdentifierNames[NUM_TEST_IDENTIFIERS] = {
+ "foo",
+ "bar",
+ "objectPointer",
+ "testObject",
+ "refCount",
+};
+
+#define ID_THROW_EXCEPTION_METHOD 0
+#define NUM_METHOD_IDENTIFIERS 1
+
+static NPIdentifier testMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
+static const NPUTF8 *testMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
+ "throwException",
+};
+
+static void initializeIdentifiers(void)
+{
+ browser->getstringidentifiers(testIdentifierNames, NUM_TEST_IDENTIFIERS, testIdentifiers);
+ browser->getstringidentifiers(testMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, testMethodIdentifiers);
+}
+
+static NPObject* testAllocate(NPP /*npp*/, NPClass* /*theClass*/)
+{
+ TestObject* newInstance = static_cast<TestObject*>(malloc(sizeof(TestObject)));
+ newInstance->testObject = 0;
+ ++testObjectCount;
+
+ if (!identifiersInitialized) {
+ identifiersInitialized = true;
+ initializeIdentifiers();
+ }
+
+ return reinterpret_cast<NPObject*>(newInstance);
+}
+
+static void testDeallocate(NPObject *obj)
+{
+ TestObject* testObject = reinterpret_cast<TestObject*>(obj);
+ if (testObject->testObject)
+ browser->releaseobject(testObject->testObject);
+
+ --testObjectCount;
+ free(obj);
+}
+
+static bool testHasMethod(NPObject*, NPIdentifier name)
+{
+ for (unsigned i = 0; i < NUM_METHOD_IDENTIFIERS; i++) {
+ if (testMethodIdentifiers[i] == name)
+ return true;
+ }
+ return false;
+}
+
+static bool testInvoke(NPObject* header, NPIdentifier name, const NPVariant* /*args*/, uint32_t /*argCount*/, NPVariant* /*result*/)
+{
+ if (name == testMethodIdentifiers[ID_THROW_EXCEPTION_METHOD]) {
+ browser->setexception(header, "test object throwException SUCCESS");
+ return true;
+ }
+ return false;
+}
+
+static bool testHasProperty(NPObject*, NPIdentifier name)
+{
+ for (unsigned i = 0; i < NUM_TEST_IDENTIFIERS; i++) {
+ if (testIdentifiers[i] == name)
+ return true;
+ }
+
+ return false;
+}
+
+static bool testGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result)
+{
+ if (name == testIdentifiers[ID_PROPERTY_FOO]) {
+ char* mem = static_cast<char*>(browser->memalloc(4));
+ strcpy(mem, "foo");
+ STRINGZ_TO_NPVARIANT(mem, *result);
+ return true;
+ }
+ if (name == testIdentifiers[ID_PROPERTY_OBJECT_POINTER]) {
+ int32_t objectPointer = static_cast<int32_t>(reinterpret_cast<long long>(npobj));
+
+ INT32_TO_NPVARIANT(objectPointer, *result);
+ return true;
+ }
+ if (name == testIdentifiers[ID_PROPERTY_TEST_OBJECT]) {
+ TestObject* testObject = reinterpret_cast<TestObject*>(npobj);
+ if (!testObject->testObject)
+ testObject->testObject = browser->createobject(0, &testClass);
+ browser->retainobject(testObject->testObject);
+ OBJECT_TO_NPVARIANT(testObject->testObject, *result);
+ return true;
+ }
+ if (name == testIdentifiers[ID_PROPERTY_REF_COUNT]) {
+ INT32_TO_NPVARIANT(npobj->referenceCount, *result);
+ return true;
+ }
+
+ return false;
+}
+
+static bool testEnumerate(NPObject* /*npobj*/, NPIdentifier **value, uint32_t *count)
+{
+ *count = NUM_ENUMERATABLE_TEST_IDENTIFIERS;
+
+ *value = (NPIdentifier*)browser->memalloc(NUM_ENUMERATABLE_TEST_IDENTIFIERS * sizeof(NPIdentifier));
+ memcpy(*value, testIdentifiers, sizeof(NPIdentifier) * NUM_ENUMERATABLE_TEST_IDENTIFIERS);
+
+ return true;
+}
+
+static bool testConstruct(NPObject* npobj, const NPVariant* /*args*/, uint32_t /*argCount*/, NPVariant* result)
+{
+ browser->retainobject(npobj);
+
+ // Just return the same object.
+ OBJECT_TO_NPVARIANT(npobj, *result);
+ return true;
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.h b/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.h
new file mode 100644
index 000000000..73748e009
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <WebKit/npapi.h>
+#include <WebKit/npruntime.h>
+
+NPClass* getTestClass(void);
+int getTestObjectCount();
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp
new file mode 100644
index 000000000..69e706ea4
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+using namespace std;
+
+extern bool testDocumentOpen(NPP npp);
+
+// Call document.open from NPP_DestroyStream.
+
+class DocumentOpenInDestroyStream : public PluginTest {
+public:
+ DocumentOpenInDestroyStream(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_shouldOpen(true)
+ {
+ }
+
+private:
+ virtual NPError NPP_DestroyStream(NPStream*, NPReason)
+ {
+ if (m_shouldOpen) {
+ testDocumentOpen(m_npp);
+ m_shouldOpen = false;
+ }
+
+ return NPERR_NO_ERROR;
+ }
+
+ bool m_shouldOpen;
+};
+
+static PluginTest::Register<DocumentOpenInDestroyStream> documentOpenInDestroyStream("document-open-in-destroy-stream");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp
new file mode 100644
index 000000000..4b5d3e01d
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// Executing JS after removing the plugin element from the document should not crash.
+
+class EvaluateJSAfterRemovingPluginElement : public PluginTest {
+public:
+ EvaluateJSAfterRemovingPluginElement(NPP, const string& identifier);
+
+private:
+ virtual NPError NPP_DestroyStream(NPStream*, NPReason);
+
+ bool m_didExecuteScript;
+};
+
+static PluginTest::Register<EvaluateJSAfterRemovingPluginElement> registrar("evaluate-js-after-removing-plugin-element");
+
+EvaluateJSAfterRemovingPluginElement::EvaluateJSAfterRemovingPluginElement(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_didExecuteScript(false)
+{
+ waitUntilDone();
+}
+
+NPError EvaluateJSAfterRemovingPluginElement::NPP_DestroyStream(NPStream*, NPReason)
+{
+ if (m_didExecuteScript)
+ return NPERR_NO_ERROR;
+ m_didExecuteScript = true;
+
+ executeScript("var plugin = document.getElementsByTagName('embed')[0]; plugin.parentElement.removeChild(plugin);");
+ executeScript("document.body.appendChild(document.createTextNode('Executing script after removing the plugin element from the document succeeded.'));");
+ notifyDone();
+
+ return NPERR_NO_ERROR;
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/FormValue.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/FormValue.cpp
new file mode 100644
index 000000000..738e192eb
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/FormValue.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+#include <string.h>
+
+extern NPNetscapeFuncs *browser;
+
+class FormValue : public PluginTest {
+public:
+ FormValue(NPP npp, const std::string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+ virtual NPError NPP_GetValue(NPPVariable, void*);
+};
+
+NPError FormValue::NPP_GetValue(NPPVariable variable, void *value)
+{
+ if (variable == NPPVformValue) {
+ static const char formValueText[] = "Plugin form value";
+ *((void**)value) = browser->memalloc(sizeof(formValueText));
+ if (!*((void**)value))
+ return NPERR_OUT_OF_MEMORY_ERROR;
+ strncpy(*((char**)value), formValueText, sizeof(formValueText));
+ return NPERR_NO_ERROR;
+ }
+ return NPERR_GENERIC_ERROR;
+}
+
+static PluginTest::Register<FormValue> formValue("form-value");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp
new file mode 100644
index 000000000..f6f39ab04
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include <string.h>
+
+using namespace std;
+
+// From NPP_New, call NPN_GetURLNotify with a URL that fails to load (NPP_NewStream won't be called).
+// The plug-in should still get a NPP_URLNotify indicating that the load failed.
+static const char *urlThatFailsToLoad = "foo://bar/";
+
+class GetURLNotifyWithURLThatFailsToLoad : public PluginTest {
+public:
+ GetURLNotifyWithURLThatFailsToLoad(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
+ {
+ NPN_GetURLNotify(urlThatFailsToLoad, 0, reinterpret_cast<void*>(0x12345678));
+ return NPERR_NO_ERROR;
+ }
+
+ bool NPP_URLNotify(const char* url, NPReason reason, void* notifyData)
+ {
+ bool didFail = false;
+
+ if (strcmp(url, urlThatFailsToLoad))
+ didFail = true;
+
+ if (reason != NPRES_NETWORK_ERR)
+ didFail = true;
+
+ if (notifyData != reinterpret_cast<void*>(0x12345678))
+ didFail = true;
+
+ if (!didFail)
+ executeScript("testSucceeded()");
+ else
+ executeScript("notifyDone()");
+ return true;
+ }
+};
+
+static PluginTest::Register<GetURLNotifyWithURLThatFailsToLoad> getURLWithJavaScriptURLDestroyingPlugin("get-url-notify-with-url-that-fails-to-load");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp
new file mode 100644
index 000000000..b3a72b0d5
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURL.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include <string.h>
+#include <vector>
+
+using namespace std;
+
+const char *javaScriptURL = "javascript:'Hello, ' + 'World!'";
+const char *javaScriptResult = "Hello, World!";
+
+// Test that evaluating a javascript: URL will send a stream with the result of the evaluation.
+// Test that evaluating JavaScript using NPN_GetURL will a stream with result of the evaluation.
+class GetURLWithJavaScriptURL : public PluginTest {
+public:
+ GetURLWithJavaScriptURL(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_didFail(false)
+ {
+ }
+
+private:
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
+ {
+ NPN_GetURL(javaScriptURL, 0);
+ return NPERR_NO_ERROR;
+ }
+
+ NPError NPP_NewStream(NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
+ {
+ stream->pdata = this;
+
+ if (strcmp(stream->url, javaScriptURL))
+ m_didFail = true;
+
+ if (stream->end != strlen(javaScriptResult))
+ m_didFail = true;
+
+ *stype = NP_NORMAL;
+ return NPERR_NO_ERROR;
+ }
+
+ NPError NPP_DestroyStream(NPStream* stream, NPReason reason)
+ {
+ if (stream->pdata != this)
+ m_didFail = true;
+
+ if (reason != NPRES_DONE)
+ m_didFail = true;
+
+ if (m_data.size() != stream->end)
+ m_didFail = true;
+
+ m_data.push_back('\0');
+
+ if (strcmp(&m_data[0], javaScriptResult))
+ m_didFail = true;
+
+ if (!m_didFail)
+ executeScript("testSucceeded()");
+ else
+ executeScript("notifyDone()");
+
+ return NPERR_NO_ERROR;
+ }
+
+ int32_t NPP_WriteReady(NPStream* stream)
+ {
+ if (stream->pdata != this)
+ m_didFail = true;
+
+ return 2;
+ }
+
+ int32_t NPP_Write(NPStream* stream, int32_t offset, int32_t len, void* buffer)
+ {
+ if (stream->pdata != this)
+ m_didFail = true;
+
+ m_data.insert(m_data.end(), static_cast<char*>(buffer), static_cast<char*>(buffer) + len);
+ return len;
+ }
+
+ vector<char> m_data;
+ bool m_didFail;
+};
+
+static PluginTest::Register<GetURLWithJavaScriptURL> getURLWithJavaScriptURLDestroyingPlugin("get-url-with-javascript-url");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp
new file mode 100644
index 000000000..9d63198b1
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+using namespace std;
+
+// From NPP_New, call NPN_GetURL to evaluate JavaScript that destroys the plug-in.
+
+class GetURLWithJavaScriptURLDestroyingPlugin : public PluginTest {
+public:
+ GetURLWithJavaScriptURLDestroyingPlugin(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
+ {
+ NPN_GetURL("javascript:removePlugin()", 0);
+ return NPERR_NO_ERROR;
+ }
+};
+
+static PluginTest::Register<GetURLWithJavaScriptURLDestroyingPlugin> getURLWithJavaScriptURLDestroyingPlugin("get-url-with-javascript-url-destroying-plugin");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp
new file mode 100644
index 000000000..322d3fec4
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// Trying to get the user agent with a null instance from NPP_New.
+
+class GetUserAgentWithNullNPPFromNPPNew : public PluginTest {
+public:
+ GetUserAgentWithNullNPPFromNPPNew(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
+ {
+ if (!browser->uagent(0))
+ pluginLog(m_npp, "FAILURE: Null user agent returned.");
+ else
+ pluginLog(m_npp, "SUCCESS!");
+
+ return NPERR_NO_ERROR;
+ }
+
+};
+
+static PluginTest::Register<GetUserAgentWithNullNPPFromNPPNew> getUserAgentWithNullNPPFromNPPNew("get-user-agent-with-null-npp-from-npp-new");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp
new file mode 100644
index 000000000..91f47aff1
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+using namespace std;
+
+static bool wasShutdownCalled = false;
+
+class NPDeallocateCalledBeforeNPShutdown : public PluginTest {
+public:
+ NPDeallocateCalledBeforeNPShutdown(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ // This is the test object.
+ class TestObject : public Object<TestObject> {
+ public:
+ ~TestObject()
+ {
+ if (wasShutdownCalled)
+ indicateTestFailure();
+ }
+ };
+
+ // This is the scriptable object. It has a single "testObject" property.
+ class ScriptableObject : public Object<ScriptableObject> {
+ public:
+ bool hasProperty(NPIdentifier propertyName)
+ {
+ return propertyName == pluginTest()->NPN_GetStringIdentifier("testObject");
+ }
+
+ bool getProperty(NPIdentifier propertyName, NPVariant* result)
+ {
+ if (propertyName != pluginTest()->NPN_GetStringIdentifier("testObject"))
+ return false;
+
+ NPObject* testObject = TestObject::create(pluginTest());
+ OBJECT_TO_NPVARIANT(testObject, *result);
+ return true;
+ }
+ };
+
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
+ {
+ registerNPShutdownFunction(shutdown);
+
+ return NPERR_NO_ERROR;
+ }
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void *value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *(NPObject**)value = ScriptableObject::create(this);
+
+ return NPERR_NO_ERROR;
+ }
+
+ static void shutdown()
+ {
+ wasShutdownCalled = true;
+ }
+
+};
+
+static PluginTest::Register<NPDeallocateCalledBeforeNPShutdown> npRuntimeObjectFromDestroyedPlugin("np-deallocate-called-before-np-shutdown");
+
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp
new file mode 100644
index 000000000..50af95905
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// NPP_SetWindow should be called with a null window handle as destruction begins on non-Mac platforms.
+
+class NPPSetWindowCalledDuringDestruction : public PluginTest {
+public:
+ NPPSetWindowCalledDuringDestruction(NPP, const string& identifier);
+
+ void setWillBeDestroyed() { m_willBeDestroyed = true; }
+
+private:
+ struct ScriptObject : Object<ScriptObject> {
+ bool hasMethod(NPIdentifier);
+ bool invoke(NPIdentifier, const NPVariant*, uint32_t, NPVariant*);
+ };
+
+ virtual NPError NPP_GetValue(NPPVariable, void*);
+ virtual NPError NPP_SetWindow(NPWindow*);
+ virtual NPError NPP_Destroy(NPSavedData**);
+
+ bool m_willBeDestroyed;
+ bool m_setWindowCalledBeforeDestruction;
+ bool m_setWindowCalledDuringDestruction;
+};
+
+static PluginTest::Register<NPPSetWindowCalledDuringDestruction> registrar("npp-set-window-called-during-destruction");
+
+NPPSetWindowCalledDuringDestruction::NPPSetWindowCalledDuringDestruction(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_willBeDestroyed(false)
+ , m_setWindowCalledBeforeDestruction(false)
+ , m_setWindowCalledDuringDestruction(false)
+{
+}
+
+NPError NPPSetWindowCalledDuringDestruction::NPP_GetValue(NPPVariable variable, void* value)
+{
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *static_cast<NPObject**>(value) = ScriptObject::create(this);
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPPSetWindowCalledDuringDestruction::NPP_SetWindow(NPWindow* window)
+{
+ if (m_willBeDestroyed) {
+ m_setWindowCalledDuringDestruction = true;
+ if (!m_setWindowCalledBeforeDestruction) {
+ log("Fail: setWillBeDestroyed() was called before the initial NPP_SetWindow call");
+ return NPERR_NO_ERROR;
+ }
+#ifndef XP_MACOSX
+ if (window->window)
+ log("Fail: NPP_SetWindow passed a non-null window during plugin destruction");
+#endif
+ return NPERR_NO_ERROR;
+ }
+
+ if (m_setWindowCalledBeforeDestruction) {
+ log("Fail: NPP_SetWindow called more than once before plugin destruction");
+ return NPERR_NO_ERROR;
+ }
+
+ m_setWindowCalledBeforeDestruction = true;
+ return NPERR_NO_ERROR;
+}
+
+NPError NPPSetWindowCalledDuringDestruction::NPP_Destroy(NPSavedData**)
+{
+#ifdef XP_MACOSX
+ bool shouldHaveBeenCalledDuringDestruction = false;
+#else
+ bool shouldHaveBeenCalledDuringDestruction = true;
+#endif
+
+ if (m_setWindowCalledDuringDestruction == shouldHaveBeenCalledDuringDestruction)
+ log("Success: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was" : "was not");
+ else
+ log("Fail: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was not" : "was");
+
+ return NPERR_NO_ERROR;
+}
+
+bool NPPSetWindowCalledDuringDestruction::ScriptObject::hasMethod(NPIdentifier methodName)
+{
+ return methodName == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed");
+}
+
+bool NPPSetWindowCalledDuringDestruction::ScriptObject::invoke(NPIdentifier identifier, const NPVariant*, uint32_t, NPVariant*)
+{
+ assert(identifier == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed"));
+ static_cast<NPPSetWindowCalledDuringDestruction*>(pluginTest())->setWillBeDestroyed();
+ return true;
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp
new file mode 100644
index 000000000..0e238e607
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+using namespace std;
+
+class NPRuntimeObjectFromDestroyedPlugin : public PluginTest {
+public:
+ NPRuntimeObjectFromDestroyedPlugin(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ // This is the test object.
+ class TestObject : public Object<TestObject> { };
+
+ // This is the scriptable object. It has a single "testObject" property and an "evaluate" function.
+ class ScriptableObject : public Object<ScriptableObject> {
+ public:
+ bool hasMethod(NPIdentifier methodName)
+ {
+ return identifierIs(methodName, "evaluate");
+ }
+
+ bool invoke(NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result)
+ {
+ if (!identifierIs(methodName, "evaluate"))
+ return false;
+
+ if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
+ return false;
+
+ return pluginTest()->executeScript(&NPVARIANT_TO_STRING(args[0]), result);
+ }
+
+ bool hasProperty(NPIdentifier propertyName)
+ {
+ return identifierIs(propertyName, "testObject");
+ }
+
+ bool getProperty(NPIdentifier propertyName, NPVariant* result)
+ {
+ if (propertyName != pluginTest()->NPN_GetStringIdentifier("testObject"))
+ return false;
+
+ NPObject* testObject = TestObject::create(pluginTest());
+ OBJECT_TO_NPVARIANT(testObject, *result);
+ return true;
+ }
+ };
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void *value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *(NPObject**)value = ScriptableObject::create(this);
+
+ return NPERR_NO_ERROR;
+ }
+};
+
+static PluginTest::Register<NPRuntimeObjectFromDestroyedPlugin> npRuntimeObjectFromDestroyedPlugin("npruntime-object-from-destroyed-plugin");
+
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp
new file mode 100644
index 000000000..8a923dc23
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include <string.h>
+
+using namespace std;
+
+class NPRuntimeRemoveProperty : public PluginTest {
+public:
+ NPRuntimeRemoveProperty(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ struct TestObject : Object<TestObject> {
+ public:
+ TestObject()
+ : m_lastRemovedProperty(0)
+ {
+ }
+
+ bool hasProperty(NPIdentifier propertyName)
+ {
+ if (identifierIs(propertyName, "lastRemovedProperty"))
+ return true;
+
+ return false;
+ }
+
+ bool getProperty(NPIdentifier propertyName, NPVariant* result)
+ {
+ assert(identifierIs(propertyName, "lastRemovedProperty"));
+
+ if (!m_lastRemovedProperty)
+ return false;
+
+ if (pluginTest()->NPN_IdentifierIsString(m_lastRemovedProperty)) {
+ char* lastRemovedPropertyName = pluginTest()->NPN_UTF8FromIdentifier(m_lastRemovedProperty);
+
+ STRINGZ_TO_NPVARIANT(lastRemovedPropertyName, *result);
+ return true;
+ }
+
+ int intIdentifier = pluginTest()->NPN_IntFromIdentifier(m_lastRemovedProperty);
+ DOUBLE_TO_NPVARIANT(intIdentifier, *result);
+ return true;
+ }
+
+ bool removeProperty(NPIdentifier propertyName)
+ {
+ m_lastRemovedProperty = propertyName;
+ return true;
+ }
+
+ private:
+ NPIdentifier m_lastRemovedProperty;
+ };
+
+ struct PluginObject : Object<PluginObject> {
+ public:
+ PluginObject()
+ : m_testObject(0)
+ {
+ }
+
+ ~PluginObject()
+ {
+ if (m_testObject)
+ pluginTest()->NPN_ReleaseObject(m_testObject);
+ }
+
+ bool hasMethod(NPIdentifier methodName)
+ {
+ if (identifierIs(methodName, "testRemoveProperty"))
+ return true;
+
+ return false;
+ }
+
+ bool invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+ {
+ assert(identifierIs(methodName, "testRemoveProperty"));
+
+ if (argumentCount != 2)
+ return false;
+
+ if (!NPVARIANT_IS_OBJECT(arguments[0]))
+ return false;
+
+ if (!NPVARIANT_IS_STRING(arguments[1]) && !NPVARIANT_IS_DOUBLE(arguments[1]))
+ return false;
+
+ NPIdentifier propertyName;
+ if (NPVARIANT_IS_STRING(arguments[1])) {
+ string propertyNameString(arguments[1].value.stringValue.UTF8Characters,
+ arguments[1].value.stringValue.UTF8Length);
+
+ propertyName = pluginTest()->NPN_GetStringIdentifier(propertyNameString.c_str());
+ } else {
+ int32_t number = static_cast<int32_t>(arguments[1].value.doubleValue);
+ propertyName = pluginTest()->NPN_GetIntIdentifier(number);
+ }
+
+ pluginTest()->NPN_RemoveProperty(NPVARIANT_TO_OBJECT(arguments[0]), propertyName);
+
+ VOID_TO_NPVARIANT(*result);
+ return true;
+ }
+
+ bool hasProperty(NPIdentifier propertyName)
+ {
+ if (identifierIs(propertyName, "testObject"))
+ return true;
+
+ return false;
+ }
+
+ bool getProperty(NPIdentifier propertyName, NPVariant* result)
+ {
+ assert(identifierIs(propertyName, "testObject"));
+
+ if (!m_testObject)
+ m_testObject = TestObject::create(pluginTest());
+
+ OBJECT_TO_NPVARIANT(pluginTest()->NPN_RetainObject(m_testObject), *result);
+ return true;
+ }
+
+ private:
+ NPObject* m_testObject;
+ };
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void *value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *(NPObject**)value = PluginObject::create(this);
+
+ return NPERR_NO_ERROR;
+ }
+
+};
+
+static PluginTest::Register<NPRuntimeRemoveProperty> npRuntimeRemoveProperty("npruntime-remove-property");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp
new file mode 100644
index 000000000..9e4e976f0
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// Passing null for our NPP_GetValue function pointer should not crash.
+
+class NullNPPGetValuePointer : public PluginTest {
+public:
+ NullNPPGetValuePointer(NPP, const string& identifier);
+
+private:
+ virtual NPError NPP_Destroy(NPSavedData**);
+ virtual NPError NPP_GetValue(NPPVariable, void* value);
+
+ NPP_GetValueProcPtr m_originalNPPGetValuePointer;
+};
+
+static PluginTest::Register<NullNPPGetValuePointer> registrar("null-npp-getvalue-pointer");
+
+NullNPPGetValuePointer::NullNPPGetValuePointer(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_originalNPPGetValuePointer(pluginFunctions->getvalue)
+{
+ // Be sneaky and null out the getvalue pointer the browser is holding. This simulates a plugin
+ // that doesn't implement NPP_GetValue (like Shockwave Director 10.3 on Windows). Note that if
+ // WebKit copies the NPPluginFuncs struct this technique will have no effect and WebKit will
+ // call into our NPP_GetValue implementation.
+ pluginFunctions->getvalue = 0;
+}
+
+NPError NullNPPGetValuePointer::NPP_Destroy(NPSavedData**)
+{
+ // Set the NPP_GetValue pointer back the way it was before we mucked with it so we don't mess
+ // up future uses of the plugin module.
+ pluginFunctions->getvalue = m_originalNPPGetValuePointer;
+ return NPERR_NO_ERROR;
+}
+
+NPError NullNPPGetValuePointer::NPP_GetValue(NPPVariable, void*)
+{
+ pluginLog(m_npp, "NPP_GetValue was called but should not have been. Maybe WebKit copied the NPPluginFuncs struct, which would invalidate this test.");
+ return NPERR_GENERIC_ERROR;
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp
new file mode 100644
index 000000000..c9af49c59
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// Passing a different NPP struct that has the same ndata value as the one passed to NPP_New should
+// not trigger an assertion failure.
+
+class PassDifferentNPPStruct : public PluginTest {
+public:
+ PassDifferentNPPStruct(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_didReceiveInitialSetWindowCall(false)
+ {
+ }
+
+private:
+ virtual NPError NPP_SetWindow(NPWindow* window)
+ {
+ if (m_didReceiveInitialSetWindowCall)
+ return NPERR_NO_ERROR;
+ m_didReceiveInitialSetWindowCall = true;
+
+ NPP oldNPP = m_npp;
+ NPP_t differentNPP = *m_npp;
+ m_npp = &differentNPP;
+
+ NPBool privateMode;
+ NPError error = NPN_GetValue(NPNVprivateModeBool, &privateMode);
+
+ m_npp = oldNPP;
+
+ if (error != NPERR_NO_ERROR) {
+ log("NPN_GetValue(NPNVprivateModeBool) with a different NPP struct failed with error %d", error);
+ return NPERR_GENERIC_ERROR;
+ }
+ log("NPN_GetValue(NPNVprivateModeBool) with a different NPP struct succeeded");
+ return NPERR_NO_ERROR;
+ }
+
+ bool m_didReceiveInitialSetWindowCall;
+};
+
+static PluginTest::Register<PassDifferentNPPStruct> getValueNetscapeWindow("pass-different-npp-struct");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp
new file mode 100644
index 000000000..959e182e4
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+using namespace std;
+
+// A test where the plug-ins scriptable object either has or doesn't have an invokeDefault function.
+class PluginScriptableNPObjectInvokeDefault : public PluginTest {
+public:
+ PluginScriptableNPObjectInvokeDefault(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ struct NPObjectWithoutInvokeDefault : Object<NPObjectWithoutInvokeDefault> { };
+
+ struct NPObjectWithInvokeDefault : Object<NPObjectWithInvokeDefault> {
+ public:
+ bool invokeDefault(const NPVariant*, uint32_t, NPVariant* result)
+ {
+ INT32_TO_NPVARIANT(1, *result);
+ return true;
+ }
+ };
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void *value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ NPObject* object;
+ if (identifier() == "plugin-scriptable-npobject-invoke-default")
+ object = NPObjectWithInvokeDefault::create(this);
+ else
+ object = NPObjectWithoutInvokeDefault::create(this);
+
+ *(NPObject**)value = object;
+
+ return NPERR_NO_ERROR;
+ }
+};
+
+static PluginTest::Register<PluginScriptableNPObjectInvokeDefault> pluginScriptableNPObjectInvokeDefault("plugin-scriptable-npobject-invoke-default");
+static PluginTest::Register<PluginScriptableNPObjectInvokeDefault> pluginScriptableNPObjectNoInvokeDefault("plugin-scriptable-npobject-no-invoke-default");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PrivateBrowsing.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PrivateBrowsing.cpp
new file mode 100644
index 000000000..ea5ac1ccc
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PrivateBrowsing.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+using namespace std;
+
+class PrivateBrowsing : public PluginTest {
+public:
+ PrivateBrowsing(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_cachedPrivateBrowsingEnabled(false)
+ {
+ }
+
+private:
+ bool privateBrowsingEnabled()
+ {
+ NPBool privateBrowsingEnabled = FALSE;
+ NPN_GetValue(NPNVprivateModeBool, &privateBrowsingEnabled);
+ return privateBrowsingEnabled;
+ }
+
+ bool cachedPrivateBrowsingEnabled()
+ {
+ return m_cachedPrivateBrowsingEnabled;
+ }
+
+ class ScriptableObject : public Object<ScriptableObject> {
+ public:
+ bool hasProperty(NPIdentifier propertyName)
+ {
+ return identifierIs(propertyName, "privateBrowsingEnabled")
+ || identifierIs(propertyName, "cachedPrivateBrowsingEnabled");
+ }
+
+ bool getProperty(NPIdentifier propertyName, NPVariant* result)
+ {
+ if (identifierIs(propertyName, "privateBrowsingEnabled")) {
+ BOOLEAN_TO_NPVARIANT(pluginTest()->privateBrowsingEnabled(), *result);
+ return true;
+ }
+ if (identifierIs(propertyName, "cachedPrivateBrowsingEnabled")) {
+ BOOLEAN_TO_NPVARIANT(pluginTest()->cachedPrivateBrowsingEnabled(), *result);
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ PrivateBrowsing* pluginTest() const { return static_cast<PrivateBrowsing*>(Object<ScriptableObject>::pluginTest()); }
+ };
+
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved)
+ {
+ m_cachedPrivateBrowsingEnabled = privateBrowsingEnabled();
+ return NPERR_NO_ERROR;
+ }
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void* value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *(NPObject**)value = ScriptableObject::create(this);
+
+ return NPERR_NO_ERROR;
+ }
+
+ virtual NPError NPP_SetValue(NPNVariable variable, void* value)
+ {
+ switch (variable) {
+ case NPNVprivateModeBool:
+ m_cachedPrivateBrowsingEnabled = *(NPBool*)value;
+ return NPERR_NO_ERROR;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+
+ }
+ bool m_cachedPrivateBrowsingEnabled;
+};
+
+static PluginTest::Register<PrivateBrowsing> privateBrowsing("private-browsing");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ContentsScaleFactor.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ContentsScaleFactor.cpp
new file mode 100644
index 000000000..5353d8333
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ContentsScaleFactor.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+using namespace std;
+
+class ContentsScaleFactor : public PluginTest {
+public:
+ ContentsScaleFactor(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_cachedContentsScaleFactor(1.0)
+ {
+ }
+
+private:
+ double contentsScaleFactor()
+ {
+ double contentsScaleFactor = 1.0;
+ NPN_GetValue(NPNVcontentsScaleFactor, &contentsScaleFactor);
+ return contentsScaleFactor;
+ }
+
+ double cachedContentsScaleFactor()
+ {
+ return m_cachedContentsScaleFactor;
+ }
+
+ class ScriptableObject : public Object<ScriptableObject> {
+ public:
+ bool hasProperty(NPIdentifier propertyName)
+ {
+ return identifierIs(propertyName, "contentsScaleFactor")
+ || identifierIs(propertyName, "cachedContentsScaleFactor");
+ }
+
+ bool getProperty(NPIdentifier propertyName, NPVariant* result)
+ {
+ if (identifierIs(propertyName, "contentsScaleFactor")) {
+ DOUBLE_TO_NPVARIANT(pluginTest()->contentsScaleFactor(), *result);
+ return true;
+ }
+
+ if (identifierIs(propertyName, "cachedContentsScaleFactor")) {
+ DOUBLE_TO_NPVARIANT(pluginTest()->cachedContentsScaleFactor(), *result);
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ ContentsScaleFactor* pluginTest() const { return static_cast<ContentsScaleFactor*>(Object<ScriptableObject>::pluginTest()); }
+
+ };
+
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData *saved)
+ {
+ m_cachedContentsScaleFactor = contentsScaleFactor();
+ return NPERR_NO_ERROR;
+ }
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void* value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *(NPObject**)value = ScriptableObject::create(this);
+
+ return NPERR_NO_ERROR;
+ }
+
+ virtual NPError NPP_SetValue(NPNVariable variable, void* value)
+ {
+ switch (variable) {
+ case NPNVcontentsScaleFactor:
+ m_cachedContentsScaleFactor = *(double*)value;
+ return NPERR_NO_ERROR;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+ double m_cachedContentsScaleFactor;
+};
+
+static PluginTest::Register<ContentsScaleFactor> contentsScaleFactor("contents-scale-factor");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp
new file mode 100644
index 000000000..96a6cc757
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+using namespace std;
+
+// Test that NPN_ConvertPoint converts correctly.
+class ConvertPoint : public PluginTest {
+public:
+ ConvertPoint(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+ bool testConvert(double x, double y, NPCoordinateSpace sourceSpace, NPCoordinateSpace destSpace)
+ {
+ // First convert from src to dest.
+ double destX, destY;
+ if (!NPN_ConvertPoint(x, y, sourceSpace, &destX, &destY, destSpace))
+ return false;
+
+ // Then convert back to src
+ double srcX, srcY;
+ if (!NPN_ConvertPoint(destX, destY, destSpace, &srcX, &srcY, sourceSpace))
+ return false;
+
+
+ // Then compare.
+ if (srcX != x || srcY != y)
+ return false;
+
+ return true;
+ }
+
+ bool testConvert()
+ {
+ static const NPCoordinateSpace spaces[] = { NPCoordinateSpacePlugin, NPCoordinateSpaceWindow, NPCoordinateSpaceFlippedWindow, NPCoordinateSpaceScreen, NPCoordinateSpaceFlippedScreen };
+
+ static const size_t numSpaces = sizeof(spaces) / sizeof(spaces[0]);
+ for (size_t i = 0; i < numSpaces; ++i) {
+ for (size_t j = 0; j < numSpaces; ++j) {
+ if (!testConvert(1234, 5678, spaces[i], spaces[j]))
+ return false;
+ }
+ }
+ return true;
+ }
+private:
+ virtual NPError NPP_SetWindow(NPWindow*)
+ {
+ if (testConvert())
+ executeScript("document.getElementById('result').innerHTML = 'SUCCESS!'");
+
+ executeScript("setTimeout(function() { layoutTestController.notifyDone() }, 0)");
+ return NPERR_NO_ERROR;
+ }
+};
+
+static PluginTest::Register<ConvertPoint> convertPoint("convert-point");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/SupportsCarbonEventModel.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/SupportsCarbonEventModel.cpp
new file mode 100644
index 000000000..51cbce2bf
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/SupportsCarbonEventModel.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+using namespace std;
+
+// Test that we report that we support the Carbon event model in 32-bit.
+class SupportsCarbonEventModel : public PluginTest {
+public:
+ SupportsCarbonEventModel(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ bool runTest()
+ {
+#ifdef NP_NO_CARBON
+ // There's no support for Carbon, so we can't test anything.
+ return true;
+#else
+ NPBool supportsCarbonEventModel = false;
+ if (NPN_GetValue(NPNVsupportsCarbonBool, &supportsCarbonEventModel) != NPERR_NO_ERROR)
+ return false;
+
+ return supportsCarbonEventModel;
+#endif
+ }
+
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
+ {
+ if (runTest())
+ executeScript("document.getElementById('result').innerHTML = 'SUCCESS!'");
+
+ return NPERR_NO_ERROR;
+ }
+};
+
+static PluginTest::Register<SupportsCarbonEventModel> supportsCarbonEventModel("supports-carbon-event-model");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp
new file mode 100644
index 000000000..2b0619832
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp
@@ -0,0 +1,118 @@
+/* Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowedPluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// Just fills its window with some gradients
+
+class DrawsGradient : public WindowedPluginTest {
+public:
+ DrawsGradient(NPP, const string& identifier);
+
+private:
+ void paint(HDC) const;
+
+ LRESULT onPaint(WPARAM, LPARAM, bool& handled);
+ LRESULT onPrintClient(WPARAM, LPARAM, bool& handled);
+
+ virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled);
+};
+
+static PluginTest::Register<DrawsGradient> registrar("draws-gradient");
+
+DrawsGradient::DrawsGradient(NPP npp, const string& identifier)
+ : WindowedPluginTest(npp, identifier)
+{
+}
+
+LRESULT DrawsGradient::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
+{
+ LRESULT result = 0;
+
+ switch (message) {
+ case WM_PAINT:
+ result = onPaint(wParam, lParam, handled);
+ break;
+ case WM_PRINTCLIENT:
+ result = onPrintClient(wParam, lParam, handled);
+ break;
+ default:
+ handled = false;
+ }
+
+ return result;
+}
+
+LRESULT DrawsGradient::onPaint(WPARAM, LPARAM, bool& handled)
+{
+ PAINTSTRUCT paintStruct;
+ HDC dc = ::BeginPaint(window(), &paintStruct);
+ if (!dc)
+ return 0;
+
+ paint(dc);
+ ::EndPaint(window(), &paintStruct);
+
+ handled = true;
+ return 0;
+}
+
+LRESULT DrawsGradient::onPrintClient(WPARAM wParam, LPARAM, bool& handled)
+{
+ paint(reinterpret_cast<HDC>(wParam));
+
+ handled = true;
+ return 0;
+}
+
+void DrawsGradient::paint(HDC dc) const
+{
+ RECT clientRect;
+ if (!::GetClientRect(window(), &clientRect))
+ return;
+
+ TRIVERTEX vertices[] = {
+ // Upper-left: green
+ { clientRect.left, clientRect.top, 0, 0xff00, 0, 0 },
+ // Upper-right: blue
+ { clientRect.right, clientRect.top, 0, 0, 0xff00, 0 },
+ // Lower-left: yellow
+ { clientRect.left, clientRect.bottom, 0xff00, 0xff00, 0, 0 },
+ // Lower-right: red
+ { clientRect.right, clientRect.bottom, 0xff00, 0, 0, 0 },
+ };
+
+ GRADIENT_TRIANGLE mesh[] = {
+ // Upper-left triangle
+ { 0, 1, 2 },
+ // Lower-right triangle
+ { 1, 2, 3 },
+ };
+
+ ::GradientFill(dc, vertices, _countof(vertices), mesh, _countof(mesh), GRADIENT_FILL_TRIANGLE);
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DumpWindowRect.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DumpWindowRect.cpp
new file mode 100644
index 000000000..fc2fd45a8
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DumpWindowRect.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowGeometryTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// This plugin dumps its window rect (relative to the test harness window) to the console when it
+// is instantiated.
+
+class DumpWindowRect : public WindowGeometryTest {
+public:
+ DumpWindowRect(NPP, const string& identifier);
+
+private:
+ virtual void performWindowGeometryTest();
+};
+
+static PluginTest::Register<DumpWindowRect> registrar("dump-window-rect");
+
+DumpWindowRect::DumpWindowRect(NPP npp, const string& identifier)
+ : WindowGeometryTest(npp, identifier)
+{
+}
+
+
+void DumpWindowRect::performWindowGeometryTest()
+{
+ RECT rect;
+ if (!::GetClientRect(window(), &rect)) {
+ log("::GetClientRect failed");
+ return;
+ }
+
+ // MSDN says that calling ::MapWindowPoints this way will tell it to treat the points as a rect.
+ if (!::MapWindowPoints(window(), testHarnessWindow(), reinterpret_cast<LPPOINT>(&rect), 2)) {
+ log("::MapWindowPoints failed");
+ return;
+ }
+
+ log("Plugin window rect: {left=%d, top=%d, right=%d, bottom=%d}", rect.left, rect.top, rect.right, rect.bottom);
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp
new file mode 100644
index 000000000..32fd99b63
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// NPN_GetValue(NPNVnetscapeWindow) should return a valid HWND.
+
+class GetValueNetscapeWindow : public PluginTest {
+public:
+ GetValueNetscapeWindow(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_didReceiveInitialSetWindowCall(false)
+ {
+ }
+
+private:
+ virtual NPError NPP_SetWindow(NPP instance, NPWindow* window)
+ {
+ if (m_didReceiveInitialSetWindowCall)
+ return NPERR_NO_ERROR;
+ m_didReceiveInitialSetWindowCall = true;
+
+ HWND hwnd;
+ NPError error = NPN_GetValue(NPNVnetscapeWindow, &hwnd);
+ if (error != NPERR_NO_ERROR) {
+ pluginLog(instance, "NPN_GetValue(NPNVnetscapeWindow) failed with error %d", error);
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (!::IsWindow(hwnd)) {
+ pluginLog(instance, "::IsWindow returned FALSE");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (hwnd == window->window) {
+ pluginLog(instance, "NPN_GetValue(NPNVnetscapeWindow) returned the same value as NPWindow::window");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ pluginLog(instance, "NPN_GetValue(NPNVnetscapeWindow) succeeded");
+ return NPERR_NO_ERROR;
+ }
+
+ bool m_didReceiveInitialSetWindowCall;
+};
+
+static PluginTest::Register<GetValueNetscapeWindow> getValueNetscapeWindow("get-value-netscape-window");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp
new file mode 100644
index 000000000..6d5484b1f
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowedPluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// NPN_InvalidateRect should invalidate the plugin's HWND.
+
+static const wchar_t instancePointerProperty[] = L"org.webkit.TestNetscapePlugin.NPNInvalidateRectInvalidatesWindow.InstancePointer";
+
+class TemporaryWindowMover {
+public:
+ TemporaryWindowMover(HWND);
+ ~TemporaryWindowMover();
+
+ bool moveSucceeded() const { return m_moveSucceeded; }
+
+private:
+ static const UINT standardSetWindowPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER;
+ bool m_moveSucceeded;
+ HWND m_window;
+ RECT m_savedWindowRect;
+};
+
+TemporaryWindowMover::TemporaryWindowMover(HWND window)
+ : m_window(window)
+{
+ m_moveSucceeded = false;
+
+ if (!::GetWindowRect(m_window, &m_savedWindowRect))
+ return;
+
+ if (!::SetWindowPos(m_window, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | standardSetWindowPosFlags))
+ return;
+
+ m_moveSucceeded = true;
+};
+
+TemporaryWindowMover::~TemporaryWindowMover()
+{
+ if (!m_moveSucceeded)
+ return;
+
+ ::SetWindowPos(m_window, 0, m_savedWindowRect.left, m_savedWindowRect.top, 0, 0, SWP_HIDEWINDOW | standardSetWindowPosFlags);
+}
+
+class NPNInvalidateRectInvalidatesWindow : public WindowedPluginTest {
+public:
+ NPNInvalidateRectInvalidatesWindow(NPP, const string& identifier);
+ ~NPNInvalidateRectInvalidatesWindow();
+
+private:
+ virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled);
+
+ void onPaint();
+ void testInvalidateRect();
+
+ virtual NPError NPP_SetWindow(NPP, NPWindow*);
+
+ TemporaryWindowMover* m_windowMover;
+};
+
+NPNInvalidateRectInvalidatesWindow::NPNInvalidateRectInvalidatesWindow(NPP npp, const string& identifier)
+ : WindowedPluginTest(npp, identifier)
+ , m_windowMover(0)
+{
+}
+
+NPNInvalidateRectInvalidatesWindow::~NPNInvalidateRectInvalidatesWindow()
+{
+ delete m_windowMover;
+}
+
+NPError NPNInvalidateRectInvalidatesWindow::NPP_SetWindow(NPP instance, NPWindow* npWindow)
+{
+ NPError error = WindowedPluginTest::NPP_SetWindow(instance, npWindow);
+ if (error != NPERR_NO_ERROR)
+ return error;
+
+ if (!window())
+ return NPERR_NO_ERROR;
+
+ // The test harness's window (the one that contains the WebView) is off-screen and hidden.
+ // We need to move it on-screen and make it visible in order for the plugin's window to
+ // accumulate an update region when the DWM is disabled.
+
+ HWND testHarnessWindow = this->testHarnessWindow();
+ if (!testHarnessWindow) {
+ pluginLog(instance, "Failed to get test harness window");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ m_windowMover = new TemporaryWindowMover(testHarnessWindow);
+ if (!m_windowMover->moveSucceeded()) {
+ pluginLog(instance, "Failed to move test harness window on-screen");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // Wait until we receive a WM_PAINT message to ensure that the window is on-screen before we do
+ // the NPN_InvalidateRect test.
+ waitUntilDone();
+ return NPERR_NO_ERROR;
+}
+
+LRESULT NPNInvalidateRectInvalidatesWindow::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
+{
+ if (message == WM_PAINT)
+ onPaint();
+
+ handled = false;
+ return 0;
+}
+
+void NPNInvalidateRectInvalidatesWindow::onPaint()
+{
+ testInvalidateRect();
+ notifyDone();
+ delete m_windowMover;
+ m_windowMover = 0;
+}
+
+void NPNInvalidateRectInvalidatesWindow::testInvalidateRect()
+{
+ RECT clientRect;
+ if (!::GetClientRect(window(), &clientRect)) {
+ pluginLog(m_npp, "::GetClientRect failed");
+ return;
+ }
+
+ if (::IsRectEmpty(&clientRect)) {
+ pluginLog(m_npp, "Plugin's HWND has not been sized when NPP_SetWindow is called");
+ return;
+ }
+
+ // Clear the invalid region.
+ if (!::ValidateRect(window(), 0)) {
+ pluginLog(m_npp, "::ValidateRect failed");
+ return;
+ }
+
+ // Invalidate our lower-right quadrant.
+ NPRect rectToInvalidate;
+ rectToInvalidate.left = (clientRect.right - clientRect.left) / 2;
+ rectToInvalidate.top = (clientRect.bottom - clientRect.top) / 2;
+ rectToInvalidate.right = clientRect.right;
+ rectToInvalidate.bottom = clientRect.bottom;
+ NPN_InvalidateRect(&rectToInvalidate);
+
+ RECT invalidRect;
+ if (!::GetUpdateRect(window(), &invalidRect, FALSE)) {
+ pluginLog(m_npp, "::GetUpdateRect failed");
+ return;
+ }
+
+ if (invalidRect.left != rectToInvalidate.left || invalidRect.top != rectToInvalidate.top || invalidRect.right != rectToInvalidate.right || invalidRect.bottom != rectToInvalidate.bottom) {
+ pluginLog(m_npp, "Expected invalid rect {left=%u, top=%u, right=%u, bottom=%u}, but got {left=%d, top=%d, right=%d, bottom=%d}", rectToInvalidate.left, rectToInvalidate.top, rectToInvalidate.right, rectToInvalidate.bottom, invalidRect.left, invalidRect.top, invalidRect.right, invalidRect.bottom);
+ return;
+ }
+
+ pluginLog(m_npp, "Plugin's HWND has been invalidated as expected");
+}
+
+static PluginTest::Register<NPNInvalidateRectInvalidatesWindow> registrar("npn-invalidate-rect-invalidates-window");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp
new file mode 100644
index 000000000..1c75d27a8
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// Plugin's HWND should be sized/positioned before NPP_SetWindow is called.
+
+class WindowGeometryInitializedBeforeSetWindow : public PluginTest {
+public:
+ WindowGeometryInitializedBeforeSetWindow(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_didReceiveInitialSetWindowCall(false)
+ {
+ }
+
+private:
+ virtual NPError NPP_SetWindow(NPP instance, NPWindow* window)
+ {
+ if (m_didReceiveInitialSetWindowCall)
+ return NPERR_NO_ERROR;
+ m_didReceiveInitialSetWindowCall = true;
+
+ if (window->type != NPWindowTypeWindow) {
+ pluginLog(instance, "window->type should be NPWindowTypeWindow but was %d", window->type);
+ return NPERR_GENERIC_ERROR;
+ }
+
+ HWND hwnd = reinterpret_cast<HWND>(window->window);
+ RECT rect;
+ if (!::GetClientRect(hwnd, &rect)) {
+ pluginLog(instance, "::GetClientRect failed");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (::IsRectEmpty(&rect)) {
+ pluginLog(instance, "Plugin's HWND has not been sized when NPP_SetWindow is called");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if ((rect.right - rect.left) != window->width || (rect.bottom - rect.top) != window->height) {
+ pluginLog(instance, "Size of HWND's rect and size of NPWindow's rect are not equal");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ pluginLog(instance, "Plugin's HWND has been sized before NPP_SetWindow was called");
+ return NPERR_NO_ERROR;
+ }
+
+ bool m_didReceiveInitialSetWindowCall;
+};
+
+static PluginTest::Register<WindowGeometryInitializedBeforeSetWindow> windowGeometryInitializedBeforeSetWindow("window-geometry-initialized-before-set-window");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp
new file mode 100644
index 000000000..7a0098b84
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowGeometryTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// The plugin's window's window region should be set to the plugin's clip rect.
+
+class WindowRegionIsSetToClipRect : public WindowGeometryTest {
+public:
+ WindowRegionIsSetToClipRect(NPP, const string& identifier);
+
+private:
+ virtual void performWindowGeometryTest();
+};
+
+static PluginTest::Register<WindowRegionIsSetToClipRect> registrar("window-region-is-set-to-clip-rect");
+
+WindowRegionIsSetToClipRect::WindowRegionIsSetToClipRect(NPP npp, const string& identifier)
+ : WindowGeometryTest(npp, identifier)
+{
+}
+
+void WindowRegionIsSetToClipRect::performWindowGeometryTest()
+{
+ RECT regionRect;
+ if (::GetWindowRgnBox(window(), &regionRect) == ERROR) {
+ log("::GetWindowRgnBox failed, or window has no window region");
+ return;
+ }
+
+ // This expected rect is based on the layout of window-region-is-set-to-clip-rect.html.
+ RECT expectedRect = { 50, 50, 100, 100 };
+ if (!::EqualRect(&regionRect, &expectedRect)) {
+ log("Expected region rect {left=%u, top=%u, right=%u, bottom=%u}, but got {left=%d, top=%d, right=%d, bottom=%d}", expectedRect.left, expectedRect.top, expectedRect.right, expectedRect.bottom, regionRect.left, regionRect.top, regionRect.right, regionRect.bottom);
+ return;
+ }
+
+ log("PASS: Plugin's window's window region has been set as expected");
+
+ // While we're here, check that our window class doesn't have the CS_PARENTDC style, which
+ // defeats clipping by ignoring the window region and always clipping to the parent window.
+ // FIXME: It would be nice to have a pixel test that shows that we're
+ // getting clipped correctly, but unfortunately window regions are ignored
+ // during WM_PRINT (see <http://webkit.org/b/49034>).
+ wchar_t className[512];
+ if (!::GetClassNameW(window(), className, _countof(className))) {
+ log("::GetClassName failed with error %u", ::GetLastError());
+ return;
+ }
+
+#ifdef DEBUG_ALL
+ const wchar_t webKitDLLName[] = L"WebKit_debug.dll";
+#else
+ const wchar_t webKitDLLName[] = L"WebKit.dll";
+#endif
+ HMODULE webKitModule = ::GetModuleHandleW(webKitDLLName);
+ if (!webKitModule) {
+ log("::GetModuleHandleW failed with error %u", ::GetLastError());
+ return;
+ }
+
+ WNDCLASSW wndClass;
+ if (!::GetClassInfoW(webKitModule, className, &wndClass)) {
+ log("::GetClassInfoW failed with error %u", ::GetLastError());
+ return;
+ }
+
+ if (wndClass.style & CS_PARENTDC)
+ log("FAIL: Plugin's window's class has the CS_PARENTDC style, which will defeat clipping");
+ else
+ log("PASS: Plugin's window's class does not have the CS_PARENTDC style");
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowlessPaintRectCoordinates.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowlessPaintRectCoordinates.cpp
new file mode 100644
index 000000000..ffc92ea2e
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowlessPaintRectCoordinates.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+// The rect passed in the WM_PAINT event for a windowless plugin should be relative to the page's
+// HWND and clipped to the plugin's bounds.
+
+class WindowlessPaintRectCoordinates : public PluginTest {
+public:
+ WindowlessPaintRectCoordinates(NPP, const string& identifier);
+
+private:
+ virtual NPError NPP_New(NPMIMEType, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData*);
+ virtual int16_t NPP_HandleEvent(void* event);
+};
+
+static PluginTest::Register<WindowlessPaintRectCoordinates> registrar("windowless-paint-rect-coordinates");
+
+WindowlessPaintRectCoordinates::WindowlessPaintRectCoordinates(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+{
+}
+
+NPError WindowlessPaintRectCoordinates::NPP_New(NPMIMEType, uint16_t, int16_t, char*[], char*[], NPSavedData*)
+{
+ browser->setvalue(m_npp, NPPVpluginWindowBool, 0);
+ return NPERR_NO_ERROR;
+}
+
+int16_t WindowlessPaintRectCoordinates::NPP_HandleEvent(void* typelessEvent)
+{
+ NPEvent* event = static_cast<NPEvent*>(typelessEvent);
+ if (!event) {
+ pluginLog(m_npp, "NPP_HandleEvent was passed a null event pointer");
+ return 0;
+ }
+
+ if (event->event != WM_PAINT)
+ return 0;
+
+ RECT* paintRect = reinterpret_cast<RECT*>(event->lParam);
+ if (!paintRect) {
+ pluginLog(m_npp, "A null paint rect was passed in the WM_PAINT event");
+ return 1;
+ }
+
+ // Keep these values in sync with windowless-paint-rect-coordinates.html.
+ RECT expectedRect = { 100, 100, 200, 200 };
+
+ if (::EqualRect(paintRect, &expectedRect))
+ pluginLog(m_npp, "Success");
+ else
+ pluginLog(m_npp, "Expected paint rect {left=%d, top=%d, right=%d, bottom=%d}, but got {left=%d, top=%d, right=%d, bottom=%d}", expectedRect.left, expectedRect.top, expectedRect.right, expectedRect.bottom, paintRect->left, paintRect->top, paintRect->right, paintRect->bottom);
+
+ return 1;
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp
new file mode 100644
index 000000000..8d25d3906
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/x11/CallInvalidateRectWithNullNPPArgument.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+class CallInvalidateRectWithNullNPPArgument : public PluginTest {
+public:
+ CallInvalidateRectWithNullNPPArgument(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
+ {
+ NPRect rect;
+ browser->invalidaterect(0, &rect);
+ pluginLog(m_npp, "SUCCESS!");
+ return NPERR_NO_ERROR;
+ }
+
+};
+
+static PluginTest::Register<CallInvalidateRectWithNullNPPArgument> callInvalidateRectWithNullNPPArgument("call-invalidate-rect-with-null-npp-argument");
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist b/Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist
new file mode 100644
index 000000000..ef45e66d2
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>TestNetscapePlugIn</string>
+ <key>CFBundleGetInfoString</key>
+ <string>420+, Copyright 2006-2009 Apple Inc.</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.testnetscapeplugin</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BRPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CFPlugInDynamicRegisterFunction</key>
+ <string></string>
+ <key>CFPlugInDynamicRegistration</key>
+ <string>NO</string>
+ <key>CFPlugInFactories</key>
+ <dict>
+ <key>00000000-0000-0000-0000-000000000000</key>
+ <string>MyFactoryFunction</string>
+ </dict>
+ <key>CFPlugInTypes</key>
+ <dict>
+ <key>00000000-0000-0000-0000-000000000000</key>
+ <array>
+ <string>00000000-0000-0000-0000-000000000000</string>
+ </array>
+ </dict>
+ <key>CFPlugInUnloadFunction</key>
+ <string></string>
+ <key>WebPluginDescription</key>
+ <string>Simple Netscape plug-in that handles test content for WebKit</string>
+ <key>WebPluginMIMETypes</key>
+ <dict>
+ <key>image/png</key>
+ <dict>
+ <key>WebPluginExtensions</key>
+ <array>
+ <string>png</string>
+ </array>
+ <key>WebPluginTypeDescription</key>
+ <string>PNG image</string>
+ </dict>
+ <key>application/x-webkit-test-netscape</key>
+ <dict>
+ <key>WebPluginExtensions</key>
+ <array>
+ <string>testnetscape</string>
+ </array>
+ <key>WebPluginTypeDescription</key>
+ <string>test netscape content</string>
+ </dict>
+ </dict>
+ <key>WebPluginName</key>
+ <string>WebKit Test PlugIn</string>
+</dict>
+</plist>
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp
new file mode 100644
index 000000000..c07bb2739
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp
@@ -0,0 +1,833 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginObject.h"
+
+#include "PluginTest.h"
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#ifdef XP_UNIX
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#endif
+
+#if !defined(NP_NO_CARBON) && defined(QD_HEADERS_ARE_PRIVATE) && QD_HEADERS_ARE_PRIVATE
+extern "C" void GlobalToLocal(Point*);
+#endif
+
+using namespace std;
+
+#define CRASH() do { \
+ *(int *)(uintptr_t)0xbbadbeef = 0; \
+ ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
+} while(false)
+
+static bool getEntryPointsWasCalled;
+static bool initializeWasCalled;
+
+#if defined(XP_WIN)
+#define STDCALL __stdcall
+
+static inline int strcasecmp(const char* s1, const char* s2)
+{
+ return _stricmp(s1, s2);
+}
+
+#else
+#define STDCALL
+#endif
+
+extern "C" {
+NPError STDCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs);
+}
+
+// Entry points
+extern "C"
+NPError STDCALL NP_Initialize(NPNetscapeFuncs *browserFuncs
+#ifdef XP_UNIX
+ , NPPluginFuncs *pluginFuncs
+#endif
+ )
+{
+ initializeWasCalled = true;
+
+#if defined(XP_WIN)
+ // Simulate Flash and QuickTime's behavior of crashing when NP_Initialize is called before NP_GetEntryPoints.
+ if (!getEntryPointsWasCalled)
+ CRASH();
+#endif
+
+ browser = browserFuncs;
+
+#ifdef XP_UNIX
+ return NP_GetEntryPoints(pluginFuncs);
+#else
+ return NPERR_NO_ERROR;
+#endif
+}
+
+extern "C"
+NPError STDCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs)
+{
+ getEntryPointsWasCalled = true;
+
+#ifdef XP_MACOSX
+ // Simulate Silverlight's behavior of crashing when NP_GetEntryPoints is called before NP_Initialize.
+ if (!initializeWasCalled)
+ CRASH();
+#endif
+
+ pluginFunctions = pluginFuncs;
+
+ pluginFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+ pluginFuncs->size = sizeof(pluginFuncs);
+ pluginFuncs->newp = NPP_New;
+ pluginFuncs->destroy = NPP_Destroy;
+ pluginFuncs->setwindow = NPP_SetWindow;
+ pluginFuncs->newstream = NPP_NewStream;
+ pluginFuncs->destroystream = NPP_DestroyStream;
+ pluginFuncs->asfile = NPP_StreamAsFile;
+ pluginFuncs->writeready = NPP_WriteReady;
+ pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
+ pluginFuncs->print = NPP_Print;
+ pluginFuncs->event = NPP_HandleEvent;
+ pluginFuncs->urlnotify = NPP_URLNotify;
+ pluginFuncs->getvalue = NPP_GetValue;
+ pluginFuncs->setvalue = NPP_SetValue;
+
+ return NPERR_NO_ERROR;
+}
+
+extern "C"
+void STDCALL NP_Shutdown(void)
+{
+ PluginTest::NP_Shutdown();
+}
+
+static void executeScript(const PluginObject* obj, const char* script);
+
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved)
+{
+#ifdef XP_MACOSX
+ NPEventModel eventModel;
+
+ // Always turn on the CG model
+ NPBool supportsCoreGraphics;
+ if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR)
+ supportsCoreGraphics = false;
+
+ if (!supportsCoreGraphics)
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+
+ NPDrawingModel drawingModelToUse = NPDrawingModelCoreGraphics;
+
+ NPBool supportsCoreAnimation;
+ if (browser->getvalue(instance, NPNVsupportsCoreAnimationBool, &supportsCoreAnimation) != NPERR_NO_ERROR)
+ supportsCoreAnimation = false;
+
+#ifndef NP_NO_CARBON
+ NPBool supportsCarbon = false;
+#endif
+ NPBool supportsCocoa = false;
+
+#ifndef NP_NO_CARBON
+ // A browser that doesn't know about NPNVsupportsCarbonBool is one that only supports Carbon event model.
+ if (browser->getvalue(instance, NPNVsupportsCarbonBool, &supportsCarbon) != NPERR_NO_ERROR)
+ supportsCarbon = true;
+#endif
+
+ if (browser->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR)
+ supportsCocoa = false;
+
+ if (supportsCocoa) {
+ eventModel = NPEventModelCocoa;
+#ifndef NP_NO_CARBON
+ } else if (supportsCarbon) {
+ eventModel = NPEventModelCarbon;
+#endif
+ } else {
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ }
+
+ browser->setvalue(instance, NPPVpluginEventModel, (void *)eventModel);
+#endif // XP_MACOSX
+
+ PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass());
+ instance->pdata = obj;
+
+#ifdef XP_MACOSX
+ obj->eventModel = eventModel;
+ obj->coreAnimationLayer = 0;
+#endif // XP_MACOSX
+
+ string testIdentifier;
+ const char* onNewScript = 0;
+
+ for (int i = 0; i < argc; i++) {
+ if (strcasecmp(argn[i], "test") == 0)
+ testIdentifier = argv[i];
+ if (strcasecmp(argn[i], "onstreamload") == 0 && !obj->onStreamLoad)
+ obj->onStreamLoad = strdup(argv[i]);
+ else if (strcasecmp(argn[i], "onStreamDestroy") == 0 && !obj->onStreamDestroy)
+ obj->onStreamDestroy = strdup(argv[i]);
+ else if (strcasecmp(argn[i], "onURLNotify") == 0 && !obj->onURLNotify)
+ obj->onURLNotify = strdup(argv[i]);
+ else if (strcasecmp(argn[i], "src") == 0 &&
+ strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0)
+ obj->returnErrorFromNewStream = TRUE;
+ else if (strcasecmp(argn[i], "src") == 0 &&
+ strcasecmp(argv[i], "data:application/x-webkit-test-netscape,alertwhenloaded") == 0)
+ executeScript(obj, "alert('Plugin Loaded!')");
+ else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow)
+ obj->onSetWindow = strdup(argv[i]);
+ else if (strcasecmp(argn[i], "onNew") == 0 && !onNewScript)
+ onNewScript = argv[i];
+ else if (strcasecmp(argn[i], "onPaintEvent") == 0 && !obj->onPaintEvent)
+ obj->onPaintEvent = strdup(argv[i]);
+ else if (strcasecmp(argn[i], "logfirstsetwindow") == 0)
+ obj->logSetWindow = TRUE;
+ else if (strcasecmp(argn[i], "testnpruntime") == 0)
+ testNPRuntime(instance);
+ else if (strcasecmp(argn[i], "logSrc") == 0) {
+ for (int i = 0; i < argc; i++)
+ if (strcasecmp(argn[i], "src") == 0)
+ pluginLog(instance, "src: %s", argv[i]);
+ } else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0)
+ executeScript(obj, "document.body.innerHTML = ''");
+ else if (!strcasecmp(argn[i], "ondestroy"))
+ obj->onDestroy = strdup(argv[i]);
+ else if (strcasecmp(argn[i], "testwindowopen") == 0)
+ obj->testWindowOpen = TRUE;
+ else if (strcasecmp(argn[i], "drawingmodel") == 0) {
+#ifdef XP_MACOSX
+ const char* value = argv[i];
+ if (strcasecmp(value, "coreanimation") == 0) {
+ if (supportsCoreAnimation)
+ drawingModelToUse = NPDrawingModelCoreAnimation;
+ else
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ } else if (strcasecmp(value, "coregraphics") == 0) {
+ if (supportsCoreGraphics)
+ drawingModelToUse = NPDrawingModelCoreGraphics;
+ else
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ } else
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+#endif
+ } else if (strcasecmp(argn[i], "testGetURLOnDestroy") == 0) {
+#if defined(XP_WIN)
+ // FIXME: When https://bugs.webkit.org/show_bug.cgi?id=41831 is fixed, this #ifdef can be removed.
+ obj->testGetURLOnDestroy = TRUE;
+#endif
+ } else if (!strcasecmp(argn[i], "src") && strstr(argv[i], "plugin-document-has-focus.pl"))
+ obj->testKeyboardFocusForPlugins = TRUE;
+ else if (!strcasecmp(argn[i], "evaluatescript")) {
+ char* script = argv[i];
+ if (script == strstr(script, "mouse::")) {
+ obj->mouseDownForEvaluateScript = true;
+ obj->evaluateScriptOnMouseDownOrKeyDown = strdup(script + sizeof("mouse::") - 1);
+ } else if (script == strstr(script, "key::")) {
+ obj->evaluateScriptOnMouseDownOrKeyDown = strdup(script + sizeof("key::") - 1);
+ }
+ // When testing evaluate script on mouse-down or key-down, allow event logging to handle events.
+ if (obj->evaluateScriptOnMouseDownOrKeyDown)
+ obj->eventLogging = true;
+ } else if (!strcasecmp(argn[i], "windowedPlugin")) {
+ void* windowed = 0;
+ if (!strcasecmp(argv[i], "false") || !strcasecmp(argv[i], "0"))
+ windowed = 0;
+ else if (!strcasecmp(argv[i], "true") || !strcasecmp(argv[i], "1"))
+ windowed = reinterpret_cast<void*>(1);
+ else
+ assert(false);
+ browser->setvalue(instance, NPPVpluginWindowBool, windowed);
+ }
+ }
+
+#ifdef XP_MACOSX
+ browser->setvalue(instance, NPPVpluginDrawingModel, (void *)drawingModelToUse);
+ if (drawingModelToUse == NPDrawingModelCoreAnimation)
+ obj->coreAnimationLayer = createCoreAnimationLayer();
+#endif
+
+ obj->pluginTest = PluginTest::create(instance, testIdentifier);
+
+ if (!obj->pluginTest) {
+ pluginLog(instance, "NPP_New: Could not find a test named \"%s\", maybe its .cpp file wasn't added to the build system?", testIdentifier.c_str());
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (onNewScript)
+ executeScript(obj, onNewScript);
+
+ return obj->pluginTest->NPP_New(pluginType, mode, argc, argn, argv, saved);
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData **save)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ if (obj) {
+ if (obj->testGetURLOnDestroy)
+ browser->geturlnotify(obj->npp, "about:blank", "", 0);
+
+ if (obj->onDestroy) {
+ executeScript(obj, obj->onDestroy);
+ free(obj->onDestroy);
+ }
+
+ if (obj->onStreamLoad)
+ free(obj->onStreamLoad);
+
+ if (obj->onStreamDestroy)
+ free(obj->onStreamDestroy);
+
+ if (obj->onURLNotify)
+ free(obj->onURLNotify);
+
+ if (obj->onSetWindow)
+ free(obj->onSetWindow);
+
+ if (obj->onPaintEvent)
+ free(obj->onPaintEvent);
+
+ if (obj->logDestroy)
+ pluginLog(instance, "NPP_Destroy");
+
+#ifdef XP_MACOSX
+ if (obj->coreAnimationLayer)
+ CFRelease(obj->coreAnimationLayer);
+#endif
+
+ if (obj->pluginTest)
+ obj->pluginTest->NPP_Destroy(save);
+
+ browser->releaseobject(&obj->header);
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_SetWindow(NPP instance, NPWindow *window)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+ if (obj) {
+ obj->lastWindow = *window;
+
+ if (obj->logSetWindow) {
+ pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
+ obj->logSetWindow = FALSE;
+ }
+
+ if (obj->onSetWindow)
+ executeScript(obj, obj->onSetWindow);
+
+ if (obj->testWindowOpen) {
+ testWindowOpen(instance);
+ obj->testWindowOpen = FALSE;
+ }
+
+ if (obj->testKeyboardFocusForPlugins) {
+ obj->eventLogging = true;
+ executeScript(obj, "eventSender.keyDown('A');");
+ }
+ }
+
+ return obj->pluginTest->NPP_SetWindow(window);
+}
+
+static void executeScript(const PluginObject* obj, const char* script)
+{
+ NPObject *windowScriptObject;
+ browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
+
+ NPString npScript;
+ npScript.UTF8Characters = script;
+ npScript.UTF8Length = strlen(script);
+
+ NPVariant browserResult;
+ browser->evaluate(obj->npp, windowScriptObject, &npScript, &browserResult);
+ browser->releasevariantvalue(&browserResult);
+}
+
+NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16_t *stype)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ obj->stream = stream;
+ *stype = NP_NORMAL;
+
+ if (obj->returnErrorFromNewStream)
+ return NPERR_GENERIC_ERROR;
+
+ if (browser->version >= NPVERS_HAS_RESPONSE_HEADERS)
+ notifyStream(obj, stream->url, stream->headers);
+
+ if (obj->onStreamLoad)
+ executeScript(obj, obj->onStreamLoad);
+
+ return obj->pluginTest->NPP_NewStream(type, stream, seekable, stype);
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
+{
+ PluginObject* obj = (PluginObject*)instance->pdata;
+
+ if (obj->onStreamDestroy) {
+ NPObject* windowObject = 0;
+ NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
+
+ if (error == NPERR_NO_ERROR) {
+ NPVariant onStreamDestroyVariant;
+ if (browser->getproperty(instance, windowObject, browser->getstringidentifier(obj->onStreamDestroy), &onStreamDestroyVariant)) {
+ if (NPVARIANT_IS_OBJECT(onStreamDestroyVariant)) {
+ NPObject* onStreamDestroyFunction = NPVARIANT_TO_OBJECT(onStreamDestroyVariant);
+
+ NPVariant reasonVariant;
+ INT32_TO_NPVARIANT(reason, reasonVariant);
+
+ NPVariant result;
+ browser->invokeDefault(instance, onStreamDestroyFunction, &reasonVariant, 1, &result);
+ browser->releasevariantvalue(&result);
+ }
+ browser->releasevariantvalue(&onStreamDestroyVariant);
+ }
+ browser->releaseobject(windowObject);
+ }
+ }
+
+ return obj->pluginTest->NPP_DestroyStream(stream, reason);
+}
+
+int32_t NPP_WriteReady(NPP instance, NPStream *stream)
+{
+ PluginObject* obj = (PluginObject*)instance->pdata;
+ return obj->pluginTest->NPP_WriteReady(stream);
+}
+
+int32_t NPP_Write(NPP instance, NPStream *stream, int32_t offset, int32_t len, void *buffer)
+{
+ PluginObject* obj = (PluginObject*)instance->pdata;
+
+ if (obj->returnNegativeOneFromWrite)
+ return -1;
+
+ return obj->pluginTest->NPP_Write(stream, offset, len, buffer);
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname)
+{
+}
+
+void NPP_Print(NPP instance, NPPrint *platformPrint)
+{
+}
+
+#ifdef XP_MACOSX
+#ifndef NP_NO_CARBON
+static int16_t handleEventCarbon(NPP instance, PluginObject* obj, EventRecord* event)
+{
+ Point pt = { event->where.v, event->where.h };
+
+ switch (event->what) {
+ case nullEvent:
+ // these are delivered non-deterministically, don't log.
+ break;
+ case mouseDown:
+ if (obj->eventLogging) {
+ GlobalToLocal(&pt);
+ pluginLog(instance, "mouseDown at (%d, %d)", pt.h, pt.v);
+ }
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ break;
+ case mouseUp:
+ if (obj->eventLogging) {
+ GlobalToLocal(&pt);
+ pluginLog(instance, "mouseUp at (%d, %d)", pt.h, pt.v);
+ }
+ break;
+ case keyDown:
+ if (obj->eventLogging)
+ pluginLog(instance, "keyDown '%c'", (char)(event->message & 0xFF));
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ break;
+ case keyUp:
+ if (obj->eventLogging)
+ pluginLog(instance, "keyUp '%c'", (char)(event->message & 0xFF));
+ if (obj->testKeyboardFocusForPlugins) {
+ obj->eventLogging = false;
+ obj->testKeyboardFocusForPlugins = FALSE;
+ executeScript(obj, "layoutTestController.notifyDone();");
+ }
+ break;
+ case autoKey:
+ if (obj->eventLogging)
+ pluginLog(instance, "autoKey '%c'", (char)(event->message & 0xFF));
+ break;
+ case updateEvt:
+ if (obj->eventLogging)
+ pluginLog(instance, "updateEvt");
+ break;
+ case diskEvt:
+ if (obj->eventLogging)
+ pluginLog(instance, "diskEvt");
+ break;
+ case activateEvt:
+ if (obj->eventLogging)
+ pluginLog(instance, "activateEvt");
+ break;
+ case osEvt:
+ if (!obj->eventLogging)
+ break;
+ printf("PLUGIN: osEvt - ");
+ switch ((event->message & 0xFF000000) >> 24) {
+ case suspendResumeMessage:
+ printf("%s\n", (event->message & 0x1) ? "resume" : "suspend");
+ break;
+ case mouseMovedMessage:
+ printf("mouseMoved\n");
+ break;
+ default:
+ printf("%08lX\n", event->message);
+ }
+ break;
+ case kHighLevelEvent:
+ if (obj->eventLogging)
+ pluginLog(instance, "kHighLevelEvent");
+ break;
+ // NPAPI events
+ case NPEventType_GetFocusEvent:
+ if (obj->eventLogging)
+ pluginLog(instance, "getFocusEvent");
+ break;
+ case NPEventType_LoseFocusEvent:
+ if (obj->eventLogging)
+ pluginLog(instance, "loseFocusEvent");
+ break;
+ case NPEventType_AdjustCursorEvent:
+ if (obj->eventLogging)
+ pluginLog(instance, "adjustCursorEvent");
+ break;
+ default:
+ if (obj->eventLogging)
+ pluginLog(instance, "event %d", event->what);
+ }
+
+ return 0;
+}
+#endif
+
+static int16_t handleEventCocoa(NPP instance, PluginObject* obj, NPCocoaEvent* event)
+{
+ switch (event->type) {
+ case NPCocoaEventWindowFocusChanged:
+
+ case NPCocoaEventFocusChanged:
+ if (obj->eventLogging) {
+ if (event->data.focus.hasFocus)
+ pluginLog(instance, "getFocusEvent");
+ else
+ pluginLog(instance, "loseFocusEvent");
+ }
+ return 1;
+
+ case NPCocoaEventDrawRect: {
+ if (obj->onPaintEvent)
+ executeScript(obj, obj->onPaintEvent);
+ return 1;
+ }
+
+ case NPCocoaEventKeyDown:
+ if (obj->eventLogging && event->data.key.characters)
+ pluginLog(instance, "keyDown '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0));
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ return 1;
+
+ case NPCocoaEventKeyUp:
+ if (obj->eventLogging && event->data.key.characters) {
+ pluginLog(instance, "keyUp '%c'", CFStringGetCharacterAtIndex(reinterpret_cast<CFStringRef>(event->data.key.characters), 0));
+ if (obj->testKeyboardFocusForPlugins) {
+ obj->eventLogging = false;
+ obj->testKeyboardFocusForPlugins = FALSE;
+ executeScript(obj, "layoutTestController.notifyDone();");
+ }
+ }
+ return 1;
+
+ case NPCocoaEventFlagsChanged:
+ return 1;
+
+ case NPCocoaEventMouseDown:
+ if (obj->eventLogging) {
+ pluginLog(instance, "mouseDown at (%d, %d)",
+ (int)event->data.mouse.pluginX,
+ (int)event->data.mouse.pluginY);
+ }
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ return 1;
+ case NPCocoaEventMouseUp:
+ if (obj->eventLogging) {
+ pluginLog(instance, "mouseUp at (%d, %d)",
+ (int)event->data.mouse.pluginX,
+ (int)event->data.mouse.pluginY);
+ }
+ return 1;
+
+ case NPCocoaEventMouseMoved:
+ case NPCocoaEventMouseEntered:
+ case NPCocoaEventMouseExited:
+ case NPCocoaEventMouseDragged:
+ case NPCocoaEventScrollWheel:
+ case NPCocoaEventTextInput:
+ return 1;
+ }
+
+ return 0;
+}
+
+#endif // XP_MACOSX
+
+#ifdef XP_UNIX
+
+static char keyEventToChar(XKeyEvent* event)
+{
+ char c = ' ';
+ XLookupString(event, &c, sizeof(c), 0, 0);
+ return c;
+}
+
+static int16_t handleEventX11(NPP instance, PluginObject* obj, XEvent* event)
+{
+ switch (event->type) {
+ case ButtonPress:
+ if (obj->eventLogging)
+ pluginLog(instance, "mouseDown at (%d, %d)", event->xbutton.x, event->xbutton.y);
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ break;
+ case ButtonRelease:
+ if (obj->eventLogging)
+ pluginLog(instance, "mouseUp at (%d, %d)", event->xbutton.x, event->xbutton.y);
+ break;
+ case KeyPress:
+ // FIXME: extract key code
+ if (obj->eventLogging)
+ pluginLog(instance, "keyDown '%c'", keyEventToChar(&event->xkey));
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ break;
+ case KeyRelease:
+ // FIXME: extract key code
+ if (obj->eventLogging)
+ pluginLog(instance, "keyUp '%c'", keyEventToChar(&event->xkey));
+ break;
+ case GraphicsExpose:
+ if (obj->eventLogging)
+ pluginLog(instance, "updateEvt");
+ if (obj->onPaintEvent)
+ executeScript(obj, obj->onPaintEvent);
+ break;
+ // NPAPI events
+ case FocusIn:
+ if (obj->eventLogging)
+ pluginLog(instance, "getFocusEvent");
+ break;
+ case FocusOut:
+ if (obj->eventLogging)
+ pluginLog(instance, "loseFocusEvent");
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ case MotionNotify:
+ break;
+ default:
+ if (obj->eventLogging)
+ pluginLog(instance, "event %d", event->type);
+ }
+
+ fflush(stdout);
+ return 0;
+}
+#endif // XP_UNIX
+
+#ifdef XP_WIN
+static int16_t handleEventWin(NPP instance, PluginObject* obj, NPEvent* event)
+{
+ switch (event->event) {
+ case WM_PAINT:
+ if (obj->onPaintEvent)
+ executeScript(obj, obj->onPaintEvent);
+ break;
+ case WM_KEYDOWN:
+ if (obj->eventLogging)
+ pluginLog(instance, "keyDown '%c'", event->wParam);
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ break;
+ case WM_CHAR:
+ break;
+ case WM_KEYUP:
+ if (obj->eventLogging)
+ pluginLog(instance, "keyUp '%c'", event->wParam);
+ if (obj->testKeyboardFocusForPlugins) {
+ obj->eventLogging = false;
+ obj->testKeyboardFocusForPlugins = FALSE;
+ executeScript(obj, "layoutTestController.notifyDone();");
+ }
+ break;
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ if (obj->eventLogging)
+ pluginLog(instance, "mouseDown at (%d, %d)", LOWORD(event->lParam), HIWORD(event->lParam));
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ break;
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ if (obj->eventLogging)
+ pluginLog(instance, "mouseUp at (%d, %d)", LOWORD(event->lParam), HIWORD(event->lParam));
+ break;
+ case WM_SETFOCUS:
+ if (obj->eventLogging)
+ pluginLog(instance, "getFocusEvent");
+ break;
+ case WM_KILLFOCUS:
+ if (obj->eventLogging)
+ pluginLog(instance, "loseFocusEvent");
+ break;
+ }
+ return 0;
+}
+#endif // XP_WIN
+
+int16_t NPP_HandleEvent(NPP instance, void *event)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+ if (obj->pluginTest->NPP_HandleEvent(event) == 1)
+ return 1;
+
+#ifdef XP_MACOSX
+#ifndef NP_NO_CARBON
+ if (obj->eventModel == NPEventModelCarbon)
+ return handleEventCarbon(instance, obj, static_cast<EventRecord*>(event));
+#endif
+
+ assert(obj->eventModel == NPEventModelCocoa);
+ return handleEventCocoa(instance, obj, static_cast<NPCocoaEvent*>(event));
+#elif defined(XP_UNIX)
+ return handleEventX11(instance, obj, static_cast<XEvent*>(event));
+#elif defined(XP_WIN)
+ return handleEventWin(instance, obj, static_cast<NPEvent*>(event));
+#else
+ // FIXME: Implement for other platforms.
+ return 0;
+#endif // XP_MACOSX
+}
+
+void NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ if (obj->pluginTest->NPP_URLNotify(url, reason, notifyData))
+ return;
+
+ if (obj->onURLNotify)
+ executeScript(obj, obj->onURLNotify);
+
+ handleCallback(obj, url, reason, notifyData);
+}
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
+{
+#ifdef XP_UNIX
+ if (variable == NPPVpluginNameString) {
+ *((char **)value) = const_cast<char*>("WebKit Test PlugIn");
+ return NPERR_NO_ERROR;
+ }
+ if (variable == NPPVpluginDescriptionString) {
+ *((char **)value) = const_cast<char*>("Simple Netscape plug-in that handles test content for WebKit");
+ return NPERR_NO_ERROR;
+ }
+ if (variable == NPPVpluginNeedsXEmbed) {
+ *((NPBool *)value) = TRUE;
+ return NPERR_NO_ERROR;
+ }
+#endif
+
+ if (!instance)
+ return NPERR_GENERIC_ERROR;
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+ // First, check if the PluginTest object supports getting this value.
+ if (obj->pluginTest->NPP_GetValue(variable, value) == NPERR_NO_ERROR)
+ return NPERR_NO_ERROR;
+
+ if (variable == NPPVpluginScriptableNPObject) {
+ void **v = (void **)value;
+ // Return value is expected to be retained
+ browser->retainobject((NPObject *)obj);
+ *v = obj;
+ return NPERR_NO_ERROR;
+ }
+
+#ifdef XP_MACOSX
+ if (variable == NPPVpluginCoreAnimationLayer) {
+ if (!obj->coreAnimationLayer)
+ return NPERR_GENERIC_ERROR;
+
+ void **v = (void **)value;
+ *v = (void*)CFRetain(obj->coreAnimationLayer);
+ return NPERR_NO_ERROR;
+ }
+#endif
+
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ return obj->pluginTest->NPP_SetValue(variable, value);
+}
+
+#ifdef XP_UNIX
+extern "C"
+const char* NP_GetMIMEDescription(void)
+{
+ return "application/x-webkit-test-netscape:testnetscape:test netscape content;image/png:png:PNG image";
+}
+
+extern "C"
+NPError NP_GetValue(NPP instance, NPPVariable variable, void* value)
+{
+ return NPP_GetValue(instance, variable, value);
+}
+#endif
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/CallJSThatDestroysPlugin.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/win/CallJSThatDestroysPlugin.cpp
new file mode 100644
index 000000000..39c6365a6
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/CallJSThatDestroysPlugin.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "PluginTest.h"
+
+#include <string.h>
+#include <vector>
+
+using namespace std;
+
+// Test that evaluating JavaScript that removes the plug-in from the page
+// destroys the plug-in asynchronously.
+class CallJSThatDestroysPlugin : public PluginTest {
+public:
+ CallJSThatDestroysPlugin(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_isDestroyed(false)
+ , m_window(0)
+ {
+ }
+ ~CallJSThatDestroysPlugin();
+
+ void runTest();
+
+private:
+ virtual NPError NPP_New(NPMIMEType, uint16_t, int16_t, char*[], char*[], NPSavedData*);
+ virtual NPError NPP_Destroy(NPSavedData**);
+
+ bool m_isDestroyed;
+ HWND m_window;
+};
+
+static PluginTest::Register<CallJSThatDestroysPlugin> registrar("call-javascript-that-destroys-plugin");
+
+static const LPCWSTR pluginTestProperty = L"PluginTestProperty";
+static const UINT runTestWindowMessage = WM_USER + 1;
+static const LPCWSTR messageWindowClassName = L"CallJSThatDestroysPluginMessageWindow";
+
+CallJSThatDestroysPlugin::~CallJSThatDestroysPlugin()
+{
+ ::RemovePropW(m_window, pluginTestProperty);
+ ::DestroyWindow(m_window);
+}
+
+void CallJSThatDestroysPlugin::runTest()
+{
+ executeScript("var plugin = document.getElementsByTagName('embed')[0]; plugin.parentElement.removeChild(plugin);");
+ if (!m_isDestroyed)
+ log("Success: executed script, and plug-in is not yet destroyed.");
+}
+
+static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg != runTestWindowMessage)
+ return ::DefWindowProcW(hwnd, msg, wParam, lParam);
+
+ CallJSThatDestroysPlugin* pluginTest = reinterpret_cast<CallJSThatDestroysPlugin*>(::GetPropW(hwnd, pluginTestProperty));
+ pluginTest->runTest();
+ return 0;
+}
+
+NPError CallJSThatDestroysPlugin::NPP_New(NPMIMEType, uint16_t, int16_t, char*[], char*[], NPSavedData*)
+{
+ assert(!m_window);
+
+ waitUntilDone();
+
+ WNDCLASSEXW wndClass = {0};
+ wndClass.cbSize = sizeof(wndClass);
+ wndClass.lpfnWndProc = wndProc;
+ wndClass.hCursor = LoadCursor(0, IDC_ARROW);
+ wndClass.hInstance = GetModuleHandle(0);
+ wndClass.lpszClassName = messageWindowClassName;
+
+ ::RegisterClassExW(&wndClass);
+ m_window = ::CreateWindowExW(0, messageWindowClassName, 0, WS_CHILD, 0, 0, 0, 0, HWND_MESSAGE, 0, GetModuleHandle(0), 0);
+
+ ::SetPropW(m_window, pluginTestProperty, reinterpret_cast<HANDLE>(this));
+ ::PostMessageW(m_window, runTestWindowMessage, 0, 0);
+
+ return NPERR_NO_ERROR;
+}
+
+NPError CallJSThatDestroysPlugin::NPP_Destroy(NPSavedData**)
+{
+ m_isDestroyed = true;
+ log("Plug-in destroyed.");
+ notifyDone();
+ return NPERR_NO_ERROR;
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def
new file mode 100644
index 000000000..ac41e7ede
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def
@@ -0,0 +1,6 @@
+LIBRARY "npTestNetscapePlugin"
+
+EXPORTS
+ NP_GetEntryPoints @1
+ NP_Initialize @2
+ NP_Shutdown @3
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc
new file mode 100644
index 000000000..c0b38ee5f
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "windows.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""windows.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "CompanyName", "Apple Inc."
+ VALUE "FileDescription", "Simple Netscape plug-in that handles test content for WebKit"
+ VALUE "FileExtents", "testnetscape|png"
+ VALUE "FileOpenName", "test netscape content|PNG image"
+ VALUE "LegalCopyright", "Copyright Apple Inc. 2007-2009"
+ VALUE "MIMEType", "application/x-webkit-test-netscape|image/png"
+ VALUE "OriginalFilename", "npTestNetscapePlugin.dll"
+ VALUE "ProductName", "WebKit Test PlugIn"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj
new file mode 100644
index 000000000..28416b242
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj
@@ -0,0 +1,556 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestNetscapePlugin"
+ ProjectGUID="{C0737398-3565-439E-A2B8-AB2BE4D5430C}"
+ RootNamespace="TestNetscapePlugin"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\TestNetscapePluginDebug.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\TestNetscapePluginRelease.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_Cairo_CFLite|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\TestNetscapePluginDebugCairoCFLite.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\TestNetscapePluginDebugAll.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Production|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\TestNetscapePluginProduction.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_Cairo_CFLite|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\TestNetscapePluginReleaseCairoCFLite.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Tests"
+ >
+ <File
+ RelativePath=".\CallJSThatDestroysPlugin.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\DocumentOpenInDestroyStream.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\EvaluateJSAfterRemovingPluginElement.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\FormValue.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\GetURLNotifyWithURLThatFailsToLoad.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\GetURLWithJavaScriptURL.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\GetURLWithJavaScriptURLDestroyingPlugin.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\GetUserAgentWithNullNPPFromNPPNew.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\NPDeallocateCalledBeforeNPShutdown.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\NPPSetWindowCalledDuringDestruction.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\NPRuntimeObjectFromDestroyedPlugin.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\NPRuntimeRemoveProperty.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\NullNPPGetValuePointer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\PassDifferentNPPStruct.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\PluginScriptableNPObjectInvokeDefault.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\PrivateBrowsing.cpp"
+ >
+ </File>
+ <Filter
+ Name="win"
+ >
+ <File
+ RelativePath="..\Tests\win\DrawsGradient.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\win\DumpWindowRect.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\win\GetValueNetscapeWindow.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\win\NPNInvalidateRectInvalidatesWindow.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\win\WindowGeometryInitializedBeforeSetWindow.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\win\WindowlessPaintRectCoordinates.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\win\WindowRegionIsSetToClipRect.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="win"
+ >
+ <File
+ RelativePath=".\WindowedPluginTest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\WindowedPluginTest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WindowGeometryTest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\WindowGeometryTest.h"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath="..\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\PluginObject.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\PluginObject.h"
+ >
+ </File>
+ <File
+ RelativePath="..\PluginTest.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\PluginTest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ <File
+ RelativePath=".\TestNetscapePlugin.def"
+ >
+ </File>
+ <File
+ RelativePath=".\TestNetscapePlugin.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\TestNetscapePlugin_debug.def"
+ >
+ </File>
+ <File
+ RelativePath="..\TestObject.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\TestObject.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops
new file mode 100644
index 000000000..4608b320a
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestNetscapePluginCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)&quot;;&quot;$(ProjectDir)..&quot;;&quot;$(ConfigurationBuildDir)\Include&quot;;&quot;$(ConfigurationBuildDir)\Include\JavaScriptCore&quot;;&quot;$(ConfigurationBuildDir)\Include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitLibrariesDir)\include&quot;"
+ PreprocessorDefinitions="_USRDLL;TESTNETSCAPEPLUGIN_EXPORTS;snprintf=_snprintf"
+ DisableSpecificWarnings="4819"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Msimg32.lib"
+ OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix)\np$(ProjectName)$(WebKitConfigSuffix).dll"
+ ModuleDefinitionFile="TestNetscapePlugin$(WebKitConfigSuffix).def"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebug.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebug.vsprops
new file mode 100644
index 000000000..1d69ebbbf
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebug.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestNetscapePluginDebug"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\TestNetscapePluginCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugAll.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugAll.vsprops
new file mode 100644
index 000000000..92e186e30
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugAll.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestNetscapePluginDebugAll"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\TestNetscapePluginCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugCairoCFLite.vsprops
new file mode 100644
index 000000000..f9b45b320
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginDebugCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestNetscapePluginDebugCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\TestNetscapePluginCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd
new file mode 100644
index 000000000..26707cac6
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd
@@ -0,0 +1 @@
+if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed"
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd
new file mode 100644
index 000000000..a77077674
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd
@@ -0,0 +1,6 @@
+%SystemDrive%\cygwin\bin\which.exe bash
+if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
+cmd /c
+if exist "%CONFIGURATIONBUILDDIR%\buildfailed" grep XX%PROJECTNAME%XX "%CONFIGURATIONBUILDDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed"
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops
new file mode 100644
index 000000000..a0699e3e2
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestNetscapePluginProduction"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\TestNetscapePluginCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops
new file mode 100644
index 000000000..a6ab3a2ee
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestNetscapePluginRelease"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\TestNetscapePluginCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops
new file mode 100644
index 000000000..99f879d77
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestNetscapePluginReleaseCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\TestNetscapePluginCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def
new file mode 100644
index 000000000..158fb7c2b
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def
@@ -0,0 +1,6 @@
+LIBRARY "npTestNetscapePlugin_debug"
+
+EXPORTS
+ NP_GetEntryPoints @1
+ NP_Initialize @2
+ NP_Shutdown @3
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.cpp
new file mode 100644
index 000000000..be7bfb31c
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowGeometryTest.h"
+
+#include "PluginObject.h"
+
+using namespace std;
+
+WindowGeometryTest::WindowGeometryTest(NPP npp, const string& identifier)
+ : WindowedPluginTest(npp, identifier)
+ , m_testHarnessWindowWasVisible(false)
+{
+}
+
+void WindowGeometryTest::startTest()
+{
+ // In WebKit1, our window's window region will be set immediately. In WebKit2, it won't be set
+ // until the UI process paints. Since the UI process will also show our window when it paints,
+ // we can detect when the paint occurs (and thus when our window region should be set) by
+ // starting with our plugin element hidden, then making it visible and waiting for a
+ // WM_WINDOWPOSCHANGED event to tell us our window has been shown.
+
+ waitUntilDone();
+
+ // If the test harness window isn't visible, we might not receive a WM_WINDOWPOSCHANGED message
+ // when our window is made visible. So we temporarily show the test harness window during this test.
+ showTestHarnessWindowIfNeeded();
+
+ // Make our window visible. (In WebKit2, this won't take effect immediately.)
+ executeScript("document.getElementsByTagName('embed')[0].style.visibility = 'visible';");
+
+ // We trigger a UI process paint after a slight delay to ensure that the UI process has
+ // received the "make the plugin window visible" message before it paints.
+ // FIXME: It would be nice to have a way to guarantee that the UI process had received that
+ // message before we triggered a paint. Hopefully that would let us get rid of this semi-
+ // arbitrary timeout.
+ ::SetTimer(window(), triggerPaintTimerID, 250, 0);
+}
+
+void WindowGeometryTest::finishTest()
+{
+ performWindowGeometryTest();
+ hideTestHarnessWindowIfNeeded();
+ notifyDone();
+}
+
+void WindowGeometryTest::showTestHarnessWindowIfNeeded()
+{
+ HWND testHarnessWindow = this->testHarnessWindow();
+ m_testHarnessWindowWasVisible = ::IsWindowVisible(testHarnessWindow);
+ if (m_testHarnessWindowWasVisible)
+ return;
+ ::ShowWindow(testHarnessWindow, SW_SHOWNA);
+}
+
+void WindowGeometryTest::hideTestHarnessWindowIfNeeded()
+{
+ if (m_testHarnessWindowWasVisible)
+ return;
+ ::ShowWindow(testHarnessWindow(), SW_HIDE);
+}
+
+LRESULT WindowGeometryTest::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
+{
+ switch (message) {
+ case WM_TIMER:
+ if (wParam != triggerPaintTimerID)
+ break;
+ handled = true;
+ ::KillTimer(window(), wParam);
+ // Tell the UI process to paint.
+ ::PostMessageW(::GetParent(window()), WM_PAINT, 0, 0);
+ break;
+ case WM_WINDOWPOSCHANGED: {
+ WINDOWPOS* windowPos = reinterpret_cast<WINDOWPOS*>(lParam);
+ if (!(windowPos->flags & SWP_SHOWWINDOW))
+ break;
+ finishTest();
+ break;
+ }
+
+ }
+
+ return 0;
+}
+
+NPError WindowGeometryTest::NPP_GetValue(NPPVariable variable, void* value)
+{
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *static_cast<NPObject**>(value) = ScriptObject::create(this);
+
+ return NPERR_NO_ERROR;
+}
+
+bool WindowGeometryTest::ScriptObject::hasMethod(NPIdentifier methodName)
+{
+ return methodName == pluginTest()->NPN_GetStringIdentifier("startTest");
+}
+
+bool WindowGeometryTest::ScriptObject::invoke(NPIdentifier identifier, const NPVariant*, uint32_t, NPVariant*)
+{
+ assert(identifier == pluginTest()->NPN_GetStringIdentifier("startTest"));
+ static_cast<WindowGeometryTest*>(pluginTest())->startTest();
+ return true;
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.h b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.h
new file mode 100644
index 000000000..4878a6941
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowGeometryTest.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 WindowGeometryTest_h
+#define WindowGeometryTest_h
+
+#include "WindowedPluginTest.h"
+
+class WindowGeometryTest : public WindowedPluginTest {
+public:
+ WindowGeometryTest(NPP, const std::string& identifier);
+
+private:
+ struct ScriptObject : Object<ScriptObject> {
+ bool hasMethod(NPIdentifier);
+ bool invoke(NPIdentifier, const NPVariant*, uint32_t, NPVariant*);
+ };
+
+ static const UINT_PTR triggerPaintTimerID = 1;
+
+ void startTest();
+ void finishTest();
+
+ void showTestHarnessWindowIfNeeded();
+ void hideTestHarnessWindowIfNeeded();
+
+ // For subclasses to implement
+ virtual void performWindowGeometryTest() = 0;
+
+ // WindowedPluginTest
+ virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled);
+
+ // PluginTest
+ virtual NPError NPP_GetValue(NPPVariable, void*);
+
+ bool m_testHarnessWindowWasVisible;
+};
+
+#endif // WindowGeometryTest_h
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp
new file mode 100644
index 000000000..2e75ca162
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "WindowedPluginTest.h"
+
+using namespace std;
+
+static const wchar_t instancePointerProperty[] = L"org.webkit.TestNetscapePlugin.WindowedPluginTest.InstancePointer";
+
+WindowedPluginTest::WindowedPluginTest(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_window(0)
+ , m_originalWndProc(0)
+{
+}
+
+HWND WindowedPluginTest::testHarnessWindow() const
+{
+ return ::GetAncestor(window(), GA_ROOT);
+}
+
+NPError WindowedPluginTest::NPP_SetWindow(NPP instance, NPWindow* window)
+{
+ HWND newWindow = reinterpret_cast<HWND>(window->window);
+ if (newWindow == m_window)
+ return NPERR_NO_ERROR;
+
+ if (m_window) {
+ ::RemovePropW(m_window, instancePointerProperty);
+ ::SetWindowLongPtr(m_window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_originalWndProc));
+ m_originalWndProc = 0;
+ }
+
+ m_window = newWindow;
+ if (!m_window)
+ return NPERR_NO_ERROR;
+
+ m_originalWndProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtrW(m_window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(staticWndProc)));
+ ::SetPropW(m_window, instancePointerProperty, this);
+
+ return NPERR_NO_ERROR;
+}
+
+LRESULT WindowedPluginTest::staticWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ WindowedPluginTest* instance = reinterpret_cast<WindowedPluginTest*>(::GetPropW(hwnd, instancePointerProperty));
+
+ bool handled = false;
+ LRESULT result = instance->wndProc(message, wParam, lParam, handled);
+ if (handled)
+ return result;
+
+ return ::CallWindowProcW(instance->m_originalWndProc, hwnd, message, wParam, lParam);
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h
new file mode 100644
index 000000000..b50746ae3
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 WindowedPluginTest_h
+#define WindowedPluginTest_h
+
+#include "PluginTest.h"
+
+class WindowedPluginTest : public PluginTest {
+protected:
+ WindowedPluginTest(NPP, const std::string& identifier);
+
+ HWND window() const { return m_window; }
+ HWND testHarnessWindow() const;
+
+ // For derived classes to override
+ virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled) = 0;
+
+ // PluginTest
+ virtual NPError NPP_SetWindow(NPP, NPWindow*);
+
+private:
+ static LRESULT CALLBACK staticWndProc(HWND, UINT message, WPARAM, LPARAM);
+
+ HWND m_window;
+ WNDPROC m_originalWndProc;
+};
+
+#endif // WindowedPluginTest_h
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/resource.h b/Tools/DumpRenderTree/TestNetscapePlugIn/win/resource.h
new file mode 100644
index 000000000..b0ce34048
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by TestNetscapePlugin.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Tools/DumpRenderTree/WorkQueue.cpp b/Tools/DumpRenderTree/WorkQueue.cpp
new file mode 100644
index 000000000..f38d81a34
--- /dev/null
+++ b/Tools/DumpRenderTree/WorkQueue.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "WorkQueue.h"
+
+#if PLATFORM(QT)
+#include "WorkQueueItemQt.h"
+#else
+#include "WorkQueueItem.h"
+#endif
+#include <wtf/Assertions.h>
+
+static const unsigned queueLength = 1024;
+
+static WorkQueueItem* theQueue[queueLength];
+static unsigned startOfQueue;
+static unsigned endOfQueue;
+
+WorkQueue* WorkQueue::shared()
+{
+ static WorkQueue* sharedInstance = new WorkQueue;
+ return sharedInstance;
+}
+
+WorkQueue::WorkQueue()
+ : m_frozen(false)
+{
+}
+
+void WorkQueue::queue(WorkQueueItem* item)
+{
+ ASSERT(endOfQueue < queueLength);
+ ASSERT(endOfQueue >= startOfQueue);
+
+ if (m_frozen) {
+ delete item;
+ return;
+ }
+
+ theQueue[endOfQueue++] = item;
+}
+
+WorkQueueItem* WorkQueue::dequeue()
+{
+ ASSERT(endOfQueue >= startOfQueue);
+
+ if (startOfQueue == endOfQueue)
+ return 0;
+
+ return theQueue[startOfQueue++];
+}
+
+unsigned WorkQueue::count()
+{
+ return endOfQueue - startOfQueue;
+}
+
+void WorkQueue::clear()
+{
+ for (unsigned i = startOfQueue; i < endOfQueue; ++i) {
+ delete theQueue[i];
+ theQueue[i] = 0;
+ }
+
+ startOfQueue = 0;
+ endOfQueue = 0;
+}
+
+bool WorkQueue::processWork()
+{
+ bool startedLoad = false;
+
+ while (!startedLoad && count()) {
+ WorkQueueItem* item = dequeue();
+ ASSERT(item);
+ startedLoad = item->invoke();
+ delete item;
+ }
+
+ // If we're done and we didn't start a load, then we're really done, so return true.
+ return !startedLoad;
+}
diff --git a/Tools/DumpRenderTree/WorkQueue.h b/Tools/DumpRenderTree/WorkQueue.h
new file mode 100644
index 000000000..649c6c1f5
--- /dev/null
+++ b/Tools/DumpRenderTree/WorkQueue.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 WorkQueue_h
+#define WorkQueue_h
+
+class WorkQueueItem;
+
+class WorkQueue {
+public:
+ static WorkQueue* shared();
+
+ void queue(WorkQueueItem*);
+ WorkQueueItem* dequeue();
+ void clear();
+ unsigned count();
+
+ void setFrozen(bool b) { m_frozen = b; }
+
+ bool processWork(); // Returns true if all work is done, false if we started a load.
+
+private:
+ WorkQueue();
+
+ bool m_frozen;
+};
+
+#endif // !defined(WorkQueue_h)
diff --git a/Tools/DumpRenderTree/WorkQueueItem.h b/Tools/DumpRenderTree/WorkQueueItem.h
new file mode 100644
index 000000000..a5823c156
--- /dev/null
+++ b/Tools/DumpRenderTree/WorkQueueItem.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 WorkQueueItem_h
+#define WorkQueueItem_h
+
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSBase.h>
+
+class WorkQueueItem {
+public:
+ virtual ~WorkQueueItem() { }
+ virtual bool invoke() const = 0; // Returns true if this started a load.
+};
+
+class LoadItem : public WorkQueueItem {
+public:
+ LoadItem(const JSStringRef url, const JSStringRef target)
+ : m_url(url)
+ , m_target(target)
+ {
+ }
+
+private:
+ virtual bool invoke() const;
+
+ JSRetainPtr<JSStringRef> m_url;
+ JSRetainPtr<JSStringRef> m_target;
+};
+
+class LoadHTMLStringItem : public WorkQueueItem {
+public:
+ LoadHTMLStringItem(const JSStringRef content, const JSStringRef baseURL)
+ : m_content(content)
+ , m_baseURL(baseURL)
+ {
+ }
+
+ LoadHTMLStringItem(const JSStringRef content, const JSStringRef baseURL, const JSStringRef unreachableURL)
+ : m_content(content)
+ , m_baseURL(baseURL)
+ , m_unreachableURL(unreachableURL)
+ {
+ }
+
+private:
+ virtual bool invoke() const;
+
+ JSRetainPtr<JSStringRef> m_content;
+ JSRetainPtr<JSStringRef> m_baseURL;
+ JSRetainPtr<JSStringRef> m_unreachableURL;
+};
+
+class ReloadItem : public WorkQueueItem {
+private:
+ virtual bool invoke() const;
+};
+
+class ScriptItem : public WorkQueueItem {
+protected:
+ ScriptItem(const JSStringRef script)
+ : m_script(script)
+ {
+ }
+
+protected:
+ virtual bool invoke() const;
+
+private:
+ JSRetainPtr<JSStringRef> m_script;
+};
+
+class LoadingScriptItem : public ScriptItem {
+public:
+ LoadingScriptItem(const JSStringRef script)
+ : ScriptItem(script)
+ {
+ }
+
+private:
+ virtual bool invoke() const { return ScriptItem::invoke(); }
+};
+
+class NonLoadingScriptItem : public ScriptItem {
+public:
+ NonLoadingScriptItem(const JSStringRef script)
+ : ScriptItem(script)
+ {
+ }
+
+private:
+ virtual bool invoke() const { ScriptItem::invoke(); return false; }
+};
+
+class BackForwardItem : public WorkQueueItem {
+protected:
+ BackForwardItem(int howFar)
+ : m_howFar(howFar)
+ {
+ }
+
+private:
+ virtual bool invoke() const;
+
+ int m_howFar;
+};
+
+class BackItem : public BackForwardItem {
+public:
+ BackItem(unsigned howFar)
+ : BackForwardItem(-howFar)
+ {
+ }
+};
+
+class ForwardItem : public BackForwardItem {
+public:
+ ForwardItem(unsigned howFar)
+ : BackForwardItem(howFar)
+ {
+ }
+};
+
+#endif // !defined(WorkQueueItem_h)
diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp
new file mode 100644
index 000000000..c10a3a7dc
--- /dev/null
+++ b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * (C) 2009 Brent Fulgham <bfulgham@webkit.org>
+ * (C) 2010 Igalia S.L
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "PixelDumpSupportCairo.h"
+
+#include "DumpRenderTree.h"
+#include "PixelDumpSupport.h"
+#include <algorithm>
+#include <ctype.h>
+#include <wtf/Assertions.h>
+#include <wtf/MD5.h>
+#include <wtf/RefPtr.h>
+#include <wtf/StringExtras.h>
+
+using namespace std;
+
+static cairo_status_t writeFunction(void* closure, const unsigned char* data, unsigned int length)
+{
+ Vector<unsigned char>* in = reinterpret_cast<Vector<unsigned char>*>(closure);
+ in->append(data, length);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void printPNG(cairo_surface_t* image, const char* checksum)
+{
+ Vector<unsigned char> pixelData;
+ // Only PNG output is supported for now.
+ cairo_surface_write_to_png_stream(image, writeFunction, &pixelData);
+
+ const size_t dataLength = pixelData.size();
+ const unsigned char* data = pixelData.data();
+
+ printPNG(data, dataLength, checksum);
+}
+
+void computeMD5HashStringForBitmapContext(BitmapContext* context, char hashString[33])
+{
+ cairo_t* bitmapContext = context->cairoContext();
+ cairo_surface_t* surface = cairo_get_target(bitmapContext);
+
+ ASSERT(cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32); // ImageDiff assumes 32 bit RGBA, we must as well.
+
+ size_t pixelsHigh = cairo_image_surface_get_height(surface);
+ size_t pixelsWide = cairo_image_surface_get_width(surface);
+ size_t bytesPerRow = cairo_image_surface_get_stride(surface);
+
+ MD5 md5Context;
+ unsigned char* bitmapData = static_cast<unsigned char*>(cairo_image_surface_get_data(surface));
+ for (unsigned row = 0; row < pixelsHigh; row++) {
+ md5Context.addBytes(bitmapData, 4 * pixelsWide);
+ bitmapData += bytesPerRow;
+ }
+ Vector<uint8_t, 16> hash;
+ md5Context.checksum(hash);
+
+ snprintf(hashString, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
+ hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]);
+}
+
+void dumpBitmap(BitmapContext* context, const char* checksum)
+{
+ cairo_surface_t* surface = cairo_get_target(context->cairoContext());
+ printPNG(surface, checksum);
+}
diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h
new file mode 100644
index 000000000..071e874d0
--- /dev/null
+++ b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * (C) 2009 Brent Fulgham <bfulgham@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PixelDumpSupportCairo_h
+#define PixelDumpSupportCairo_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+#if PLATFORM(WIN)
+#include <windows.h>
+#include <cairo-win32.h>
+#elif PLATFORM(GTK) || PLATFORM(EFL)
+#include <cairo.h>
+#endif
+
+#if PLATFORM(WIN)
+typedef HBITMAP PlatformBitmapBuffer;
+#else
+typedef void* PlatformBitmapBuffer;
+#endif
+
+class BitmapContext : public RefCounted<BitmapContext> {
+public:
+ static PassRefPtr<BitmapContext> createByAdoptingBitmapAndContext(PlatformBitmapBuffer buffer, cairo_t* context)
+ {
+ return adoptRef(new BitmapContext(buffer, context));
+ }
+
+ ~BitmapContext()
+ {
+ if (m_buffer)
+#if PLATFORM(WIN)
+ DeleteObject(m_buffer);
+#else
+ free(m_buffer);
+#endif
+ cairo_destroy(m_context);
+ }
+
+ cairo_t* cairoContext() const { return m_context; }
+
+private:
+
+ BitmapContext(PlatformBitmapBuffer buffer, cairo_t* context)
+ : m_buffer(buffer)
+ , m_context(context)
+ {
+ }
+
+ PlatformBitmapBuffer m_buffer;
+ cairo_t* m_context;
+};
+
+#endif // PixelDumpSupportCairo_h
diff --git a/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.cpp b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.cpp
new file mode 100644
index 000000000..33dc28a4c
--- /dev/null
+++ b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "WebArchiveDumpSupport.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CFNetwork/CFNetwork.h>
+#include <wtf/RetainPtr.h>
+
+extern "C" {
+
+CFURLRef CFURLResponseGetURL(CFURLResponseRef response);
+CFStringRef CFURLResponseGetMIMEType(CFURLResponseRef response);
+CFStringRef CFURLResponseGetTextEncodingName(CFURLResponseRef response);
+SInt64 CFURLResponseGetExpectedContentLength(CFURLResponseRef response);
+CFHTTPMessageRef CFURLResponseGetHTTPResponse(CFURLResponseRef response);
+
+CFTypeID CFURLResponseGetTypeID(void);
+
+}
+
+static void convertMIMEType(CFMutableStringRef mimeType)
+{
+#ifdef BUILDING_ON_LEOPARD
+ // Workaround for <rdar://problem/5539824> on Leopard
+ if (CFStringCompare(mimeType, CFSTR("text/xml"), kCFCompareAnchored | kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ CFStringReplaceAll(mimeType, CFSTR("application/xml"));
+#endif
+ // Workaround for <rdar://problem/6234318> with Dashcode 2.0
+ if (CFStringCompare(mimeType, CFSTR("application/x-javascript"), kCFCompareAnchored | kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ CFStringReplaceAll(mimeType, CFSTR("text/javascript"));
+}
+
+static void convertWebResourceDataToString(CFMutableDictionaryRef resource)
+{
+ CFMutableStringRef mimeType = (CFMutableStringRef)CFDictionaryGetValue(resource, CFSTR("WebResourceMIMEType"));
+ CFStringLowercase(mimeType, CFLocaleGetSystem());
+ convertMIMEType(mimeType);
+
+ CFArrayRef supportedMIMETypes = supportedNonImageMIMETypes();
+ if (CFStringHasPrefix(mimeType, CFSTR("text/")) || CFArrayContainsValue(supportedMIMETypes, CFRangeMake(0, CFArrayGetCount(supportedMIMETypes)), mimeType)) {
+ CFStringRef textEncodingName = static_cast<CFStringRef>(CFDictionaryGetValue(resource, CFSTR("WebResourceTextEncodingName")));
+ CFStringEncoding stringEncoding;
+ if (textEncodingName && CFStringGetLength(textEncodingName))
+ stringEncoding = CFStringConvertIANACharSetNameToEncoding(textEncodingName);
+ else
+ stringEncoding = kCFStringEncodingUTF8;
+
+ CFDataRef data = static_cast<CFDataRef>(CFDictionaryGetValue(resource, CFSTR("WebResourceData")));
+ RetainPtr<CFStringRef> dataAsString(AdoptCF, CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, data, stringEncoding));
+ if (dataAsString)
+ CFDictionarySetValue(resource, CFSTR("WebResourceData"), dataAsString.get());
+ }
+}
+
+static void normalizeHTTPResponseHeaderFields(CFMutableDictionaryRef fields)
+{
+ // Normalize headers
+ if (CFDictionaryContainsKey(fields, CFSTR("Date")))
+ CFDictionarySetValue(fields, CFSTR("Date"), CFSTR("Sun, 16 Nov 2008 17:00:00 GMT"));
+ if (CFDictionaryContainsKey(fields, CFSTR("Last-Modified")))
+ CFDictionarySetValue(fields, CFSTR("Last-Modified"), CFSTR("Sun, 16 Nov 2008 16:55:00 GMT"));
+ if (CFDictionaryContainsKey(fields, CFSTR("Etag")))
+ CFDictionarySetValue(fields, CFSTR("Etag"), CFSTR("\"301925-21-45c7d72d3e780\""));
+ if (CFDictionaryContainsKey(fields, CFSTR("Server")))
+ CFDictionarySetValue(fields, CFSTR("Server"), CFSTR("Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.7l PHP/5.2.6"));
+
+ // Remove headers
+ CFDictionaryRemoveValue(fields, CFSTR("Connection"));
+ CFDictionaryRemoveValue(fields, CFSTR("Keep-Alive"));
+}
+
+static void normalizeWebResourceURL(CFMutableStringRef webResourceURL)
+{
+ static CFIndex fileUrlLength = CFStringGetLength(CFSTR("file://"));
+ CFRange layoutTestsWebArchivePathRange = CFStringFind(webResourceURL, CFSTR("/LayoutTests/"), kCFCompareBackwards);
+ if (layoutTestsWebArchivePathRange.location == kCFNotFound)
+ return;
+ CFRange currentWorkingDirectoryRange = CFRangeMake(fileUrlLength, layoutTestsWebArchivePathRange.location - fileUrlLength);
+ CFStringReplace(webResourceURL, currentWorkingDirectoryRange, CFSTR(""));
+}
+
+static void convertWebResourceResponseToDictionary(CFMutableDictionaryRef propertyList)
+{
+ CFDataRef responseData = static_cast<CFDataRef>(CFDictionaryGetValue(propertyList, CFSTR("WebResourceResponse"))); // WebResourceResponseKey in WebResource.m
+ if (CFGetTypeID(responseData) != CFDataGetTypeID())
+ return;
+
+ RetainPtr<CFURLResponseRef> response(AdoptCF, createCFURLResponseFromResponseData(responseData));
+ if (!response)
+ return;
+
+ RetainPtr<CFMutableDictionaryRef> responseDictionary(AdoptCF, CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+
+ RetainPtr<CFMutableStringRef> urlString(AdoptCF, CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFURLGetString(CFURLResponseGetURL(response.get()))));
+ normalizeWebResourceURL(urlString.get());
+ CFDictionarySetValue(responseDictionary.get(), CFSTR("URL"), urlString.get());
+
+ RetainPtr<CFMutableStringRef> mimeTypeString(AdoptCF, CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFURLResponseGetMIMEType(response.get())));
+ convertMIMEType(mimeTypeString.get());
+ CFDictionarySetValue(responseDictionary.get(), CFSTR("MIMEType"), mimeTypeString.get());
+
+ CFStringRef textEncodingName = CFURLResponseGetTextEncodingName(response.get());
+ if (textEncodingName)
+ CFDictionarySetValue(responseDictionary.get(), CFSTR("textEncodingName"), textEncodingName);
+
+ SInt64 expectedContentLength = CFURLResponseGetExpectedContentLength(response.get());
+ RetainPtr<CFNumberRef> expectedContentLengthNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &expectedContentLength));
+ CFDictionarySetValue(responseDictionary.get(), CFSTR("expectedContentLength"), expectedContentLengthNumber.get());
+
+ if (CFHTTPMessageRef httpMessage = CFURLResponseGetHTTPResponse(response.get())) {
+ RetainPtr<CFDictionaryRef> allHeaders(AdoptCF, CFHTTPMessageCopyAllHeaderFields(httpMessage));
+ RetainPtr<CFMutableDictionaryRef> allHeaderFields(AdoptCF, CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, allHeaders.get()));
+ normalizeHTTPResponseHeaderFields(allHeaderFields.get());
+ CFDictionarySetValue(responseDictionary.get(), CFSTR("allHeaderFields"), allHeaderFields.get());
+
+ CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(httpMessage);
+ RetainPtr<CFNumberRef> statusCodeNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &statusCode));
+ CFDictionarySetValue(responseDictionary.get(), CFSTR("statusCode"), statusCodeNumber.get());
+ }
+
+ CFDictionarySetValue(propertyList, CFSTR("WebResourceResponse"), responseDictionary.get());
+}
+
+static CFComparisonResult compareResourceURLs(const void *val1, const void *val2, void *context)
+{
+ CFStringRef url1 = static_cast<CFStringRef>(CFDictionaryGetValue(static_cast<CFDictionaryRef>(val1), CFSTR("WebResourceURL")));
+ CFStringRef url2 = static_cast<CFStringRef>(CFDictionaryGetValue(static_cast<CFDictionaryRef>(val2), CFSTR("WebResourceURL")));
+
+ return CFStringCompare(url1, url2, kCFCompareAnchored);
+}
+
+CFStringRef createXMLStringFromWebArchiveData(CFDataRef webArchiveData)
+{
+ CFErrorRef error = 0;
+ CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0;
+
+#ifdef BUILDING_ON_LEOPARD
+ CFIndex bytesCount = CFDataGetLength(webArchiveData);
+ RetainPtr<CFReadStreamRef> readStream(AdoptCF, CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault, CFDataGetBytePtr(webArchiveData), bytesCount, kCFAllocatorNull));
+ CFReadStreamOpen(readStream.get());
+ RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, (CFMutableDictionaryRef)CFPropertyListCreateFromStream(kCFAllocatorDefault, readStream.get(), bytesCount, kCFPropertyListMutableContainersAndLeaves, &format, 0));
+ CFReadStreamClose(readStream.get());
+#else
+ RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, (CFMutableDictionaryRef)CFPropertyListCreateWithData(kCFAllocatorDefault, webArchiveData, kCFPropertyListMutableContainersAndLeaves, &format, &error));
+#endif
+
+ if (!propertyList) {
+ if (error)
+ return CFErrorCopyDescription(error);
+ return static_cast<CFStringRef>(CFRetain(CFSTR("An unknown error occurred converting data to property list.")));
+ }
+
+ RetainPtr<CFMutableArrayRef> resources(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
+ CFArrayAppendValue(resources.get(), propertyList.get());
+
+ while (CFArrayGetCount(resources.get())) {
+ RetainPtr<CFMutableDictionaryRef> resourcePropertyList = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(resources.get(), 0);
+ CFArrayRemoveValueAtIndex(resources.get(), 0);
+
+ CFMutableDictionaryRef mainResource = (CFMutableDictionaryRef)CFDictionaryGetValue(resourcePropertyList.get(), CFSTR("WebMainResource"));
+ normalizeWebResourceURL((CFMutableStringRef)CFDictionaryGetValue(mainResource, CFSTR("WebResourceURL")));
+ convertWebResourceDataToString(mainResource);
+
+ // Add subframeArchives to list for processing
+ CFMutableArrayRef subframeArchives = (CFMutableArrayRef)CFDictionaryGetValue(resourcePropertyList.get(), CFSTR("WebSubframeArchives")); // WebSubframeArchivesKey in WebArchive.m
+ if (subframeArchives)
+ CFArrayAppendArray(resources.get(), subframeArchives, CFRangeMake(0, CFArrayGetCount(subframeArchives)));
+
+ CFMutableArrayRef subresources = (CFMutableArrayRef)CFDictionaryGetValue(resourcePropertyList.get(), CFSTR("WebSubresources")); // WebSubresourcesKey in WebArchive.m
+ if (!subresources)
+ continue;
+
+ CFIndex subresourcesCount = CFArrayGetCount(subresources);
+ for (CFIndex i = 0; i < subresourcesCount; ++i) {
+ CFMutableDictionaryRef subresourcePropertyList = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(subresources, i);
+ normalizeWebResourceURL((CFMutableStringRef)CFDictionaryGetValue(subresourcePropertyList, CFSTR("WebResourceURL")));
+ convertWebResourceResponseToDictionary(subresourcePropertyList);
+ convertWebResourceDataToString(subresourcePropertyList);
+ }
+
+ // Sort the subresources so they're always in a predictable order for the dump
+ CFArraySortValues(subresources, CFRangeMake(0, CFArrayGetCount(subresources)), compareResourceURLs, 0);
+ }
+
+ error = 0;
+
+#ifdef BUILDING_ON_LEOPARD
+ RetainPtr<CFDataRef> xmlData(AdoptCF, CFPropertyListCreateXMLData(kCFAllocatorDefault, propertyList.get()));
+#else
+ RetainPtr<CFDataRef> xmlData(AdoptCF, CFPropertyListCreateData(kCFAllocatorDefault, propertyList.get(), kCFPropertyListXMLFormat_v1_0, 0, &error));
+#endif
+
+ if (!xmlData) {
+ if (error)
+ return CFErrorCopyDescription(error);
+ return static_cast<CFStringRef>(CFRetain(CFSTR("An unknown error occurred converting property list to data.")));
+ }
+
+ RetainPtr<CFStringRef> xmlString(AdoptCF, CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, xmlData.get(), kCFStringEncodingUTF8));
+ RetainPtr<CFMutableStringRef> string(AdoptCF, CFStringCreateMutableCopy(kCFAllocatorDefault, 0, xmlString.get()));
+
+ // Replace "Apple Computer" with "Apple" in the DTD declaration.
+ CFStringFindAndReplace(string.get(), CFSTR("-//Apple Computer//"), CFSTR("-//Apple//"), CFRangeMake(0, CFStringGetLength(string.get())), 0);
+
+ return string.leakRef();
+}
diff --git a/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h
new file mode 100644
index 000000000..00c58184e
--- /dev/null
+++ b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 WebArchiveDumpSupport_h
+#define WebArchiveDumpSupport_h
+
+#include <CoreFoundation/CoreFoundation.h>
+
+typedef struct _CFURLResponse* CFURLResponseRef;
+
+CFStringRef createXMLStringFromWebArchiveData(CFDataRef webArchiveData);
+
+// MARK: -
+// MARK: Platform-specific methods
+
+CFURLResponseRef createCFURLResponseFromResponseData(CFDataRef responseData);
+CFArrayRef supportedNonImageMIMETypes();
+
+#endif /* WebArchiveDumpSupport_h */
diff --git a/Tools/DumpRenderTree/cg/ImageDiffCG.cpp b/Tools/DumpRenderTree/cg/ImageDiffCG.cpp
new file mode 100644
index 000000000..07e51130c
--- /dev/null
+++ b/Tools/DumpRenderTree/cg/ImageDiffCG.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Ben La Monica <ben.lamonica@gmail.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#define min min
+
+// FIXME: We need to be able to include these defines from a config.h somewhere.
+#define JS_EXPORT_PRIVATE
+#define WTF_EXPORT_PRIVATE
+
+#include <stdio.h>
+#include <wtf/Platform.h>
+#include <wtf/RetainPtr.h>
+
+#if PLATFORM(WIN)
+#include <winsock2.h>
+#include <windows.h>
+#include <fcntl.h>
+#include <io.h>
+#include <wtf/MathExtras.h>
+#endif
+
+#include <CoreGraphics/CGBitmapContext.h>
+#include <CoreGraphics/CGImage.h>
+#include <ImageIO/CGImageDestination.h>
+
+#if PLATFORM(MAC)
+#include <LaunchServices/UTCoreTypes.h>
+#endif
+
+#ifndef CGFLOAT_DEFINED
+#ifdef __LP64__
+typedef double CGFloat;
+#else
+typedef float CGFloat;
+#endif
+#define CGFLOAT_DEFINED 1
+#endif
+
+using namespace std;
+
+#if PLATFORM(WIN)
+static inline float strtof(const char *nptr, char **endptr)
+{
+ return strtod(nptr, endptr);
+}
+static const CFStringRef kUTTypePNG = CFSTR("public.png");
+#endif
+
+static RetainPtr<CGImageRef> createImageFromStdin(int bytesRemaining)
+{
+ unsigned char buffer[2048];
+ RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, bytesRemaining));
+
+ while (bytesRemaining > 0) {
+ size_t bytesToRead = min(bytesRemaining, 2048);
+ size_t bytesRead = fread(buffer, 1, bytesToRead, stdin);
+ CFDataAppendBytes(data.get(), buffer, static_cast<CFIndex>(bytesRead));
+ bytesRemaining -= static_cast<int>(bytesRead);
+ }
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get()));
+ return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateWithPNGDataProvider(dataProvider.get(), 0, false, kCGRenderingIntentDefault));
+}
+
+static void releaseMallocBuffer(void* info, const void* data, size_t size)
+{
+ free((void*)data);
+}
+
+static RetainPtr<CGImageRef> createDifferenceImage(CGImageRef baseImage, CGImageRef testImage, float& difference)
+{
+ size_t width = CGImageGetWidth(baseImage);
+ size_t height = CGImageGetHeight(baseImage);
+ size_t rowBytes = width * 4;
+
+ // Draw base image in bitmap context
+ void* baseBuffer = calloc(height, rowBytes);
+ RetainPtr<CGContextRef> baseContext(AdoptCF, CGBitmapContextCreate(baseBuffer, width, height, 8, rowBytes, CGImageGetColorSpace(baseImage), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+ CGContextDrawImage(baseContext.get(), CGRectMake(0, 0, width, height), baseImage);
+
+ // Draw test image in bitmap context
+ void* buffer = calloc(height, rowBytes);
+ RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(buffer, width, height, 8, rowBytes, CGImageGetColorSpace(testImage), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+ CGContextDrawImage(context.get(), CGRectMake(0, 0, width, height), testImage);
+
+ // Compare the content of the 2 bitmaps
+ void* diffBuffer = malloc(width * height);
+ float count = 0.0f;
+ float sum = 0.0f;
+ float maxDistance = 0.0f;
+ unsigned char* basePixel = (unsigned char*)baseBuffer;
+ unsigned char* pixel = (unsigned char*)buffer;
+ unsigned char* diff = (unsigned char*)diffBuffer;
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ float red = (pixel[0] - basePixel[0]) / max<float>(255 - basePixel[0], basePixel[0]);
+ float green = (pixel[1] - basePixel[1]) / max<float>(255 - basePixel[1], basePixel[1]);
+ float blue = (pixel[2] - basePixel[2]) / max<float>(255 - basePixel[2], basePixel[2]);
+ float alpha = (pixel[3] - basePixel[3]) / max<float>(255 - basePixel[3], basePixel[3]);
+ float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f;
+
+ *diff++ = (unsigned char)(distance * 255.0f);
+
+ if (distance >= 1.0f / 255.0f) {
+ count += 1.0f;
+ sum += distance;
+ if (distance > maxDistance)
+ maxDistance = distance;
+ }
+
+ basePixel += 4;
+ pixel += 4;
+ }
+ }
+
+ // Compute the difference as a percentage combining both the number of different pixels and their difference amount i.e. the average distance over the entire image
+ if (count > 0.0f)
+ difference = 100.0f * sum / (height * width);
+ else
+ difference = 0.0f;
+
+ RetainPtr<CGImageRef> diffImage;
+ // Generate a normalized diff image if there is any difference
+ if (difference > 0.0f) {
+ if (maxDistance < 1.0f) {
+ diff = (unsigned char*)diffBuffer;
+ for(size_t p = 0; p < height * width; ++p)
+ diff[p] = diff[p] / maxDistance;
+ }
+
+ static CGColorSpaceRef diffColorspace = CGColorSpaceCreateDeviceGray();
+ RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithData(0, diffBuffer, width * height, releaseMallocBuffer));
+ diffImage.adoptCF(CGImageCreate(width, height, 8, 8, width, diffColorspace, 0, provider.get(), 0, false, kCGRenderingIntentDefault));
+ }
+ else
+ free(diffBuffer);
+
+ // Destroy drawing buffers
+ if (buffer)
+ free(buffer);
+ if (baseBuffer)
+ free(baseBuffer);
+
+ return diffImage;
+}
+
+static inline bool imageHasAlpha(CGImageRef image)
+{
+ CGImageAlphaInfo info = CGImageGetAlphaInfo(image);
+
+ return (info >= kCGImageAlphaPremultipliedLast) && (info <= kCGImageAlphaFirst);
+}
+
+int main(int argc, const char* argv[])
+{
+#if PLATFORM(WIN)
+ _setmode(0, _O_BINARY);
+ _setmode(1, _O_BINARY);
+#endif
+
+ float tolerance = 0.0f;
+
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) {
+ if (i >= argc - 1)
+ exit(1);
+ tolerance = strtof(argv[i + 1], 0);
+ ++i;
+ continue;
+ }
+ }
+
+ char buffer[2048];
+ RetainPtr<CGImageRef> actualImage;
+ RetainPtr<CGImageRef> baselineImage;
+
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ // remove the CR
+ char* newLineCharacter = strchr(buffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (!strncmp("Content-Length: ", buffer, 16)) {
+ strtok(buffer, " ");
+ int imageSize = strtol(strtok(0, " "), 0, 10);
+
+ if (imageSize > 0 && !actualImage)
+ actualImage = createImageFromStdin(imageSize);
+ else if (imageSize > 0 && !baselineImage)
+ baselineImage = createImageFromStdin(imageSize);
+ else
+ fputs("error, image size must be specified.\n", stderr);
+ }
+
+ if (actualImage && baselineImage) {
+ RetainPtr<CGImageRef> diffImage;
+ float difference = 100.0f;
+
+ if ((CGImageGetWidth(actualImage.get()) == CGImageGetWidth(baselineImage.get())) && (CGImageGetHeight(actualImage.get()) == CGImageGetHeight(baselineImage.get())) && (imageHasAlpha(actualImage.get()) == imageHasAlpha(baselineImage.get()))) {
+ diffImage = createDifferenceImage(actualImage.get(), baselineImage.get(), difference); // difference is passed by reference
+ if (difference <= tolerance)
+ difference = 0.0f;
+ else {
+ difference = roundf(difference * 100.0f) / 100.0f;
+ difference = max(difference, 0.01f); // round to 2 decimal places
+ }
+ } else
+ fputs("error, test and reference image have different properties.\n", stderr);
+
+ if (difference > 0.0f) {
+ if (diffImage) {
+ RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0));
+ RetainPtr<CGImageDestinationRef> imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0));
+ CGImageDestinationAddImage(imageDest.get(), diffImage.get(), 0);
+ CGImageDestinationFinalize(imageDest.get());
+ printf("Content-Length: %lu\n", CFDataGetLength(imageData.get()));
+ fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout);
+ }
+
+ fprintf(stdout, "diff: %01.2f%% failed\n", difference);
+ } else
+ fprintf(stdout, "diff: %01.2f%% passed\n", difference);
+
+ actualImage = 0;
+ baselineImage = 0;
+ }
+
+ fflush(stdout);
+ }
+
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp
new file mode 100644
index 000000000..bf59b03ec
--- /dev/null
+++ b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "PixelDumpSupportCG.h"
+
+#include "DumpRenderTree.h"
+#include "PixelDumpSupport.h"
+#include <ImageIO/CGImageDestination.h>
+#include <algorithm>
+#include <ctype.h>
+#include <wtf/Assertions.h>
+#include <wtf/RefPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/StringExtras.h>
+
+#if PLATFORM(WIN)
+#include "MD5.h"
+#elif PLATFORM(MAC)
+#include <LaunchServices/UTCoreTypes.h>
+#define COMMON_DIGEST_FOR_OPENSSL
+#include <CommonCrypto/CommonDigest.h>
+#endif
+
+using namespace std;
+
+#if PLATFORM(WIN)
+static const CFStringRef kUTTypePNG = CFSTR("public.png");
+#endif
+
+static void printPNG(CGImageRef image, const char* checksum)
+{
+ RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0));
+ RetainPtr<CGImageDestinationRef> imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0));
+ CGImageDestinationAddImage(imageDest.get(), image, 0);
+ CGImageDestinationFinalize(imageDest.get());
+
+ const UInt8* data = CFDataGetBytePtr(imageData.get());
+ CFIndex dataLength = CFDataGetLength(imageData.get());
+
+ printPNG(static_cast<const unsigned char*>(data), static_cast<size_t>(dataLength), checksum);
+}
+
+void computeMD5HashStringForBitmapContext(BitmapContext* context, char hashString[33])
+{
+ CGContextRef bitmapContext = context->cgContext();
+
+ ASSERT(CGBitmapContextGetBitsPerPixel(bitmapContext) == 32); // ImageDiff assumes 32 bit RGBA, we must as well.
+ size_t pixelsHigh = CGBitmapContextGetHeight(bitmapContext);
+ size_t pixelsWide = CGBitmapContextGetWidth(bitmapContext);
+ size_t bytesPerRow = CGBitmapContextGetBytesPerRow(bitmapContext);
+
+ // We need to swap the bytes to ensure consistent hashes independently of endianness
+ MD5_CTX md5Context;
+ MD5_Init(&md5Context);
+ unsigned char* bitmapData = static_cast<unsigned char*>(CGBitmapContextGetData(bitmapContext));
+#if PLATFORM(MAC)
+ if ((CGBitmapContextGetBitmapInfo(bitmapContext) & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Big) {
+ for (unsigned row = 0; row < pixelsHigh; row++) {
+ uint32_t buffer[pixelsWide];
+ for (unsigned column = 0; column < pixelsWide; column++)
+ buffer[column] = OSReadLittleInt32(bitmapData, 4 * column);
+ MD5_Update(&md5Context, buffer, 4 * pixelsWide);
+ bitmapData += bytesPerRow;
+ }
+ } else
+#endif
+ {
+ for (unsigned row = 0; row < pixelsHigh; row++) {
+ MD5_Update(&md5Context, bitmapData, 4 * pixelsWide);
+ bitmapData += bytesPerRow;
+ }
+ }
+ unsigned char hash[16];
+ MD5_Final(hash, &md5Context);
+
+ hashString[0] = '\0';
+ for (int i = 0; i < 16; i++)
+ snprintf(hashString, 33, "%s%02x", hashString, hash[i]);
+}
+
+void dumpBitmap(BitmapContext* context, const char* checksum)
+{
+ RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context->cgContext()));
+ printPNG(image.get(), checksum);
+}
diff --git a/Tools/DumpRenderTree/cg/PixelDumpSupportCG.h b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.h
new file mode 100644
index 000000000..f0c974631
--- /dev/null
+++ b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PixelDumpSupportCG_h
+#define PixelDumpSupportCG_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RetainPtr.h>
+
+#if PLATFORM(WIN)
+#include <windows.h>
+#endif
+
+typedef struct CGContext* CGContextRef;
+
+#if PLATFORM(MAC)
+typedef void* PlatformBitmapBuffer;
+#elif PLATFORM(WIN)
+typedef HBITMAP PlatformBitmapBuffer;
+#endif
+
+class BitmapContext : public RefCounted<BitmapContext> {
+public:
+ static PassRefPtr<BitmapContext> createByAdoptingBitmapAndContext(PlatformBitmapBuffer buffer, CGContextRef context)
+ {
+ return adoptRef(new BitmapContext(buffer, context));
+ }
+
+ ~BitmapContext()
+ {
+ if (m_buffer)
+#if PLATFORM(MAC)
+ free(m_buffer);
+#elif PLATFORM(WIN)
+ DeleteObject(m_buffer);
+#endif
+ }
+
+ CGContextRef cgContext() const { return m_context.get(); }
+
+private:
+
+ BitmapContext(PlatformBitmapBuffer buffer, CGContextRef context)
+ : m_buffer(buffer)
+ , m_context(AdoptCF, context)
+ {
+ }
+
+ PlatformBitmapBuffer m_buffer;
+ RetainPtr<CGContextRef> m_context;
+
+};
+
+PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect);
+
+#endif // PixelDumpSupportCG_h
diff --git a/Tools/DumpRenderTree/chromium/AccessibilityController.cpp b/Tools/DumpRenderTree/chromium/AccessibilityController.cpp
new file mode 100644
index 000000000..860a747aa
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityController.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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 "AccessibilityController.h"
+
+#include "TestShell.h"
+#include "WebAccessibilityObject.h"
+#include "WebFrame.h"
+#include "platform/WebString.h"
+#include "WebView.h"
+
+using namespace WebKit;
+
+AccessibilityController::AccessibilityController(TestShell* shell)
+ : m_logAccessibilityEvents(false)
+ , m_shell(shell)
+{
+
+ bindMethod("logAccessibilityEvents", &AccessibilityController::logAccessibilityEventsCallback);
+ bindMethod("addNotificationListener", &AccessibilityController::addNotificationListenerCallback);
+ bindMethod("removeNotificationListener", &AccessibilityController::removeNotificationListenerCallback);
+
+ bindProperty("focusedElement", &AccessibilityController::focusedElementGetterCallback);
+ bindProperty("rootElement", &AccessibilityController::rootElementGetterCallback);
+
+ bindFallbackMethod(&AccessibilityController::fallbackCallback);
+}
+
+void AccessibilityController::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ WebAccessibilityObject::enableAccessibility();
+ CppBoundClass::bindToJavascript(frame, classname);
+}
+
+void AccessibilityController::reset()
+{
+ m_rootElement = WebAccessibilityObject();
+ m_focusedElement = WebAccessibilityObject();
+ m_elements.clear();
+
+ m_logAccessibilityEvents = false;
+}
+
+void AccessibilityController::setFocusedElement(const WebAccessibilityObject& focusedElement)
+{
+ m_focusedElement = focusedElement;
+}
+
+AccessibilityUIElement* AccessibilityController::getFocusedElement()
+{
+ if (m_focusedElement.isNull())
+ m_focusedElement = m_shell->webView()->accessibilityObject();
+ return m_elements.getOrCreate(m_focusedElement);
+}
+
+AccessibilityUIElement* AccessibilityController::getRootElement()
+{
+ if (m_rootElement.isNull())
+ m_rootElement = m_shell->webView()->accessibilityObject();
+ return m_elements.createRoot(m_rootElement);
+}
+
+bool AccessibilityController::shouldLogAccessibilityEvents()
+{
+ return m_logAccessibilityEvents;
+}
+
+void AccessibilityController::notificationReceived(const WebKit::WebAccessibilityObject& target, const char* notificationName)
+{
+ // Call notification listeners on the element.
+ AccessibilityUIElement* element = m_elements.getOrCreate(target);
+ element->notificationReceived(notificationName);
+
+ // Call global notification listeners.
+ size_t callbackCount = m_notificationCallbacks.size();
+ for (size_t i = 0; i < callbackCount; i++) {
+ CppVariant arguments[2];
+ arguments[0].set(*element->getAsCppVariant());
+ arguments[1].set(notificationName);
+ CppVariant invokeResult;
+ m_notificationCallbacks[i].invokeDefault(arguments, 2, invokeResult);
+ }
+}
+
+void AccessibilityController::logAccessibilityEventsCallback(const CppArgumentList&, CppVariant* result)
+{
+ m_logAccessibilityEvents = true;
+ result->setNull();
+}
+
+void AccessibilityController::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 || !arguments[0].isObject()) {
+ result->setNull();
+ return;
+ }
+
+ m_notificationCallbacks.push_back(arguments[0]);
+ result->setNull();
+}
+
+void AccessibilityController::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void AccessibilityController::focusedElementGetterCallback(CppVariant* result)
+{
+ result->set(*(getFocusedElement()->getAsCppVariant()));
+}
+
+void AccessibilityController::rootElementGetterCallback(CppVariant* result)
+{
+ result->set(*(getRootElement()->getAsCppVariant()));
+}
+
+void AccessibilityController::fallbackCallback(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on "
+ "AccessibilityController\n");
+ result->setNull();
+}
diff --git a/Tools/DumpRenderTree/chromium/AccessibilityController.h b/Tools/DumpRenderTree/chromium/AccessibilityController.h
new file mode 100644
index 000000000..954edb9ca
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityController.h
@@ -0,0 +1,83 @@
+/*
+ * 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 AccessibilityController_h
+#define AccessibilityController_h
+
+#include "AccessibilityUIElement.h"
+#include "CppBoundClass.h"
+
+namespace WebKit {
+class WebAccessibilityObject;
+class WebFrame;
+}
+
+class TestShell;
+
+class AccessibilityController : public CppBoundClass {
+public:
+ explicit AccessibilityController(TestShell*);
+
+ // Shadow to include accessibility initialization.
+ void bindToJavascript(WebKit::WebFrame*, const WebKit::WebString& classname);
+ void reset();
+
+ void setFocusedElement(const WebKit::WebAccessibilityObject&);
+ AccessibilityUIElement* getFocusedElement();
+ AccessibilityUIElement* getRootElement();
+
+ bool shouldLogAccessibilityEvents();
+
+ void notificationReceived(const WebKit::WebAccessibilityObject& target, const char* notificationName);
+
+private:
+ // If true, will log all accessibility notifications.
+ bool m_logAccessibilityEvents;
+
+ // Bound methods and properties
+ void logAccessibilityEventsCallback(const CppArgumentList&, CppVariant*);
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+ void addNotificationListenerCallback(const CppArgumentList&, CppVariant*);
+ void removeNotificationListenerCallback(const CppArgumentList&, CppVariant*);
+
+ void focusedElementGetterCallback(CppVariant*);
+ void rootElementGetterCallback(CppVariant*);
+
+ WebKit::WebAccessibilityObject m_focusedElement;
+ WebKit::WebAccessibilityObject m_rootElement;
+
+ AccessibilityUIElementList m_elements;
+
+ std::vector<CppVariant> m_notificationCallbacks;
+
+ TestShell* m_shell;
+};
+
+#endif // AccessibilityController_h
diff --git a/Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp
new file mode 100644
index 000000000..3ca1ee72a
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp
@@ -0,0 +1,817 @@
+/*
+ * 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 "AccessibilityUIElement.h"
+
+#include "WebAccessibilityObject.h"
+#include "platform/WebCString.h"
+#include "platform/WebRect.h"
+#include "platform/WebString.h"
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+using namespace std;
+
+// Map role value to string, matching Safari/Mac platform implementation to
+// avoid rebaselining layout tests.
+static string roleToString(WebAccessibilityRole role)
+{
+ string result = "AXRole: AX";
+ switch (role) {
+ case WebAccessibilityRoleButton:
+ return result.append("Button");
+ case WebAccessibilityRoleRadioButton:
+ return result.append("RadioButton");
+ case WebAccessibilityRoleCheckBox:
+ return result.append("CheckBox");
+ case WebAccessibilityRoleSlider:
+ return result.append("Slider");
+ case WebAccessibilityRoleTabGroup:
+ return result.append("TabGroup");
+ case WebAccessibilityRoleTextField:
+ return result.append("TextField");
+ case WebAccessibilityRoleStaticText:
+ return result.append("StaticText");
+ case WebAccessibilityRoleTextArea:
+ return result.append("TextArea");
+ case WebAccessibilityRoleScrollArea:
+ return result.append("ScrollArea");
+ case WebAccessibilityRolePopUpButton:
+ return result.append("PopUpButton");
+ case WebAccessibilityRoleMenuButton:
+ return result.append("MenuButton");
+ case WebAccessibilityRoleTable:
+ return result.append("Table");
+ case WebAccessibilityRoleApplication:
+ return result.append("Application");
+ case WebAccessibilityRoleGroup:
+ return result.append("Group");
+ case WebAccessibilityRoleRadioGroup:
+ return result.append("RadioGroup");
+ case WebAccessibilityRoleList:
+ return result.append("List");
+ case WebAccessibilityRoleScrollBar:
+ return result.append("ScrollBar");
+ case WebAccessibilityRoleValueIndicator:
+ return result.append("ValueIndicator");
+ case WebAccessibilityRoleImage:
+ return result.append("Image");
+ case WebAccessibilityRoleMenuBar:
+ return result.append("MenuBar");
+ case WebAccessibilityRoleMenu:
+ return result.append("Menu");
+ case WebAccessibilityRoleMenuItem:
+ return result.append("MenuItem");
+ case WebAccessibilityRoleColumn:
+ return result.append("Column");
+ case WebAccessibilityRoleRow:
+ return result.append("Row");
+ case WebAccessibilityRoleToolbar:
+ return result.append("Toolbar");
+ case WebAccessibilityRoleBusyIndicator:
+ return result.append("BusyIndicator");
+ case WebAccessibilityRoleProgressIndicator:
+ return result.append("ProgressIndicator");
+ case WebAccessibilityRoleWindow:
+ return result.append("Window");
+ case WebAccessibilityRoleDrawer:
+ return result.append("Drawer");
+ case WebAccessibilityRoleSystemWide:
+ return result.append("SystemWide");
+ case WebAccessibilityRoleOutline:
+ return result.append("Outline");
+ case WebAccessibilityRoleIncrementor:
+ return result.append("Incrementor");
+ case WebAccessibilityRoleBrowser:
+ return result.append("Browser");
+ case WebAccessibilityRoleComboBox:
+ return result.append("ComboBox");
+ case WebAccessibilityRoleSplitGroup:
+ return result.append("SplitGroup");
+ case WebAccessibilityRoleSplitter:
+ return result.append("Splitter");
+ case WebAccessibilityRoleColorWell:
+ return result.append("ColorWell");
+ case WebAccessibilityRoleGrowArea:
+ return result.append("GrowArea");
+ case WebAccessibilityRoleSheet:
+ return result.append("Sheet");
+ case WebAccessibilityRoleHelpTag:
+ return result.append("HelpTag");
+ case WebAccessibilityRoleMatte:
+ return result.append("Matte");
+ case WebAccessibilityRoleRuler:
+ return result.append("Ruler");
+ case WebAccessibilityRoleRulerMarker:
+ return result.append("RulerMarker");
+ case WebAccessibilityRoleLink:
+ return result.append("Link");
+ case WebAccessibilityRoleDisclosureTriangle:
+ return result.append("DisclosureTriangle");
+ case WebAccessibilityRoleGrid:
+ return result.append("Grid");
+ case WebAccessibilityRoleCell:
+ return result.append("Cell");
+ case WebAccessibilityRoleColumnHeader:
+ return result.append("ColumnHeader");
+ case WebAccessibilityRoleRowHeader:
+ return result.append("RowHeader");
+ case WebAccessibilityRoleWebCoreLink:
+ // Maps to Link role.
+ return result.append("Link");
+ case WebAccessibilityRoleImageMapLink:
+ return result.append("ImageMapLink");
+ case WebAccessibilityRoleImageMap:
+ return result.append("ImageMap");
+ case WebAccessibilityRoleListMarker:
+ return result.append("ListMarker");
+ case WebAccessibilityRoleWebArea:
+ return result.append("WebArea");
+ case WebAccessibilityRoleHeading:
+ return result.append("Heading");
+ case WebAccessibilityRoleListBox:
+ return result.append("ListBox");
+ case WebAccessibilityRoleListBoxOption:
+ return result.append("ListBoxOption");
+ case WebAccessibilityRoleTableHeaderContainer:
+ return result.append("TableHeaderContainer");
+ case WebAccessibilityRoleDefinitionListTerm:
+ return result.append("DefinitionListTerm");
+ case WebAccessibilityRoleDefinitionListDefinition:
+ return result.append("DefinitionListDefinition");
+ case WebAccessibilityRoleAnnotation:
+ return result.append("Annotation");
+ case WebAccessibilityRoleSliderThumb:
+ return result.append("SliderThumb");
+ case WebAccessibilityRoleLandmarkApplication:
+ return result.append("LandmarkApplication");
+ case WebAccessibilityRoleLandmarkBanner:
+ return result.append("LandmarkBanner");
+ case WebAccessibilityRoleLandmarkComplementary:
+ return result.append("LandmarkComplementary");
+ case WebAccessibilityRoleLandmarkContentInfo:
+ return result.append("LandmarkContentInfo");
+ case WebAccessibilityRoleLandmarkMain:
+ return result.append("LandmarkMain");
+ case WebAccessibilityRoleLandmarkNavigation:
+ return result.append("LandmarkNavigation");
+ case WebAccessibilityRoleLandmarkSearch:
+ return result.append("LandmarkSearch");
+ case WebAccessibilityRoleApplicationLog:
+ return result.append("ApplicationLog");
+ case WebAccessibilityRoleApplicationMarquee:
+ return result.append("ApplicationMarquee");
+ case WebAccessibilityRoleApplicationStatus:
+ return result.append("ApplicationStatus");
+ case WebAccessibilityRoleApplicationTimer:
+ return result.append("ApplicationTimer");
+ case WebAccessibilityRoleDocument:
+ return result.append("Document");
+ case WebAccessibilityRoleDocumentArticle:
+ return result.append("DocumentArticle");
+ case WebAccessibilityRoleDocumentNote:
+ return result.append("DocumentNote");
+ case WebAccessibilityRoleDocumentRegion:
+ return result.append("DocumentRegion");
+ case WebAccessibilityRoleUserInterfaceTooltip:
+ return result.append("UserInterfaceTooltip");
+ default:
+ // Also matches WebAccessibilityRoleUnknown.
+ return result.append("Unknown");
+ }
+}
+
+string getDescription(const WebAccessibilityObject& object)
+{
+ string description = object.accessibilityDescription().utf8();
+ return description.insert(0, "AXDescription: ");
+}
+
+string getHelpText(const WebAccessibilityObject& object)
+{
+ string helpText = object.helpText().utf8();
+ return helpText.insert(0, "AXHelp: ");
+}
+
+string getStringValue(const WebAccessibilityObject& object)
+{
+ string value = object.stringValue().utf8();
+ return value.insert(0, "AXValue: ");
+}
+
+string getRole(const WebAccessibilityObject& object)
+{
+ return roleToString(object.roleValue());
+}
+
+string getTitle(const WebAccessibilityObject& object)
+{
+ string title = object.title().utf8();
+ return title.insert(0, "AXTitle: ");
+}
+
+string getOrientation(const WebAccessibilityObject& object)
+{
+ if (object.isVertical())
+ return "AXOrientation: AXVerticalOrientation";
+
+ return "AXOrientation: AXHorizontalOrientation";
+}
+
+string getAttributes(const WebAccessibilityObject& object)
+{
+ // FIXME: Concatenate all attributes of the AccessibilityObject.
+ string attributes(getTitle(object));
+ attributes.append("\n");
+ attributes.append(getRole(object));
+ attributes.append("\n");
+ attributes.append(getDescription(object));
+ return attributes;
+}
+
+
+// Collects attributes into a string, delimited by dashes. Used by all methods
+// that output lists of attributes: attributesOfLinkedUIElementsCallback,
+// AttributesOfChildrenCallback, etc.
+class AttributesCollector {
+public:
+ void collectAttributes(const WebAccessibilityObject& object)
+ {
+ m_attributes.append("\n------------\n");
+ m_attributes.append(getAttributes(object));
+ }
+
+ string attributes() const { return m_attributes; }
+
+private:
+ string m_attributes;
+};
+
+AccessibilityUIElement::AccessibilityUIElement(const WebAccessibilityObject& object, Factory* factory)
+ : m_accessibilityObject(object)
+ , m_factory(factory)
+{
+
+ ASSERT(factory);
+
+ //
+ // Properties
+ //
+
+ bindProperty("role", &AccessibilityUIElement::roleGetterCallback);
+ bindProperty("title", &AccessibilityUIElement::titleGetterCallback);
+ bindProperty("description", &AccessibilityUIElement::descriptionGetterCallback);
+ bindProperty("helpText", &AccessibilityUIElement::helpTextGetterCallback);
+ bindProperty("stringValue", &AccessibilityUIElement::stringValueGetterCallback);
+ bindProperty("x", &AccessibilityUIElement::xGetterCallback);
+ bindProperty("y", &AccessibilityUIElement::yGetterCallback);
+ bindProperty("width", &AccessibilityUIElement::widthGetterCallback);
+ bindProperty("height", &AccessibilityUIElement::heightGetterCallback);
+ bindProperty("intValue", &AccessibilityUIElement::intValueGetterCallback);
+ bindProperty("minValue", &AccessibilityUIElement::minValueGetterCallback);
+ bindProperty("maxValue", &AccessibilityUIElement::maxValueGetterCallback);
+ bindProperty("childrenCount", &AccessibilityUIElement::childrenCountGetterCallback);
+ bindProperty("insertionPointLineNumber", &AccessibilityUIElement::insertionPointLineNumberGetterCallback);
+ bindProperty("selectedTextRange", &AccessibilityUIElement::selectedTextRangeGetterCallback);
+ bindProperty("isEnabled", &AccessibilityUIElement::isEnabledGetterCallback);
+ bindProperty("isRequired", &AccessibilityUIElement::isRequiredGetterCallback);
+ bindProperty("isFocused", &AccessibilityUIElement::isFocusedGetterCallback);
+ bindProperty("isFocusable", &AccessibilityUIElement::isFocusableGetterCallback);
+ bindProperty("isSelected", &AccessibilityUIElement::isSelectedGetterCallback);
+ bindProperty("isSelectable", &AccessibilityUIElement::isSelectableGetterCallback);
+ bindProperty("isMultiSelectable", &AccessibilityUIElement::isMultiSelectableGetterCallback);
+ bindProperty("isSelectedOptionActive", &AccessibilityUIElement::isSelectedOptionActiveGetterCallback);
+ bindProperty("isExpanded", &AccessibilityUIElement::isExpandedGetterCallback);
+ bindProperty("isChecked", &AccessibilityUIElement::isCheckedGetterCallback);
+ bindProperty("isVisible", &AccessibilityUIElement::isVisibleGetterCallback);
+ bindProperty("isOffScreen", &AccessibilityUIElement::isOffScreenGetterCallback);
+ bindProperty("isCollapsed", &AccessibilityUIElement::isCollapsedGetterCallback);
+ bindProperty("hasPopup", &AccessibilityUIElement::hasPopupGetterCallback);
+ bindProperty("isValid", &AccessibilityUIElement::isValidGetterCallback);
+ bindProperty("orientation", &AccessibilityUIElement::orientationGetterCallback);
+
+ //
+ // Methods
+ //
+
+ bindMethod("allAttributes", &AccessibilityUIElement::allAttributesCallback);
+ bindMethod("attributesOfLinkedUIElements", &AccessibilityUIElement::attributesOfLinkedUIElementsCallback);
+ bindMethod("attributesOfDocumentLinks", &AccessibilityUIElement::attributesOfDocumentLinksCallback);
+ bindMethod("attributesOfChildren", &AccessibilityUIElement::attributesOfChildrenCallback);
+ bindMethod("lineForIndex", &AccessibilityUIElement::lineForIndexCallback);
+ bindMethod("boundsForRange", &AccessibilityUIElement::boundsForRangeCallback);
+ bindMethod("stringForRange", &AccessibilityUIElement::stringForRangeCallback);
+ bindMethod("childAtIndex", &AccessibilityUIElement::childAtIndexCallback);
+ bindMethod("elementAtPoint", &AccessibilityUIElement::elementAtPointCallback);
+ bindMethod("attributesOfColumnHeaders", &AccessibilityUIElement::attributesOfColumnHeadersCallback);
+ bindMethod("attributesOfRowHeaders", &AccessibilityUIElement::attributesOfRowHeadersCallback);
+ bindMethod("attributesOfColumns", &AccessibilityUIElement::attributesOfColumnsCallback);
+ bindMethod("attributesOfRows", &AccessibilityUIElement::attributesOfRowsCallback);
+ bindMethod("attributesOfVisibleCells", &AccessibilityUIElement::attributesOfVisibleCellsCallback);
+ bindMethod("attributesOfHeader", &AccessibilityUIElement::attributesOfHeaderCallback);
+ bindMethod("indexInTable", &AccessibilityUIElement::indexInTableCallback);
+ bindMethod("rowIndexRange", &AccessibilityUIElement::rowIndexRangeCallback);
+ bindMethod("columnIndexRange", &AccessibilityUIElement::columnIndexRangeCallback);
+ bindMethod("cellForColumnAndRow", &AccessibilityUIElement::cellForColumnAndRowCallback);
+ bindMethod("titleUIElement", &AccessibilityUIElement::titleUIElementCallback);
+ bindMethod("setSelectedTextRange", &AccessibilityUIElement::setSelectedTextRangeCallback);
+ bindMethod("attributeValue", &AccessibilityUIElement::attributeValueCallback);
+ bindMethod("isAttributeSettable", &AccessibilityUIElement::isAttributeSettableCallback);
+ bindMethod("isActionSupported", &AccessibilityUIElement::isActionSupportedCallback);
+ bindMethod("parentElement", &AccessibilityUIElement::parentElementCallback);
+ bindMethod("increment", &AccessibilityUIElement::incrementCallback);
+ bindMethod("decrement", &AccessibilityUIElement::decrementCallback);
+ bindMethod("showMenu", &AccessibilityUIElement::showMenuCallback);
+ bindMethod("press", &AccessibilityUIElement::pressCallback);
+ bindMethod("isEqual", &AccessibilityUIElement::isEqualCallback);
+ bindMethod("addNotificationListener", &AccessibilityUIElement::addNotificationListenerCallback);
+ bindMethod("removeNotificationListener", &AccessibilityUIElement::removeNotificationListenerCallback);
+ bindMethod("takeFocus", &AccessibilityUIElement::takeFocusCallback);
+
+ bindFallbackMethod(&AccessibilityUIElement::fallbackCallback);
+}
+
+AccessibilityUIElement* AccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ return m_factory->getOrCreate(accessibilityObject().childAt(index));
+}
+
+bool AccessibilityUIElement::isEqual(const WebKit::WebAccessibilityObject& other)
+{
+ return accessibilityObject().equals(other);
+}
+
+void AccessibilityUIElement::notificationReceived(const char* notificationName)
+{
+ size_t callbackCount = m_notificationCallbacks.size();
+ for (size_t i = 0; i < callbackCount; i++) {
+ CppVariant notificationNameArgument;
+ notificationNameArgument.set(notificationName);
+ CppVariant invokeResult;
+ m_notificationCallbacks[i].invokeDefault(&notificationNameArgument, 1, invokeResult);
+ }
+}
+
+//
+// Properties
+//
+
+void AccessibilityUIElement::roleGetterCallback(CppVariant* result)
+{
+ result->set(getRole(accessibilityObject()));
+}
+
+void AccessibilityUIElement::titleGetterCallback(CppVariant* result)
+{
+ result->set(getTitle(accessibilityObject()));
+}
+
+void AccessibilityUIElement::descriptionGetterCallback(CppVariant* result)
+{
+ result->set(getDescription(accessibilityObject()));
+}
+
+void AccessibilityUIElement::helpTextGetterCallback(CppVariant* result)
+{
+ result->set(getHelpText(accessibilityObject()));
+}
+
+void AccessibilityUIElement::stringValueGetterCallback(CppVariant* result)
+{
+ result->set(getStringValue(accessibilityObject()));
+}
+
+void AccessibilityUIElement::xGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().boundingBoxRect().x);
+}
+
+void AccessibilityUIElement::yGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().boundingBoxRect().y);
+}
+
+void AccessibilityUIElement::widthGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().boundingBoxRect().width);
+}
+
+void AccessibilityUIElement::heightGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().boundingBoxRect().height);
+}
+
+void AccessibilityUIElement::intValueGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().valueForRange());
+}
+
+void AccessibilityUIElement::minValueGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().minValueForRange());
+}
+
+void AccessibilityUIElement::maxValueGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().maxValueForRange());
+}
+
+void AccessibilityUIElement::childrenCountGetterCallback(CppVariant* result)
+{
+ int count = 1; // Root object always has only one child, the WebView.
+ if (!isRoot())
+ count = accessibilityObject().childCount();
+ result->set(count);
+}
+
+void AccessibilityUIElement::insertionPointLineNumberGetterCallback(CppVariant* result)
+{
+ WebVector<int> lineBreaks;
+ accessibilityObject().lineBreaks(lineBreaks);
+ int cursor = accessibilityObject().selectionEnd();
+ int line = 0;
+ while (line < static_cast<int>(lineBreaks.size()) && lineBreaks[line] <= cursor)
+ line++;
+ result->set(line);
+}
+
+void AccessibilityUIElement::selectedTextRangeGetterCallback(CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->set(std::string());
+}
+
+void AccessibilityUIElement::isEnabledGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isEnabled());
+}
+
+void AccessibilityUIElement::isRequiredGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isRequired());
+}
+
+void AccessibilityUIElement::isFocusedGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isFocused());
+}
+
+void AccessibilityUIElement::isFocusableGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().canSetFocusAttribute());
+}
+
+void AccessibilityUIElement::isSelectedGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isSelected());
+}
+
+void AccessibilityUIElement::isSelectableGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().canSetSelectedAttribute());
+}
+
+void AccessibilityUIElement::isMultiSelectableGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isMultiSelectable());
+}
+
+void AccessibilityUIElement::isSelectedOptionActiveGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isSelectedOptionActive());
+}
+
+void AccessibilityUIElement::isExpandedGetterCallback(CppVariant* result)
+{
+ result->set(!accessibilityObject().isCollapsed());
+}
+
+void AccessibilityUIElement::isCheckedGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isChecked());
+}
+
+void AccessibilityUIElement::isVisibleGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isVisible());
+}
+
+void AccessibilityUIElement::isOffScreenGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isOffScreen());
+}
+
+void AccessibilityUIElement::isCollapsedGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isCollapsed());
+}
+
+void AccessibilityUIElement::hasPopupGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().ariaHasPopup());
+}
+
+void AccessibilityUIElement::isValidGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isValid());
+}
+
+void AccessibilityUIElement::orientationGetterCallback(CppVariant* result)
+{
+ result->set(getOrientation(accessibilityObject()));
+}
+
+//
+// Methods
+//
+
+void AccessibilityUIElement::allAttributesCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->set(getAttributes(accessibilityObject()));
+}
+
+void AccessibilityUIElement::attributesOfLinkedUIElementsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfDocumentLinksCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfChildrenCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ AttributesCollector collector;
+ unsigned size = accessibilityObject().childCount();
+ for (unsigned i = 0; i < size; ++i)
+ collector.collectAttributes(accessibilityObject().childAt(i));
+ result->set(collector.attributes());
+}
+
+void AccessibilityUIElement::parametrizedAttributeNamesCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::lineForIndexCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::boundsForRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::stringForRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::childAtIndexCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (!arguments.size() || !arguments[0].isNumber()) {
+ result->setNull();
+ return;
+ }
+
+ AccessibilityUIElement* child = getChildAtIndex(arguments[0].toInt32());
+ if (!child) {
+ result->setNull();
+ return;
+ }
+
+ result->set(*(child->getAsCppVariant()));
+}
+
+void AccessibilityUIElement::elementAtPointCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfColumnHeadersCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfRowHeadersCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfColumnsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfRowsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfVisibleCellsCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributesOfHeaderCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::indexInTableCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::rowIndexRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::columnIndexRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::cellForColumnAndRowCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::titleUIElementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::setSelectedTextRangeCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::attributeValueCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::isAttributeSettableCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 && !arguments[0].isString()) {
+ result->setNull();
+ return;
+ }
+
+ string attribute = arguments[0].toString();
+ bool settable = false;
+ if (attribute == "AXValue")
+ settable = accessibilityObject().canSetValueAttribute();
+ result->set(settable);
+}
+
+void AccessibilityUIElement::isActionSupportedCallback(const CppArgumentList&, CppVariant* result)
+{
+ // This one may be really hard to implement.
+ // Not exposed by AccessibilityObject.
+ result->setNull();
+}
+
+void AccessibilityUIElement::parentElementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::incrementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::decrementCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::showMenuCallback(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::pressCallback(const CppArgumentList&, CppVariant* result)
+{
+ accessibilityObject().performDefaultAction();
+ result->setNull();
+}
+
+void AccessibilityUIElement::isEqualCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 || !arguments[0].isObject()) {
+ result->setNull();
+ return;
+ }
+
+ result->set(arguments[0].isEqual(*getAsCppVariant()));
+}
+
+void AccessibilityUIElement::addNotificationListenerCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 || !arguments[0].isObject()) {
+ result->setNull();
+ return;
+ }
+
+ m_notificationCallbacks.push_back(arguments[0]);
+ result->setNull();
+}
+
+void AccessibilityUIElement::removeNotificationListenerCallback(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void AccessibilityUIElement::takeFocusCallback(const CppArgumentList&, CppVariant* result)
+{
+ accessibilityObject().setFocused(true);
+ result->setNull();
+}
+
+void AccessibilityUIElement::fallbackCallback(const CppArgumentList &, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+RootAccessibilityUIElement::RootAccessibilityUIElement(const WebAccessibilityObject &object, Factory *factory)
+ : AccessibilityUIElement(object, factory) { }
+
+AccessibilityUIElement* RootAccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ if (index)
+ return 0;
+
+ return factory()->getOrCreate(accessibilityObject());
+}
+
+
+AccessibilityUIElementList ::~AccessibilityUIElementList()
+{
+ clear();
+}
+
+void AccessibilityUIElementList::clear()
+{
+ for (ElementList::iterator i = m_elements.begin(); i != m_elements.end(); ++i)
+ delete (*i);
+ m_elements.clear();
+}
+
+AccessibilityUIElement* AccessibilityUIElementList::getOrCreate(const WebAccessibilityObject& object)
+{
+ if (object.isNull())
+ return 0;
+
+ size_t elementCount = m_elements.size();
+ for (size_t i = 0; i < elementCount; i++) {
+ if (m_elements[i]->isEqual(object))
+ return m_elements[i];
+ }
+
+ AccessibilityUIElement* element = new AccessibilityUIElement(object, this);
+ m_elements.append(element);
+ return element;
+}
+
+AccessibilityUIElement* AccessibilityUIElementList::createRoot(const WebAccessibilityObject& object)
+{
+ AccessibilityUIElement* element = new RootAccessibilityUIElement(object, this);
+ m_elements.append(element);
+ return element;
+}
diff --git a/Tools/DumpRenderTree/chromium/AccessibilityUIElement.h b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.h
new file mode 100644
index 000000000..b5fce86f0
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.h
@@ -0,0 +1,164 @@
+/*
+ * 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 AccessibilityUIElement_h
+#define AccessibilityUIElement_h
+
+#include "CppBoundClass.h"
+#include "WebAccessibilityObject.h"
+#include <vector>
+#include <wtf/Vector.h>
+
+class AccessibilityUIElement : public CppBoundClass {
+public:
+ class Factory {
+ public:
+ virtual ~Factory() { }
+ virtual AccessibilityUIElement* getOrCreate(const WebKit::WebAccessibilityObject&) = 0;
+ };
+
+ AccessibilityUIElement(const WebKit::WebAccessibilityObject&, Factory*);
+
+ virtual AccessibilityUIElement* getChildAtIndex(unsigned);
+ virtual bool isRoot() const { return false; }
+ virtual bool isEqual(const WebKit::WebAccessibilityObject&);
+
+ virtual void notificationReceived(const char *notificationName);
+
+protected:
+ const WebKit::WebAccessibilityObject& accessibilityObject() const { return m_accessibilityObject; }
+
+ Factory* factory() const { return m_factory; }
+
+private:
+ // Bound properties.
+ void roleGetterCallback(CppVariant*);
+ void titleGetterCallback(CppVariant*);
+ void descriptionGetterCallback(CppVariant*);
+ void helpTextGetterCallback(CppVariant*);
+ void stringValueGetterCallback(CppVariant*);
+ void xGetterCallback(CppVariant*);
+ void yGetterCallback(CppVariant*);
+ void widthGetterCallback(CppVariant*);
+ void heightGetterCallback(CppVariant*);
+ void intValueGetterCallback(CppVariant*);
+ void minValueGetterCallback(CppVariant*);
+ void maxValueGetterCallback(CppVariant*);
+ void childrenCountGetterCallback(CppVariant*);
+ void insertionPointLineNumberGetterCallback(CppVariant*);
+ void selectedTextRangeGetterCallback(CppVariant*);
+ void isEnabledGetterCallback(CppVariant*);
+ void isRequiredGetterCallback(CppVariant*);
+ void isFocusedGetterCallback(CppVariant*);
+ void isFocusableGetterCallback(CppVariant*);
+ void isSelectedGetterCallback(CppVariant*);
+ void isSelectableGetterCallback(CppVariant*);
+ void isMultiSelectableGetterCallback(CppVariant*);
+ void isSelectedOptionActiveGetterCallback(CppVariant*);
+ void isExpandedGetterCallback(CppVariant*);
+ void isCheckedGetterCallback(CppVariant*);
+ void isVisibleGetterCallback(CppVariant*);
+ void isOffScreenGetterCallback(CppVariant*);
+ void isCollapsedGetterCallback(CppVariant*);
+ void hasPopupGetterCallback(CppVariant*);
+ void isValidGetterCallback(CppVariant*);
+ void orientationGetterCallback(CppVariant*);
+
+ // Bound methods.
+ void allAttributesCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfLinkedUIElementsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfDocumentLinksCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfChildrenCallback(const CppArgumentList&, CppVariant*);
+ void parametrizedAttributeNamesCallback(const CppArgumentList&, CppVariant*);
+ void lineForIndexCallback(const CppArgumentList&, CppVariant*);
+ void boundsForRangeCallback(const CppArgumentList&, CppVariant*);
+ void stringForRangeCallback(const CppArgumentList&, CppVariant*);
+ void childAtIndexCallback(const CppArgumentList&, CppVariant*);
+ void elementAtPointCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfColumnHeadersCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfRowHeadersCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfColumnsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfRowsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfVisibleCellsCallback(const CppArgumentList&, CppVariant*);
+ void attributesOfHeaderCallback(const CppArgumentList&, CppVariant*);
+ void indexInTableCallback(const CppArgumentList&, CppVariant*);
+ void rowIndexRangeCallback(const CppArgumentList&, CppVariant*);
+ void columnIndexRangeCallback(const CppArgumentList&, CppVariant*);
+ void cellForColumnAndRowCallback(const CppArgumentList&, CppVariant*);
+ void titleUIElementCallback(const CppArgumentList&, CppVariant*);
+ void setSelectedTextRangeCallback(const CppArgumentList&, CppVariant*);
+ void attributeValueCallback(const CppArgumentList&, CppVariant*);
+ void isAttributeSettableCallback(const CppArgumentList&, CppVariant*);
+ void isActionSupportedCallback(const CppArgumentList&, CppVariant*);
+ void parentElementCallback(const CppArgumentList&, CppVariant*);
+ void incrementCallback(const CppArgumentList&, CppVariant*);
+ void decrementCallback(const CppArgumentList&, CppVariant*);
+ void showMenuCallback(const CppArgumentList&, CppVariant*);
+ void pressCallback(const CppArgumentList&, CppVariant*);
+ void isEqualCallback(const CppArgumentList&, CppVariant*);
+ void addNotificationListenerCallback(const CppArgumentList&, CppVariant*);
+ void removeNotificationListenerCallback(const CppArgumentList&, CppVariant*);
+ void takeFocusCallback(const CppArgumentList&, CppVariant*);
+
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ WebKit::WebAccessibilityObject m_accessibilityObject;
+ Factory* m_factory;
+ std::vector<CppVariant> m_notificationCallbacks;
+};
+
+
+class RootAccessibilityUIElement : public AccessibilityUIElement {
+public:
+ RootAccessibilityUIElement(const WebKit::WebAccessibilityObject&, Factory*);
+
+ virtual AccessibilityUIElement* getChildAtIndex(unsigned);
+ virtual bool isRoot() const { return true; }
+};
+
+
+// Provides simple lifetime management of the AccessibilityUIElement instances:
+// all AccessibilityUIElements ever created from the controller are stored in
+// a list and cleared explicitly.
+class AccessibilityUIElementList : public AccessibilityUIElement::Factory {
+public:
+ AccessibilityUIElementList() { }
+ virtual ~AccessibilityUIElementList();
+
+ void clear();
+ virtual AccessibilityUIElement* getOrCreate(const WebKit::WebAccessibilityObject&);
+ AccessibilityUIElement* createRoot(const WebKit::WebAccessibilityObject&);
+
+private:
+ typedef Vector<AccessibilityUIElement*> ElementList;
+ ElementList m_elements;
+};
+
+#endif // AccessibilityUIElement_h
diff --git a/Tools/DumpRenderTree/chromium/CppBoundClass.cpp b/Tools/DumpRenderTree/chromium/CppBoundClass.cpp
new file mode 100644
index 000000000..9b4a3b646
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/CppBoundClass.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * 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.
+ */
+
+// This file contains definitions for CppBoundClass
+
+// Here's the control flow of a JS method getting forwarded to a class.
+// - Something calls our NPObject with a function like "Invoke".
+// - CppNPObject's static invoke() function forwards it to its attached
+// CppBoundClass's invoke() method.
+// - CppBoundClass has then overridden invoke() to look up the function
+// name in its internal map of methods, and then calls the appropriate
+// method.
+
+#include "config.h"
+#include "CppBoundClass.h"
+
+#include "WebBindings.h"
+#include "WebFrame.h"
+#include "platform/WebString.h"
+#include <wtf/Assertions.h>
+#include <wtf/OwnPtr.h>
+
+using namespace WebKit;
+using namespace std;
+
+class CppVariantPropertyCallback : public CppBoundClass::PropertyCallback {
+public:
+ CppVariantPropertyCallback(CppVariant* value) : m_value(value) { }
+
+ virtual bool getValue(CppVariant* value)
+ {
+ value->set(*m_value);
+ return true;
+ }
+
+ virtual bool setValue(const CppVariant& value)
+ {
+ m_value->set(value);
+ return true;
+ }
+
+private:
+ CppVariant* m_value;
+};
+
+class GetterPropertyCallback : public CppBoundClass::PropertyCallback {
+public:
+ GetterPropertyCallback(PassOwnPtr<CppBoundClass::GetterCallback> callback)
+ : m_callback(callback)
+ {
+ }
+
+ virtual bool getValue(CppVariant* value)
+ {
+ m_callback->run(value);
+ return true;
+ }
+
+ virtual bool setValue(const CppVariant& value) { return false; }
+
+private:
+ OwnPtr<CppBoundClass::GetterCallback> m_callback;
+};
+
+// Our special NPObject type. We extend an NPObject with a pointer to a
+// CppBoundClass, which is just a C++ interface that we forward all NPObject
+// callbacks to.
+struct CppNPObject {
+ NPObject parent; // This must be the first field in the struct.
+ CppBoundClass* boundClass;
+
+ //
+ // All following objects and functions are static, and just used to interface
+ // with NPObject/NPClass.
+ //
+
+ // An NPClass associates static functions of CppNPObject with the
+ // function pointers used by the JS runtime.
+ static NPClass npClass;
+
+ // Allocate a new NPObject with the specified class.
+ static NPObject* allocate(NPP, NPClass*);
+
+ // Free an object.
+ static void deallocate(NPObject*);
+
+ // Returns true if the C++ class associated with this NPObject exposes the
+ // given property. Called by the JS runtime.
+ static bool hasProperty(NPObject*, NPIdentifier);
+
+ // Returns true if the C++ class associated with this NPObject exposes the
+ // given method. Called by the JS runtime.
+ static bool hasMethod(NPObject*, NPIdentifier);
+
+ // If the given method is exposed by the C++ class associated with this
+ // NPObject, invokes it with the given arguments and returns a result. Otherwise,
+ // returns "undefined" (in the JavaScript sense). Called by the JS runtime.
+ static bool invoke(NPObject*, NPIdentifier,
+ const NPVariant* arguments, uint32_t argumentCount,
+ NPVariant* result);
+
+ // If the given property is exposed by the C++ class associated with this
+ // NPObject, returns its value. Otherwise, returns "undefined" (in the
+ // JavaScript sense). Called by the JS runtime.
+ static bool getProperty(NPObject*, NPIdentifier, NPVariant* result);
+
+ // If the given property is exposed by the C++ class associated with this
+ // NPObject, sets its value. Otherwise, does nothing. Called by the JS
+ // runtime.
+ static bool setProperty(NPObject*, NPIdentifier, const NPVariant* value);
+};
+
+// Build CppNPObject's static function pointers into an NPClass, for use
+// in constructing NPObjects for the C++ classes.
+NPClass CppNPObject::npClass = {
+ NP_CLASS_STRUCT_VERSION,
+ CppNPObject::allocate,
+ CppNPObject::deallocate,
+ /* NPInvalidateFunctionPtr */ 0,
+ CppNPObject::hasMethod,
+ CppNPObject::invoke,
+ /* NPInvokeDefaultFunctionPtr */ 0,
+ CppNPObject::hasProperty,
+ CppNPObject::getProperty,
+ CppNPObject::setProperty,
+ /* NPRemovePropertyFunctionPtr */ 0
+};
+
+NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass)
+{
+ CppNPObject* obj = new CppNPObject;
+ // obj->parent will be initialized by the NPObject code calling this.
+ obj->boundClass = 0;
+ return &obj->parent;
+}
+
+void CppNPObject::deallocate(NPObject* npObj)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ delete obj;
+}
+
+bool CppNPObject::hasMethod(NPObject* npObj, NPIdentifier ident)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->hasMethod(ident);
+}
+
+bool CppNPObject::hasProperty(NPObject* npObj, NPIdentifier ident)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->hasProperty(ident);
+}
+
+bool CppNPObject::invoke(NPObject* npObj, NPIdentifier ident,
+ const NPVariant* arguments, uint32_t argumentCount,
+ NPVariant* result)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->invoke(ident, arguments, argumentCount, result);
+}
+
+bool CppNPObject::getProperty(NPObject* npObj, NPIdentifier ident, NPVariant* result)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->getProperty(ident, result);
+}
+
+bool CppNPObject::setProperty(NPObject* npObj, NPIdentifier ident, const NPVariant* value)
+{
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ return obj->boundClass->setProperty(ident, value);
+}
+
+CppBoundClass::~CppBoundClass()
+{
+ for (MethodList::iterator i = m_methods.begin(); i != m_methods.end(); ++i)
+ delete i->second;
+
+ for (PropertyList::iterator i = m_properties.begin(); i != m_properties.end(); ++i)
+ delete i->second;
+
+ // Unregister ourselves if we were bound to a frame.
+ if (m_boundToFrame)
+ WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(m_selfVariant));
+}
+
+bool CppBoundClass::hasMethod(NPIdentifier ident) const
+{
+ return m_methods.find(ident) != m_methods.end();
+}
+
+bool CppBoundClass::hasProperty(NPIdentifier ident) const
+{
+ return m_properties.find(ident) != m_properties.end();
+}
+
+bool CppBoundClass::invoke(NPIdentifier ident,
+ const NPVariant* arguments,
+ size_t argumentCount,
+ NPVariant* result) {
+ MethodList::const_iterator end = m_methods.end();
+ MethodList::const_iterator method = m_methods.find(ident);
+ Callback* callback;
+ if (method == end) {
+ if (!m_fallbackCallback.get()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ callback = m_fallbackCallback.get();
+ } else
+ callback = (*method).second;
+
+ // Build a CppArgumentList argument vector from the NPVariants coming in.
+ CppArgumentList cppArguments(argumentCount);
+ for (size_t i = 0; i < argumentCount; i++)
+ cppArguments[i].set(arguments[i]);
+
+ CppVariant cppResult;
+ callback->run(cppArguments, &cppResult);
+
+ cppResult.copyToNPVariant(result);
+ return true;
+}
+
+bool CppBoundClass::getProperty(NPIdentifier ident, NPVariant* result) const
+{
+ PropertyList::const_iterator callback = m_properties.find(ident);
+ if (callback == m_properties.end()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+
+ CppVariant cppValue;
+ if (!callback->second->getValue(&cppValue))
+ return false;
+ cppValue.copyToNPVariant(result);
+ return true;
+}
+
+bool CppBoundClass::setProperty(NPIdentifier ident, const NPVariant* value)
+{
+ PropertyList::iterator callback = m_properties.find(ident);
+ if (callback == m_properties.end())
+ return false;
+
+ CppVariant cppValue;
+ cppValue.set(*value);
+ return (*callback).second->setValue(cppValue);
+}
+
+void CppBoundClass::bindCallback(const string& name, Callback* callback)
+{
+ NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
+ MethodList::iterator oldCallback = m_methods.find(ident);
+ if (oldCallback != m_methods.end()) {
+ delete oldCallback->second;
+ if (!callback) {
+ m_methods.remove(oldCallback);
+ return;
+ }
+ }
+
+ m_methods.set(ident, callback);
+}
+
+void CppBoundClass::bindGetterCallback(const string& name, PassOwnPtr<GetterCallback> callback)
+{
+ PropertyCallback* propertyCallback = callback ? new GetterPropertyCallback(callback) : 0;
+ bindProperty(name, propertyCallback);
+}
+
+void CppBoundClass::bindProperty(const string& name, CppVariant* prop)
+{
+ PropertyCallback* propertyCallback = prop ? new CppVariantPropertyCallback(prop) : 0;
+ bindProperty(name, propertyCallback);
+}
+
+void CppBoundClass::bindProperty(const string& name, PropertyCallback* callback)
+{
+ NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
+ PropertyList::iterator oldCallback = m_properties.find(ident);
+ if (oldCallback != m_properties.end()) {
+ delete oldCallback->second;
+ if (!callback) {
+ m_properties.remove(oldCallback);
+ return;
+ }
+ }
+
+ m_properties.set(ident, callback);
+}
+
+bool CppBoundClass::isMethodRegistered(const string& name) const
+{
+ NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
+ MethodList::const_iterator callback = m_methods.find(ident);
+ return callback != m_methods.end();
+}
+
+CppVariant* CppBoundClass::getAsCppVariant()
+{
+ if (!m_selfVariant.isObject()) {
+ // Create an NPObject using our static NPClass. The first argument (a
+ // plugin's instance handle) is passed through to the allocate function
+ // directly, and we don't use it, so it's ok to be 0.
+ NPObject* npObj = WebBindings::createObject(0, &CppNPObject::npClass);
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
+ obj->boundClass = this;
+ m_selfVariant.set(npObj);
+ WebBindings::releaseObject(npObj); // CppVariant takes the reference.
+ }
+ ASSERT(m_selfVariant.isObject());
+ return &m_selfVariant;
+}
+
+void CppBoundClass::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ // BindToWindowObject will take its own reference to the NPObject, and clean
+ // up after itself. It will also (indirectly) register the object with V8,
+ // so we must remember this so we can unregister it when we're destroyed.
+ frame->bindToWindowObject(classname, NPVARIANT_TO_OBJECT(*getAsCppVariant()));
+ m_boundToFrame = true;
+}
diff --git a/Tools/DumpRenderTree/chromium/CppBoundClass.h b/Tools/DumpRenderTree/chromium/CppBoundClass.h
new file mode 100644
index 000000000..4fb5361e1
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/CppBoundClass.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * 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.
+ */
+
+/*
+ CppBoundClass class:
+ This base class serves as a parent for C++ classes designed to be bound to
+ JavaScript objects.
+
+ Subclasses should define the constructor to build the property and method
+ lists needed to bind this class to a JS object. They should also declare
+ and define member variables and methods to be exposed to JS through
+ that object.
+*/
+
+#ifndef CppBoundClass_h
+#define CppBoundClass_h
+
+#include "CppVariant.h"
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+class WebFrame;
+class WebString;
+}
+
+typedef Vector<CppVariant> CppArgumentList;
+
+// CppBoundClass lets you map Javascript method calls and property accesses
+// directly to C++ method calls and CppVariant* variable access.
+class CppBoundClass {
+ WTF_MAKE_NONCOPYABLE(CppBoundClass);
+public:
+ class PropertyCallback {
+ public:
+ virtual ~PropertyCallback() { }
+
+ // Sets |value| to the value of the property. Returns false in case of
+ // failure. |value| is always non-0.
+ virtual bool getValue(CppVariant* result) = 0;
+
+ // sets the property value to |value|. Returns false in case of failure.
+ virtual bool setValue(const CppVariant&) = 0;
+ };
+
+ // Callback class for "void function(CppVariant*)"
+ class GetterCallback {
+ public:
+ virtual ~GetterCallback() { }
+ virtual void run(CppVariant*) = 0;
+ };
+
+ // The constructor should call BindMethod, BindProperty, and
+ // SetFallbackMethod as needed to set up the methods, properties, and
+ // fallback method.
+ CppBoundClass() : m_boundToFrame(false) { }
+ virtual ~CppBoundClass();
+
+ // Return a CppVariant representing this class, for use with BindProperty().
+ // The variant type is guaranteed to be NPVariantType_Object.
+ CppVariant* getAsCppVariant();
+
+ // Given a WebFrame, BindToJavascript builds the NPObject that will represent
+ // the class and binds it to the frame's window under the given name. This
+ // should generally be called from the WebView delegate's
+ // WindowObjectCleared(). A class so bound will be accessible to JavaScript
+ // as window.<classname>. The owner of the CppBoundObject is responsible for
+ // keeping the object around while the frame is alive, and for destroying it
+ // afterwards.
+ void bindToJavascript(WebKit::WebFrame*, const WebKit::WebString& classname);
+
+ // Used by a test. Returns true if a method with the specified name exists,
+ // regardless of whether a fallback is registered.
+ bool isMethodRegistered(const std::string&) const;
+
+protected:
+ // Callback for "void function(const CppArguemntList&, CppVariant*)"
+ class Callback {
+ public:
+ virtual ~Callback() { }
+ virtual void run(const CppArgumentList&, CppVariant*) = 0;
+ };
+
+ // Callback for "void T::method(const CppArguemntList&, CppVariant*)"
+ template <class T> class MemberCallback : public Callback {
+ public:
+ typedef void (T::*MethodType)(const CppArgumentList&, CppVariant*);
+ MemberCallback(T* object, MethodType method)
+ : m_object(object)
+ , m_method(method) { }
+ virtual ~MemberCallback() { }
+
+ virtual void run(const CppArgumentList& arguments, CppVariant* result)
+ {
+ (m_object->*m_method)(arguments, result);
+ }
+
+ private:
+ T* m_object;
+ MethodType m_method;
+ };
+
+ // Callback class for "void T::method(CppVariant*)"
+ template <class T> class MemberGetterCallback : public GetterCallback {
+ public:
+ typedef void (T::*MethodType)(CppVariant*);
+ MemberGetterCallback(T* object, MethodType method)
+ : m_object(object)
+ , m_method(method) { }
+ virtual ~MemberGetterCallback() { }
+
+ virtual void run(CppVariant* result) { (m_object->*m_method)(result); }
+
+ private:
+ T* m_object;
+ MethodType m_method;
+ };
+
+ // Bind the Javascript method called the string parameter to the C++ method.
+ void bindCallback(const std::string&, Callback*);
+
+ // A wrapper for bindCallback, to simplify the common case of binding a
+ // method on the current object. Though not verified here, the method parameter
+ // must be a method of this CppBoundClass subclass.
+ template<class T>
+ void bindMethod(const std::string& name, void (T::*method)(const CppArgumentList&, CppVariant*))
+ {
+ Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method);
+ bindCallback(name, callback);
+ }
+
+ // Bind Javascript property |name| to the C++ getter callback |callback|.
+ // This can be used to create read-only properties.
+ void bindGetterCallback(const std::string&, PassOwnPtr<GetterCallback>);
+
+ // A wrapper for BindGetterCallback, to simplify the common case of binding a
+ // property on the current object. Though not verified here, the method parameter
+ // must be a method of this CppBoundClass subclass.
+ template<class T>
+ void bindProperty(const std::string& name, void (T::*method)(CppVariant*))
+ {
+ OwnPtr<GetterCallback> callback = adoptPtr(new MemberGetterCallback<T>(static_cast<T*>(this), method));
+ bindGetterCallback(name, callback.release());
+ }
+
+ // Bind the Javascript property called |name| to a CppVariant.
+ void bindProperty(const std::string&, CppVariant*);
+
+ // Bind Javascript property called |name| to a PropertyCallback.
+ // CppBoundClass assumes control over the life time of the callback.
+ void bindProperty(const std::string&, PropertyCallback*);
+
+ // Set the fallback callback, which is called when when a callback is
+ // invoked that isn't bound.
+ // If it is 0 (its default value), a JavaScript exception is thrown in
+ // that case (as normally expected). If non 0, the fallback method is
+ // invoked and the script continues its execution.
+ // Passing 0 clears out any existing binding.
+ // It is used for tests and should probably only be used in such cases
+ // as it may cause unexpected behaviors (a JavaScript object with a
+ // fallback always returns true when checked for a method's
+ // existence).
+ void bindFallbackCallback(PassOwnPtr<Callback> fallbackCallback)
+ {
+ m_fallbackCallback = fallbackCallback;
+ }
+
+ // A wrapper for BindFallbackCallback, to simplify the common case of
+ // binding a method on the current object. Though not verified here,
+ // |method| must be a method of this CppBoundClass subclass.
+ // Passing 0 for |method| clears out any existing binding.
+ template<class T>
+ void bindFallbackMethod(void (T::*method)(const CppArgumentList&, CppVariant*))
+ {
+ if (method) {
+ OwnPtr<Callback> callback = adoptPtr(new MemberCallback<T>(static_cast<T*>(this), method));
+ bindFallbackCallback(callback.release());
+ } else
+ bindFallbackCallback(nullptr);
+ }
+
+ // Some fields are protected because some tests depend on accessing them,
+ // but otherwise they should be considered private.
+
+ typedef HashMap<NPIdentifier, PropertyCallback*> PropertyList;
+ typedef HashMap<NPIdentifier, Callback*> MethodList;
+ // These maps associate names with property and method pointers to be
+ // exposed to JavaScript.
+ PropertyList m_properties;
+ MethodList m_methods;
+
+ // The callback gets invoked when a call is made to an nonexistent method.
+ OwnPtr<Callback> m_fallbackCallback;
+
+private:
+ // NPObject callbacks.
+ friend struct CppNPObject;
+ bool hasMethod(NPIdentifier) const;
+ bool invoke(NPIdentifier, const NPVariant* args, size_t argCount,
+ NPVariant* result);
+ bool hasProperty(NPIdentifier) const;
+ bool getProperty(NPIdentifier, NPVariant* result) const;
+ bool setProperty(NPIdentifier, const NPVariant*);
+
+ // A lazily-initialized CppVariant representing this class. We retain 1
+ // reference to this object, and it is released on deletion.
+ CppVariant m_selfVariant;
+
+ // True if our np_object has been bound to a WebFrame, in which case it must
+ // be unregistered with V8 when we delete it.
+ bool m_boundToFrame;
+};
+
+#endif // CppBoundClass_h
diff --git a/Tools/DumpRenderTree/chromium/CppVariant.cpp b/Tools/DumpRenderTree/chromium/CppVariant.cpp
new file mode 100644
index 000000000..b587d75aa
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/CppVariant.cpp
@@ -0,0 +1,321 @@
+/*
+ * 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 "CppVariant.h"
+
+#include "WebBindings.h"
+#include <limits>
+#include <wtf/Assertions.h>
+#include <wtf/StringExtras.h>
+
+using namespace WebKit;
+using namespace std;
+
+CppVariant::CppVariant()
+{
+ type = NPVariantType_Null;
+}
+
+// Note that Set() performs a deep copy, which is necessary to safely
+// call FreeData() on the value in the destructor.
+CppVariant::CppVariant(const CppVariant& original)
+{
+ type = NPVariantType_Null;
+ set(original);
+}
+
+// See comment for copy constructor, above.
+CppVariant& CppVariant::operator=(const CppVariant& original)
+{
+ if (&original != this)
+ set(original);
+ return *this;
+}
+
+CppVariant::~CppVariant()
+{
+ freeData();
+}
+
+void CppVariant::freeData()
+{
+ WebBindings::releaseVariantValue(this);
+}
+
+bool CppVariant::isEqual(const CppVariant& other) const
+{
+ if (type != other.type)
+ return false;
+
+ switch (type) {
+ case NPVariantType_Bool:
+ return (value.boolValue == other.value.boolValue);
+ case NPVariantType_Int32:
+ return (value.intValue == other.value.intValue);
+ case NPVariantType_Double:
+ return (value.doubleValue == other.value.doubleValue);
+ case NPVariantType_String: {
+ const NPString *this_value = &value.stringValue;
+ const NPString *other_value = &other.value.stringValue;
+ uint32_t len = this_value->UTF8Length;
+ return len == other_value->UTF8Length
+ && !strncmp(this_value->UTF8Characters,
+ other_value->UTF8Characters, len);
+ }
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ return true;
+ case NPVariantType_Object: {
+ NPObject* thisValue = value.objectValue;
+ NPObject* otherValue = other.value.objectValue;
+ return thisValue->_class == otherValue->_class
+ && thisValue->referenceCount == otherValue->referenceCount;
+ }
+ }
+ return false;
+}
+
+void CppVariant::copyToNPVariant(NPVariant* result) const
+{
+ result->type = type;
+ switch (type) {
+ case NPVariantType_Bool:
+ result->value.boolValue = value.boolValue;
+ break;
+ case NPVariantType_Int32:
+ result->value.intValue = value.intValue;
+ break;
+ case NPVariantType_Double:
+ result->value.doubleValue = value.doubleValue;
+ break;
+ case NPVariantType_String:
+ WebBindings::initializeVariantWithStringCopy(result, &value.stringValue);
+ break;
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ // Nothing to set.
+ break;
+ case NPVariantType_Object:
+ result->type = NPVariantType_Object;
+ result->value.objectValue = WebBindings::retainObject(value.objectValue);
+ break;
+ }
+}
+
+void CppVariant::set(const NPVariant& newValue)
+{
+ freeData();
+ switch (newValue.type) {
+ case NPVariantType_Bool:
+ set(newValue.value.boolValue);
+ break;
+ case NPVariantType_Int32:
+ set(newValue.value.intValue);
+ break;
+ case NPVariantType_Double:
+ set(newValue.value.doubleValue);
+ break;
+ case NPVariantType_String:
+ set(newValue.value.stringValue);
+ break;
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ type = newValue.type;
+ break;
+ case NPVariantType_Object:
+ set(newValue.value.objectValue);
+ break;
+ }
+}
+
+void CppVariant::setNull()
+{
+ freeData();
+ type = NPVariantType_Null;
+}
+
+void CppVariant::set(bool newValue)
+{
+ freeData();
+ type = NPVariantType_Bool;
+ value.boolValue = newValue;
+}
+
+void CppVariant::set(int32_t newValue)
+{
+ freeData();
+ type = NPVariantType_Int32;
+ value.intValue = newValue;
+}
+
+void CppVariant::set(double newValue)
+{
+ freeData();
+ type = NPVariantType_Double;
+ value.doubleValue = newValue;
+}
+
+// The newValue must be a null-terminated string.
+void CppVariant::set(const char* newValue)
+{
+ freeData();
+ type = NPVariantType_String;
+ NPString newString = {newValue,
+ static_cast<uint32_t>(strlen(newValue))};
+ WebBindings::initializeVariantWithStringCopy(this, &newString);
+}
+
+void CppVariant::set(const string& newValue)
+{
+ freeData();
+ type = NPVariantType_String;
+ NPString newString = {newValue.data(),
+ static_cast<uint32_t>(newValue.size())};
+ WebBindings::initializeVariantWithStringCopy(this, &newString);
+}
+
+void CppVariant::set(const NPString& newValue)
+{
+ freeData();
+ type = NPVariantType_String;
+ WebBindings::initializeVariantWithStringCopy(this, &newValue);
+}
+
+void CppVariant::set(NPObject* newValue)
+{
+ freeData();
+ type = NPVariantType_Object;
+ value.objectValue = WebBindings::retainObject(newValue);
+}
+
+string CppVariant::toString() const
+{
+ ASSERT(isString());
+ return string(value.stringValue.UTF8Characters,
+ value.stringValue.UTF8Length);
+}
+
+int32_t CppVariant::toInt32() const
+{
+ if (isInt32())
+ return value.intValue;
+ if (isDouble())
+ return static_cast<int32_t>(value.doubleValue);
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+double CppVariant::toDouble() const
+{
+ if (isInt32())
+ return static_cast<double>(value.intValue);
+ if (isDouble())
+ return value.doubleValue;
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+bool CppVariant::toBoolean() const
+{
+ ASSERT(isBool());
+ return value.boolValue;
+}
+
+Vector<string> CppVariant::toStringVector() const
+{
+
+ ASSERT(isObject());
+ Vector<string> stringVector;
+ NPObject* npValue = value.objectValue;
+ NPIdentifier lengthId = WebBindings::getStringIdentifier("length");
+
+ if (!WebBindings::hasProperty(0, npValue, lengthId))
+ return stringVector;
+
+ NPVariant lengthValue;
+ if (!WebBindings::getProperty(0, npValue, lengthId, &lengthValue))
+ return stringVector;
+
+ int length = 0;
+ // The length is a double in some cases.
+ if (NPVARIANT_IS_DOUBLE(lengthValue))
+ length = static_cast<int>(NPVARIANT_TO_DOUBLE(lengthValue));
+ else if (NPVARIANT_IS_INT32(lengthValue))
+ length = NPVARIANT_TO_INT32(lengthValue);
+ WebBindings::releaseVariantValue(&lengthValue);
+
+ // For sanity, only allow 100 items.
+ length = min(100, length);
+ for (int i = 0; i < length; ++i) {
+ // Get each of the items.
+ char indexInChar[20]; // Enough size to store 32-bit integer
+ snprintf(indexInChar, 20, "%d", i);
+ string index(indexInChar);
+ NPIdentifier indexId = WebBindings::getStringIdentifier(index.c_str());
+ if (!WebBindings::hasProperty(0, npValue, indexId))
+ continue;
+ NPVariant indexValue;
+ if (!WebBindings::getProperty(0, npValue, indexId, &indexValue))
+ continue;
+ if (NPVARIANT_IS_STRING(indexValue)) {
+ string item(NPVARIANT_TO_STRING(indexValue).UTF8Characters,
+ NPVARIANT_TO_STRING(indexValue).UTF8Length);
+ stringVector.append(item);
+ }
+ WebBindings::releaseVariantValue(&indexValue);
+ }
+ return stringVector;
+}
+
+bool CppVariant::invoke(const string& method, const CppVariant* arguments,
+ uint32_t argumentCount, CppVariant& result) const
+{
+ ASSERT(isObject());
+ NPIdentifier methodName = WebBindings::getStringIdentifier(method.c_str());
+ NPObject* npObject = value.objectValue;
+ if (!WebBindings::hasMethod(0, npObject, methodName))
+ return false;
+ NPVariant r;
+ bool status = WebBindings::invoke(0, npObject, methodName, arguments, argumentCount, &r);
+ result.set(r);
+ return status;
+}
+
+bool CppVariant::invokeDefault(const CppVariant* arguments, uint32_t argumentCount,
+ CppVariant& result) const
+{
+ ASSERT(isObject());
+ NPObject* npObject = value.objectValue;
+ NPVariant r;
+ bool status = WebBindings::invokeDefault(0, npObject, arguments, argumentCount, &r);
+ result.set(r);
+ return status;
+}
diff --git a/Tools/DumpRenderTree/chromium/CppVariant.h b/Tools/DumpRenderTree/chromium/CppVariant.h
new file mode 100644
index 000000000..60cc6271e
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/CppVariant.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+/*
+ This file contains the declaration for CppVariant, a type used by C++ classes
+ that are to be bound to JavaScript objects.
+
+ CppVariant exists primarily as an interface between C++ callers and the
+ corresponding NPVariant type. CppVariant also provides a number of
+ convenience constructors and accessors, so that the NPVariantType values
+ don't need to be exposed, and a destructor to free any memory allocated for
+ string values.
+*/
+
+#ifndef CppVariant_h
+#define CppVariant_h
+
+#include "WebBindings.h"
+#include "webkit/support/webkit_support.h"
+#include <string>
+#include <wtf/Vector.h>
+
+class CppVariant : public NPVariant {
+public:
+ CppVariant();
+ ~CppVariant();
+ void setNull();
+ void set(bool);
+ void set(int32_t);
+ void set(double);
+
+ // Note that setting a CppVariant to a string value involves copying the
+ // string data, which must be freed with a call to freeData() when the
+ // CppVariant is set to a different value or is no longer needed. Normally
+ // this is handled by the other set() methods and by the destructor.
+ void set(const char*); // Must be a null-terminated string.
+ void set(const std::string&);
+ void set(const NPString&);
+ void set(const NPVariant&);
+
+ // Note that setting a CppVariant to an NPObject involves ref-counting
+ // the actual object. freeData() should only be called if the CppVariant
+ // is no longer needed. The other set() methods handle this internally.
+ // Also, the object's NPClass is expected to be a static object: neither
+ // the NP runtime nor CppVariant will ever free it.
+ void set(NPObject*_value);
+
+ // These three methods all perform deep copies of any string data. This
+ // allows local CppVariants to be released by the destructor without
+ // corrupting their sources. In performance-critical code, or when strings
+ // are very long, avoid creating new CppVariants.
+ // In case of NPObject as the data, the copying involves ref-counting
+ // as opposed to deep-copying. The ref-counting ensures that sources don't
+ // get corrupted when the copies get destroyed.
+ void copyToNPVariant(NPVariant* result) const;
+ CppVariant& operator=(const CppVariant& original);
+ CppVariant(const CppVariant& original);
+
+ // Calls NPN_ReleaseVariantValue, which frees any string data
+ // held by the object and sets its type to null.
+ // In case of NPObject, the NPN_ReleaseVariantValue decrements
+ // the ref-count (releases when ref-count becomes 0)
+ void freeData();
+
+ // Compares this CppVariant's type and value to another's. They must be
+ // identical in both type and value to be considered equal. For string and
+ // object types, a deep comparison is performed; that is, the contents of the
+ // strings, or the classes and refcounts of the objects, must be the same,
+ // but they need not be the same pointers.
+ bool isEqual(const CppVariant&) const;
+
+ // The value of a CppVariant may be read directly from its NPVariant (but
+ // should only be set using one of the set() methods above). Although the
+ // type of a CppVariant is likewise public, it can be accessed through these
+ // functions rather than directly if a caller wishes to avoid dependence on
+ // the NPVariantType values.
+ bool isBool() const { return (type == NPVariantType_Bool); }
+ bool isInt32() const { return (type == NPVariantType_Int32); }
+ bool isDouble() const { return (type == NPVariantType_Double); }
+ bool isNumber() const { return (isInt32() || isDouble()); }
+ bool isString() const { return (type == NPVariantType_String); }
+ bool isVoid() const { return (type == NPVariantType_Void); }
+ bool isNull() const { return (type == NPVariantType_Null); }
+ bool isEmpty() const { return (isVoid() || isNull()); }
+ bool isObject() const { return (type == NPVariantType_Object); }
+
+ // Converters. The CppVariant must be of a type convertible to these values.
+ // For example, toInt32() works only if isNumber() is true.
+ std::string toString() const;
+ int32_t toInt32() const;
+ double toDouble() const;
+ bool toBoolean() const;
+ // Returns a vector of strings for the specified argument. This is useful
+ // for converting a JavaScript array of strings into a vector of strings.
+ Vector<std::string> toStringVector() const;
+
+ // Invoke method of the given name on an object with the supplied arguments.
+ // The first argument should be the object on which the method is to be
+ // invoked. Returns whether the method was successfully invoked. If the
+ // method was invoked successfully, any return value is stored in the
+ // CppVariant specified by result.
+ bool invoke(const std::string&, const CppVariant* arguments,
+ uint32_t argumentCount, CppVariant& result) const;
+
+ // Invoke an object's default method with the supplied arguments.
+ // The first argument should be the object on which the method is to be
+ // invoked. Returns whether the method was successfully invoked. If the
+ // method was invoked successfully, any return value is stored in the
+ // CppVariant specified by result.
+ bool invokeDefault(const CppVariant* arguments,
+ uint32_t argumentCount, CppVariant& result) const;
+};
+
+#endif // CppVariant_h
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp
new file mode 100644
index 000000000..21aed1b9d
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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 "DRTDevToolsAgent.h"
+
+#include "DRTDevToolsClient.h"
+
+#include "platform/WebCString.h"
+#include "WebDevToolsAgent.h"
+#include "WebView.h"
+#include "webkit/support/webkit_support.h"
+
+using namespace WebKit;
+
+DRTDevToolsAgent::DRTDevToolsAgent()
+ : m_drtDevToolsClient(0)
+ , m_webView(0)
+{
+ static int devToolsAgentCounter = 0;
+
+ m_routingID = ++devToolsAgentCounter;
+}
+
+void DRTDevToolsAgent::reset()
+{
+ m_taskList.revokeAll();
+}
+
+void DRTDevToolsAgent::setWebView(WebView* webView)
+{
+ m_webView = webView;
+}
+
+void DRTDevToolsAgent::sendMessageToInspectorFrontend(const WebString& data)
+{
+ if (m_drtDevToolsClient)
+ m_drtDevToolsClient->asyncCall(data);
+}
+
+void DRTDevToolsAgent::runtimePropertyChanged(const WebString& name, const WebString& value)
+{
+ // FIXME: Implement.
+}
+
+WebDevToolsAgentClient::WebKitClientMessageLoop* DRTDevToolsAgent::createClientMessageLoop()
+{
+ return webkit_support::CreateDevToolsMessageLoop();
+}
+
+void DRTDevToolsAgent::asyncCall(const WebString& args)
+{
+ postTask(new AsyncCallTask(this, args));
+}
+
+void DRTDevToolsAgent::call(const WebString& args)
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (agent)
+ agent->dispatchOnInspectorBackend(args);
+}
+
+WebDevToolsAgent* DRTDevToolsAgent::webDevToolsAgent()
+{
+ if (!m_webView)
+ return 0;
+ return m_webView->devToolsAgent();
+}
+
+void DRTDevToolsAgent::attach(DRTDevToolsClient* client)
+{
+ ASSERT(!m_drtDevToolsClient);
+ m_drtDevToolsClient = client;
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (agent)
+ agent->attach();
+}
+
+void DRTDevToolsAgent::detach()
+{
+ ASSERT(m_drtDevToolsClient);
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (agent)
+ agent->detach();
+ m_drtDevToolsClient = 0;
+}
+
+bool DRTDevToolsAgent::setJavaScriptProfilingEnabled(bool enabled)
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (!agent)
+ return false;
+ agent->setJavaScriptProfilingEnabled(enabled);
+ return true;
+}
+
+bool DRTDevToolsAgent::evaluateInWebInspector(long callID, const std::string& script)
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (!agent)
+ return false;
+ agent->evaluateInWebInspector(callID, WebString::fromUTF8(script));
+ return true;
+}
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h
new file mode 100644
index 000000000..6e491ad53
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h
@@ -0,0 +1,96 @@
+/*
+ * 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 DRTDevToolsAgent_h
+#define DRTDevToolsAgent_h
+
+#include "Task.h"
+#include "WebDevToolsAgentClient.h"
+#include "platform/WebString.h"
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebKit {
+
+class WebCString;
+class WebDevToolsAgent;
+class WebView;
+struct WebDevToolsMessageData;
+
+} // namespace WebKit
+
+class DRTDevToolsClient;
+
+class DRTDevToolsAgent : public WebKit::WebDevToolsAgentClient {
+ WTF_MAKE_NONCOPYABLE(DRTDevToolsAgent);
+public:
+ DRTDevToolsAgent();
+ virtual ~DRTDevToolsAgent() { }
+ void reset();
+
+ void setWebView(WebKit::WebView*);
+
+ // WebDevToolsAgentClient implementation.
+ virtual void sendMessageToInspectorFrontend(const WebKit::WebString&);
+ virtual int hostIdentifier() { return m_routingID; }
+ virtual void runtimePropertyChanged(const WebKit::WebString& name, const WebKit::WebString& value);
+ virtual WebKitClientMessageLoop* createClientMessageLoop();
+
+ void asyncCall(const WebKit::WebString& args);
+
+ void attach(DRTDevToolsClient*);
+ void detach();
+
+ bool evaluateInWebInspector(long callID, const std::string& script);
+ bool setJavaScriptProfilingEnabled(bool);
+ TaskList* taskList() { return &m_taskList; }
+
+private:
+ void call(const WebKit::WebString& args);
+ WebKit::WebDevToolsAgent* webDevToolsAgent();
+
+ class AsyncCallTask: public MethodTask<DRTDevToolsAgent> {
+ public:
+ AsyncCallTask(DRTDevToolsAgent* object, const WebKit::WebString& args)
+ : MethodTask<DRTDevToolsAgent>(object), m_args(args) { }
+ virtual void runIfValid() { m_object->call(m_args); }
+
+ private:
+ WebKit::WebString m_args;
+ };
+
+ TaskList m_taskList;
+ DRTDevToolsClient* m_drtDevToolsClient;
+ int m_routingID;
+ WebKit::WebDevToolsAgent* m_webDevToolsAgent;
+ WebKit::WebView* m_webView;
+};
+
+#endif // DRTDevToolsAgent_h
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp
new file mode 100644
index 000000000..a7fc4d048
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 "DRTDevToolsClient.h"
+
+#include "DRTDevToolsAgent.h"
+#include "WebDevToolsAgent.h"
+#include "WebDevToolsFrontend.h"
+#include "WebFrame.h"
+#include "WebScriptSource.h"
+#include "WebView.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/PassOwnPtr.h>
+
+using namespace WebKit;
+
+DRTDevToolsClient::DRTDevToolsClient(DRTDevToolsAgent* agent, WebView* webView)
+ : m_webView(webView)
+ , m_drtDevToolsAgent(agent)
+{
+ m_webDevToolsFrontend = adoptPtr(WebDevToolsFrontend::create(m_webView, this, WebString::fromUTF8("en-US")));
+ m_drtDevToolsAgent->attach(this);
+}
+
+DRTDevToolsClient::~DRTDevToolsClient()
+{
+ // There is a chance that the page will be destroyed at detach step of
+ // m_drtDevToolsAgent and we should clean pending requests a bit earlier.
+ m_taskList.revokeAll();
+ if (m_drtDevToolsAgent)
+ m_drtDevToolsAgent->detach();
+}
+
+void DRTDevToolsClient::reset()
+{
+ m_taskList.revokeAll();
+}
+
+void DRTDevToolsClient::sendMessageToBackend(const WebString& data)
+{
+ if (m_drtDevToolsAgent)
+ m_drtDevToolsAgent->asyncCall(data);
+}
+
+void DRTDevToolsClient::activateWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::closeWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::dockWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::undockWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::asyncCall(const WebString& args)
+{
+ postTask(new AsyncCallTask(this, args));
+}
+
+void DRTDevToolsClient::call(const WebString& args)
+{
+ m_webDevToolsFrontend->dispatchOnInspectorFrontend(args);
+}
+
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h
new file mode 100644
index 000000000..97a1edc0b
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h
@@ -0,0 +1,87 @@
+/*
+ * 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 DRTDevToolsClient_h
+#define DRTDevToolsClient_h
+
+#include "Task.h"
+#include "WebDevToolsFrontendClient.h"
+#include "platform/WebString.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+namespace WebKit {
+
+class WebDevToolsFrontend;
+struct WebDevToolsMessageData;
+class WebView;
+
+} // namespace WebKit
+
+class DRTDevToolsAgent;
+
+class DRTDevToolsClient : public WebKit::WebDevToolsFrontendClient {
+ WTF_MAKE_NONCOPYABLE(DRTDevToolsClient);
+public:
+ DRTDevToolsClient(DRTDevToolsAgent*, WebKit::WebView*);
+ virtual ~DRTDevToolsClient();
+ void reset();
+
+ // WebDevToolsFrontendClient implementation
+ virtual void sendMessageToBackend(const WebKit::WebString&);
+
+ virtual void activateWindow();
+ virtual void closeWindow();
+ virtual void dockWindow();
+ virtual void undockWindow();
+
+ void asyncCall(const WebKit::WebString& args);
+
+ void allMessagesProcessed();
+ TaskList* taskList() { return &m_taskList; }
+
+ private:
+ void call(const WebKit::WebString& args);
+ class AsyncCallTask: public MethodTask<DRTDevToolsClient> {
+ public:
+ AsyncCallTask(DRTDevToolsClient* object, const WebKit::WebString& args)
+ : MethodTask<DRTDevToolsClient>(object), m_args(args) { }
+ virtual void runIfValid() { m_object->call(m_args); }
+
+ private:
+ WebKit::WebString m_args;
+ };
+
+ TaskList m_taskList;
+ WebKit::WebView* m_webView;
+ DRTDevToolsAgent* m_drtDevToolsAgent;
+ WTF::OwnPtr<WebKit::WebDevToolsFrontend> m_webDevToolsFrontend;
+};
+
+#endif // DRTDevToolsClient_h
diff --git a/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp b/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp
new file mode 100644
index 000000000..f9f6f5a69
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2011 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 "TestShell.h"
+#include "webkit/support/webkit_support.h"
+#include <v8/include/v8-testing.h>
+#include <v8/include/v8.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+static const char optionComplexText[] = "--complex-text";
+static const char optionDumpAllPixels[] = "--dump-all-pixels";
+static const char optionNotree[] = "--notree";
+static const char optionPixelTests[] = "--pixel-tests";
+static const char optionThreaded[] = "--threaded";
+static const char optionDebugRenderTree[] = "--debug-render-tree";
+static const char optionDebugLayerTree[] = "--debug-layer-tree";
+
+static const char optionPixelTestsWithName[] = "--pixel-tests=";
+static const char optionTestShell[] = "--test-shell";
+static const char optionAllowExternalPages[] = "--allow-external-pages";
+static const char optionStartupDialog[] = "--testshell-startup-dialog";
+static const char optionCheckLayoutTestSystemDeps[] = "--check-layout-test-sys-deps";
+
+static const char optionHardwareAcceleratedGL[] = "--enable-hardware-gpu";
+static const char optionEnableThreadedCompositing[] = "--enable-threaded-compositing";
+static const char optionForceCompositingMode[] = "--force-compositing-mode";
+static const char optionEnableAccelerated2DCanvas[] = "--enable-accelerated-2d-canvas";
+static const char optionEnableLegacyAccelerated2DCanvas[] = "--enable-legacy-accelerated-2d-canvas";
+static const char optionEnableAcceleratedPainting[] = "--enable-accelerated-painting";
+static const char optionEnableAcceleratedCompositingForVideo[] = "--enable-accelerated-video";
+static const char optionEnableCompositeToTexture[] = "--enable-composite-to-texture";
+static const char optionUseGraphicsContext3DImplementation[] = "--use-graphics-context-3d-implementation=";
+static const char optionEnablePerTilePainting[] = "--enable-per-tile-painting";
+
+static const char optionStressOpt[] = "--stress-opt";
+static const char optionStressDeopt[] = "--stress-deopt";
+static const char optionJavaScriptFlags[] = "--js-flags=";
+static const char optionNoTimeout[] = "--no-timeout";
+static const char optionWebCoreLogChannels[] = "--webcore-log-channels=";
+
+class WebKitSupportTestEnvironment {
+public:
+ WebKitSupportTestEnvironment()
+ {
+ webkit_support::SetUpTestEnvironment();
+ }
+ ~WebKitSupportTestEnvironment()
+ {
+ webkit_support::TearDownTestEnvironment();
+ }
+};
+
+static void runTest(TestShell& shell, TestParams& params, const string& testName, bool testShellMode)
+{
+ int oldTimeoutMsec = shell.layoutTestTimeout();
+ params.pixelHash = "";
+ string pathOrURL = testName;
+ if (testShellMode) {
+ string timeOut;
+ string::size_type separatorPosition = pathOrURL.find(' ');
+ if (separatorPosition != string::npos) {
+ timeOut = pathOrURL.substr(separatorPosition + 1);
+ pathOrURL.erase(separatorPosition);
+ separatorPosition = timeOut.find_first_of(' ');
+ if (separatorPosition != string::npos) {
+ params.pixelHash = timeOut.substr(separatorPosition + 1);
+ timeOut.erase(separatorPosition);
+ }
+ shell.setLayoutTestTimeout(atoi(timeOut.c_str()));
+ }
+ } else {
+ string::size_type separatorPosition = pathOrURL.find("'");
+ if (separatorPosition != string::npos) {
+ params.pixelHash = pathOrURL.substr(separatorPosition + 1);
+ pathOrURL.erase(separatorPosition);
+ }
+ }
+ params.testUrl = webkit_support::CreateURLForPathOrURL(pathOrURL);
+ webkit_support::SetCurrentDirectoryForFileURL(params.testUrl);
+ v8::V8::SetFlagsFromString(shell.javaScriptFlags().c_str(), shell.javaScriptFlags().length());
+ if (shell.stressOpt() || shell.stressDeopt()) {
+ if (shell.stressOpt())
+ v8::Testing::SetStressRunType(v8::Testing::kStressTypeOpt);
+ else
+ v8::Testing::SetStressRunType(v8::Testing::kStressTypeDeopt);
+ for (int i = 0; i < v8::Testing::GetStressRuns(); i++) {
+ v8::Testing::PrepareStressRun(i);
+ bool isLastLoad = (i == (v8::Testing::GetStressRuns() - 1));
+ shell.setDumpWhenFinished(isLastLoad);
+ shell.resetTestController();
+ shell.runFileTest(params);
+ }
+ } else {
+ shell.resetTestController();
+ shell.runFileTest(params);
+ }
+ shell.setLayoutTestTimeout(oldTimeoutMsec);
+}
+
+int main(int argc, char* argv[])
+{
+ WebKitSupportTestEnvironment testEnvironment;
+ platformInit(&argc, &argv);
+
+ TestParams params;
+ Vector<string> tests;
+ bool serverMode = false;
+ bool testShellMode = false;
+ bool allowExternalPages = false;
+ bool startupDialog = false;
+ bool acceleratedCompositingForVideoEnabled = false;
+ bool threadedCompositingEnabled = false;
+ bool compositeToTexture = false;
+ bool forceCompositingMode = false;
+ bool accelerated2DCanvasEnabled = false;
+ bool legacyAccelerated2DCanvasEnabled = false;
+ bool acceleratedPaintingEnabled = false;
+ bool perTilePaintingEnabled = false;
+ bool stressOpt = false;
+ bool stressDeopt = false;
+ bool hardwareAcceleratedGL = false;
+ string javaScriptFlags;
+ bool noTimeout = false;
+ for (int i = 1; i < argc; ++i) {
+ string argument(argv[i]);
+ if (argument == "-")
+ serverMode = true;
+ else if (argument == optionNotree)
+ params.dumpTree = false;
+ else if (argument == optionPixelTests)
+ params.dumpPixels = true;
+ else if (!argument.find(optionPixelTestsWithName)) {
+ params.dumpPixels = true;
+ params.pixelFileName = argument.substr(strlen(optionPixelTestsWithName));
+ } else if (argument == optionDebugRenderTree)
+ params.debugRenderTree = true;
+ else if (argument == optionDebugLayerTree)
+ params.debugLayerTree = true;
+ else if (argument == optionTestShell) {
+ testShellMode = true;
+ serverMode = true;
+ } else if (argument == optionAllowExternalPages)
+ allowExternalPages = true;
+ else if (argument == optionStartupDialog)
+ startupDialog = true;
+ else if (argument == optionCheckLayoutTestSystemDeps)
+ return checkLayoutTestSystemDependencies() ? EXIT_SUCCESS : EXIT_FAILURE;
+ else if (argument == optionHardwareAcceleratedGL)
+ hardwareAcceleratedGL = true;
+ else if (argument == optionEnableAcceleratedCompositingForVideo)
+ acceleratedCompositingForVideoEnabled = true;
+ else if (argument == optionEnableThreadedCompositing)
+ threadedCompositingEnabled = true;
+ else if (argument == optionEnableCompositeToTexture)
+ compositeToTexture = true;
+ else if (argument == optionForceCompositingMode)
+ forceCompositingMode = true;
+ else if (argument == optionEnableAccelerated2DCanvas)
+ accelerated2DCanvasEnabled = true;
+ else if (argument == optionEnableLegacyAccelerated2DCanvas)
+ legacyAccelerated2DCanvasEnabled = true;
+ else if (argument == optionEnableAcceleratedPainting)
+ acceleratedPaintingEnabled = true;
+ else if (!argument.find(optionUseGraphicsContext3DImplementation)) {
+ string implementation = argument.substr(strlen(optionUseGraphicsContext3DImplementation));
+ if (!implementation.compare("IN_PROCESS"))
+ webkit_support::SetGraphicsContext3DImplementation(webkit_support::IN_PROCESS);
+ else if (!implementation.compare("IN_PROCESS_COMMAND_BUFFER"))
+ webkit_support::SetGraphicsContext3DImplementation(webkit_support::IN_PROCESS_COMMAND_BUFFER);
+ else
+ fprintf(stderr, "Unknown GraphicContext3D implementation %s\n", implementation.c_str());
+ } else if (argument == optionEnablePerTilePainting)
+ perTilePaintingEnabled = true;
+ else if (argument == optionStressOpt)
+ stressOpt = true;
+ else if (argument == optionStressDeopt)
+ stressDeopt = true;
+ else if (!argument.find(optionJavaScriptFlags))
+ javaScriptFlags = argument.substr(strlen(optionJavaScriptFlags));
+ else if (argument == optionNoTimeout)
+ noTimeout = true;
+ else if (!argument.find(optionWebCoreLogChannels)) {
+ string channels = argument.substr(strlen(optionWebCoreLogChannels));
+ webkit_support::EnableWebCoreLogChannels(channels);
+ } else if (argument.size() && argument[0] == '-')
+ fprintf(stderr, "Unknown option: %s\n", argv[i]);
+ else
+ tests.append(argument);
+ }
+ if (testShellMode && params.dumpPixels && params.pixelFileName.empty()) {
+ fprintf(stderr, "--pixel-tests with --test-shell requires a file name.\n");
+ return EXIT_FAILURE;
+ }
+ if (stressOpt && stressDeopt) {
+ fprintf(stderr, "--stress-opt and --stress-deopt are mutually exclusive.\n");
+ return EXIT_FAILURE;
+ }
+
+ webkit_support::SetUpGLBindings(hardwareAcceleratedGL ? webkit_support::GL_BINDING_DEFAULT : webkit_support::GL_BINDING_SOFTWARE_RENDERER);
+
+ if (startupDialog)
+ openStartupDialog();
+
+ { // Explicit scope for the TestShell instance.
+ TestShell shell(testShellMode);
+ shell.setAllowExternalPages(allowExternalPages);
+ shell.setAcceleratedCompositingForVideoEnabled(acceleratedCompositingForVideoEnabled);
+ shell.setThreadedCompositingEnabled(threadedCompositingEnabled);
+ shell.setCompositeToTexture(compositeToTexture);
+ shell.setForceCompositingMode(forceCompositingMode);
+ shell.setAccelerated2dCanvasEnabled(accelerated2DCanvasEnabled);
+ shell.setLegacyAccelerated2dCanvasEnabled(legacyAccelerated2DCanvasEnabled);
+ shell.setAcceleratedPaintingEnabled(acceleratedPaintingEnabled);
+ shell.setPerTilePaintingEnabled(perTilePaintingEnabled);
+ shell.setJavaScriptFlags(javaScriptFlags);
+ shell.setStressOpt(stressOpt);
+ shell.setStressDeopt(stressDeopt);
+ if (noTimeout) {
+ // 0x20000000ms is big enough for the purpose to avoid timeout in debugging.
+ shell.setLayoutTestTimeout(0x20000000);
+ }
+ if (serverMode && !tests.size()) {
+#if OS(ANDROID)
+ // Send a signal to host to indicate DRT is ready to process commands.
+ puts("#READY");
+ fflush(stdout);
+#endif
+ params.printSeparators = true;
+ char testString[2048]; // 2048 is the same as the sizes of other platforms.
+ while (fgets(testString, sizeof(testString), stdin)) {
+ char* newLinePosition = strchr(testString, '\n');
+ if (newLinePosition)
+ *newLinePosition = '\0';
+ if (testString[0] == '\0')
+ continue;
+ // Explicitly quit on platforms where EOF is not reliable.
+ if (!strcmp(testString, "QUIT"))
+ break;
+ runTest(shell, params, testString, testShellMode);
+ }
+ } else if (!tests.size())
+ puts("#EOF");
+ else {
+ params.printSeparators = tests.size() > 1;
+ for (unsigned i = 0; i < tests.size(); i++)
+ runTest(shell, params, tests[i], testShellMode);
+ }
+
+ shell.callJSGC();
+ shell.callJSGC();
+
+ // When we finish the last test, cleanup the LayoutTestController.
+ // It may have references to not-yet-cleaned up windows. By cleaning up
+ // here we help purify reports.
+ shell.resetTestController();
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/Tools/DumpRenderTree/chromium/EventSender.cpp b/Tools/DumpRenderTree/chromium/EventSender.cpp
new file mode 100644
index 000000000..9acc42dfb
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/EventSender.cpp
@@ -0,0 +1,1130 @@
+/*
+ * 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.
+ */
+
+// This file contains the definition for EventSender.
+//
+// Some notes about drag and drop handling:
+// Windows drag and drop goes through a system call to doDragDrop. At that
+// point, program control is given to Windows which then periodically makes
+// callbacks into the webview. This won't work for layout tests, so instead,
+// we queue up all the mouse move and mouse up events. When the test tries to
+// start a drag (by calling EvenSendingController::doDragDrop), we take the
+// events in the queue and replay them.
+// The behavior of queuing events and replaying them can be disabled by a
+// layout test by setting eventSender.dragMode to false.
+
+#include "config.h"
+#include "EventSender.h"
+
+#include "TestShell.h"
+#include "WebContextMenuData.h"
+#include "platform/WebDragData.h"
+#include "WebDragOperation.h"
+#include "platform/WebPoint.h"
+#include "platform/WebString.h"
+#include "WebTouchPoint.h"
+#include "WebView.h"
+#include "webkit/support/webkit_support.h"
+#include <wtf/Deque.h>
+#include <wtf/StringExtras.h>
+
+#if OS(WINDOWS)
+#include "win/WebInputEventFactory.h"
+#endif
+
+// FIXME: layout before each event?
+
+using namespace std;
+using namespace WebKit;
+
+WebPoint EventSender::lastMousePos;
+WebMouseEvent::Button EventSender::pressedButton = WebMouseEvent::ButtonNone;
+WebMouseEvent::Button EventSender::lastButtonType = WebMouseEvent::ButtonNone;
+
+struct SavedEvent {
+ enum SavedEventType {
+ Unspecified,
+ MouseUp,
+ MouseMove,
+ LeapForward
+ };
+
+ SavedEventType type;
+ WebMouseEvent::Button buttonType; // For MouseUp.
+ WebPoint pos; // For MouseMove.
+ int milliseconds; // For LeapForward.
+
+ SavedEvent()
+ : type(Unspecified)
+ , buttonType(WebMouseEvent::ButtonNone)
+ , milliseconds(0) { }
+};
+
+static WebDragData currentDragData;
+static WebDragOperation currentDragEffect;
+static WebDragOperationsMask currentDragEffectsAllowed;
+static bool replayingSavedEvents = false;
+static Deque<SavedEvent> mouseEventQueue;
+static int touchModifiers;
+static Vector<WebTouchPoint> touchPoints;
+
+// Time and place of the last mouse up event.
+static double lastClickTimeSec = 0;
+static WebPoint lastClickPos;
+static int clickCount = 0;
+
+// maximum distance (in space and time) for a mouse click
+// to register as a double or triple click
+static const double multipleClickTimeSec = 1;
+static const int multipleClickRadiusPixels = 5;
+
+// How much we should scroll per event - the value here is chosen to
+// match the WebKit impl and layout test results.
+static const float scrollbarPixelsPerTick = 40.0f;
+
+inline bool outsideMultiClickRadius(const WebPoint& a, const WebPoint& b)
+{
+ return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
+ multipleClickRadiusPixels * multipleClickRadiusPixels;
+}
+
+// Used to offset the time the event hander things an event happened. This is
+// done so tests can run without a delay, but bypass checks that are time
+// dependent (e.g., dragging has a timeout vs selection).
+static uint32 timeOffsetMs = 0;
+
+static double getCurrentEventTimeSec()
+{
+ return (webkit_support::GetCurrentTimeInMillisecond() + timeOffsetMs) / 1000.0;
+}
+
+static void advanceEventTime(int32_t deltaMs)
+{
+ timeOffsetMs += deltaMs;
+}
+
+static void initMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b,
+ const WebPoint& pos, WebMouseEvent* e)
+{
+ e->type = t;
+ e->button = b;
+ e->modifiers = 0;
+ e->x = pos.x;
+ e->y = pos.y;
+ e->globalX = pos.x;
+ e->globalY = pos.y;
+ e->timeStampSeconds = getCurrentEventTimeSec();
+ e->clickCount = clickCount;
+}
+
+// Returns true if the specified key is the system key.
+static bool applyKeyModifier(const string& modifierName, WebInputEvent* event)
+{
+ bool isSystemKey = false;
+ const char* characters = modifierName.c_str();
+ if (!strcmp(characters, "ctrlKey")
+#if !OS(MAC_OS_X)
+ || !strcmp(characters, "addSelectionKey")
+#endif
+ ) {
+ event->modifiers |= WebInputEvent::ControlKey;
+ } else if (!strcmp(characters, "shiftKey") || !strcmp(characters, "rangeSelectionKey"))
+ event->modifiers |= WebInputEvent::ShiftKey;
+ else if (!strcmp(characters, "altKey")) {
+ event->modifiers |= WebInputEvent::AltKey;
+#if !OS(MAC_OS_X)
+ // On Windows all keys with Alt modifier will be marked as system key.
+ // We keep the same behavior on Linux and everywhere non-Mac, see:
+ // WebKit/chromium/src/gtk/WebInputEventFactory.cpp
+ // If we want to change this behavior on Linux, this piece of code must be
+ // kept in sync with the related code in above file.
+ isSystemKey = true;
+#endif
+#if OS(MAC_OS_X)
+ } else if (!strcmp(characters, "metaKey") || !strcmp(characters, "addSelectionKey")) {
+ event->modifiers |= WebInputEvent::MetaKey;
+ // On Mac only command key presses are marked as system key.
+ // See the related code in: WebKit/chromium/src/mac/WebInputEventFactory.cpp
+ // It must be kept in sync with the related code in above file.
+ isSystemKey = true;
+#else
+ } else if (!strcmp(characters, "metaKey")) {
+ event->modifiers |= WebInputEvent::MetaKey;
+#endif
+ }
+ return isSystemKey;
+}
+
+static bool applyKeyModifiers(const CppVariant* argument, WebInputEvent* event)
+{
+ bool isSystemKey = false;
+ if (argument->isObject()) {
+ Vector<string> modifiers = argument->toStringVector();
+ for (Vector<string>::const_iterator i = modifiers.begin(); i != modifiers.end(); ++i)
+ isSystemKey |= applyKeyModifier(*i, event);
+ } else if (argument->isString())
+ isSystemKey = applyKeyModifier(argument->toString(), event);
+ return isSystemKey;
+}
+
+// Get the edit command corresponding to a keyboard event.
+// Returns true if the specified event corresponds to an edit command, the name
+// of the edit command will be stored in |*name|.
+bool getEditCommand(const WebKeyboardEvent& event, string* name)
+{
+#if OS(MAC_OS_X)
+ // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
+ // modifiers. These key events correspond to some special movement and
+ // selection editor commands, and was supposed to be handled in
+ // WebKit/chromium/src/EditorClientImpl.cpp. But these keys will be marked
+ // as system key, which prevents them from being handled. Thus they must be
+ // handled specially.
+ if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) != WebKeyboardEvent::MetaKey)
+ return false;
+
+ switch (event.windowsKeyCode) {
+ case webkit_support::VKEY_LEFT:
+ *name = "MoveToBeginningOfLine";
+ break;
+ case webkit_support::VKEY_RIGHT:
+ *name = "MoveToEndOfLine";
+ break;
+ case webkit_support::VKEY_UP:
+ *name = "MoveToBeginningOfDocument";
+ break;
+ case webkit_support::VKEY_DOWN:
+ *name = "MoveToEndOfDocument";
+ break;
+ default:
+ return false;
+ }
+
+ if (event.modifiers & WebKeyboardEvent::ShiftKey)
+ name->append("AndModifySelection");
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+// Key event location code introduced in DOM Level 3.
+// See also: http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents
+enum KeyLocationCode {
+ DOMKeyLocationStandard = 0x00,
+ DOMKeyLocationLeft = 0x01,
+ DOMKeyLocationRight = 0x02,
+ DOMKeyLocationNumpad = 0x03
+};
+
+EventSender::EventSender(TestShell* shell)
+ : m_shell(shell)
+{
+ // Initialize the map that associates methods of this class with the names
+ // they will use when called by JavaScript. The actual binding of those
+ // names to their methods will be done by calling bindToJavaScript() (defined
+ // by CppBoundClass, the parent to EventSender).
+ bindMethod("addTouchPoint", &EventSender::addTouchPoint);
+ bindMethod("beginDragWithFiles", &EventSender::beginDragWithFiles);
+ bindMethod("cancelTouchPoint", &EventSender::cancelTouchPoint);
+ bindMethod("clearKillRing", &EventSender::clearKillRing);
+ bindMethod("clearTouchPoints", &EventSender::clearTouchPoints);
+ bindMethod("contextClick", &EventSender::contextClick);
+ bindMethod("continuousMouseScrollBy", &EventSender::continuousMouseScrollBy);
+ bindMethod("dispatchMessage", &EventSender::dispatchMessage);
+ bindMethod("dumpFilenameBeingDragged", &EventSender::dumpFilenameBeingDragged);
+ bindMethod("enableDOMUIEventLogging", &EventSender::enableDOMUIEventLogging);
+ bindMethod("fireKeyboardEventsToElement", &EventSender::fireKeyboardEventsToElement);
+ bindMethod("keyDown", &EventSender::keyDown);
+ bindMethod("leapForward", &EventSender::leapForward);
+ bindMethod("mouseDown", &EventSender::mouseDown);
+ bindMethod("mouseMoveTo", &EventSender::mouseMoveTo);
+ bindMethod("mouseScrollBy", &EventSender::mouseScrollBy);
+ bindMethod("mouseUp", &EventSender::mouseUp);
+ bindMethod("releaseTouchPoint", &EventSender::releaseTouchPoint);
+ bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick);
+ bindMethod("scheduleAsynchronousKeyDown", &EventSender::scheduleAsynchronousKeyDown);
+ bindMethod("setTouchModifier", &EventSender::setTouchModifier);
+ bindMethod("textZoomIn", &EventSender::textZoomIn);
+ bindMethod("textZoomOut", &EventSender::textZoomOut);
+ bindMethod("touchCancel", &EventSender::touchCancel);
+ bindMethod("touchEnd", &EventSender::touchEnd);
+ bindMethod("touchMove", &EventSender::touchMove);
+ bindMethod("touchStart", &EventSender::touchStart);
+ bindMethod("updateTouchPoint", &EventSender::updateTouchPoint);
+ bindMethod("gestureScrollBegin", &EventSender::gestureScrollBegin);
+ bindMethod("gestureScrollEnd", &EventSender::gestureScrollEnd);
+ bindMethod("gestureScrollUpdate", &EventSender::gestureScrollUpdate);
+ bindMethod("gestureTap", &EventSender::gestureTap);
+ bindMethod("zoomPageIn", &EventSender::zoomPageIn);
+ bindMethod("zoomPageOut", &EventSender::zoomPageOut);
+ bindMethod("scalePageBy", &EventSender::scalePageBy);
+
+ // When set to true (the default value), we batch mouse move and mouse up
+ // events so we can simulate drag & drop.
+ bindProperty("dragMode", &dragMode);
+#if OS(WINDOWS)
+ bindProperty("WM_KEYDOWN", &wmKeyDown);
+ bindProperty("WM_KEYUP", &wmKeyUp);
+ bindProperty("WM_CHAR", &wmChar);
+ bindProperty("WM_DEADCHAR", &wmDeadChar);
+ bindProperty("WM_SYSKEYDOWN", &wmSysKeyDown);
+ bindProperty("WM_SYSKEYUP", &wmSysKeyUp);
+ bindProperty("WM_SYSCHAR", &wmSysChar);
+ bindProperty("WM_SYSDEADCHAR", &wmSysDeadChar);
+#endif
+}
+
+void EventSender::reset()
+{
+ // The test should have finished a drag and the mouse button state.
+ ASSERT(currentDragData.isNull());
+ currentDragData.reset();
+ currentDragEffect = WebKit::WebDragOperationNone;
+ currentDragEffectsAllowed = WebKit::WebDragOperationNone;
+ pressedButton = WebMouseEvent::ButtonNone;
+ dragMode.set(true);
+#if OS(WINDOWS)
+ wmKeyDown.set(WM_KEYDOWN);
+ wmKeyUp.set(WM_KEYUP);
+ wmChar.set(WM_CHAR);
+ wmDeadChar.set(WM_DEADCHAR);
+ wmSysKeyDown.set(WM_SYSKEYDOWN);
+ wmSysKeyUp.set(WM_SYSKEYUP);
+ wmSysChar.set(WM_SYSCHAR);
+ wmSysDeadChar.set(WM_SYSDEADCHAR);
+#endif
+ lastMousePos = WebPoint(0, 0);
+ lastClickTimeSec = 0;
+ lastClickPos = WebPoint(0, 0);
+ clickCount = 0;
+ lastButtonType = WebMouseEvent::ButtonNone;
+ timeOffsetMs = 0;
+ touchModifiers = 0;
+ touchPoints.clear();
+ m_taskList.revokeAll();
+ m_gestureStartLocation = WebPoint(0, 0);
+}
+
+WebView* EventSender::webview()
+{
+ return m_shell->webView();
+}
+
+void EventSender::doDragDrop(const WebDragData& dragData, WebDragOperationsMask mask)
+{
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event);
+ WebPoint clientPoint(event.x, event.y);
+ WebPoint screenPoint(event.globalX, event.globalY);
+ currentDragData = dragData;
+ currentDragEffectsAllowed = mask;
+ currentDragEffect = webview()->dragTargetDragEnter(dragData, clientPoint, screenPoint, currentDragEffectsAllowed);
+
+ // Finish processing events.
+ replaySavedEvents();
+}
+
+void EventSender::dumpFilenameBeingDragged(const CppArgumentList&, CppVariant*)
+{
+ printf("Filename being dragged: %s\n", currentDragData.fileContentFilename().utf8().data());
+}
+
+WebMouseEvent::Button EventSender::getButtonTypeFromButtonNumber(int buttonCode)
+{
+ if (!buttonCode)
+ return WebMouseEvent::ButtonLeft;
+ if (buttonCode == 2)
+ return WebMouseEvent::ButtonRight;
+ return WebMouseEvent::ButtonMiddle;
+}
+
+int EventSender::getButtonNumberFromSingleArg(const CppArgumentList& arguments)
+{
+ int buttonCode = 0;
+ if (arguments.size() > 0 && arguments[0].isNumber())
+ buttonCode = arguments[0].toInt32();
+ return buttonCode;
+}
+
+void EventSender::updateClickCountForButton(WebMouseEvent::Button buttonType)
+{
+ if ((getCurrentEventTimeSec() - lastClickTimeSec < multipleClickTimeSec)
+ && (!outsideMultiClickRadius(lastMousePos, lastClickPos))
+ && (buttonType == lastButtonType))
+ ++clickCount;
+ else {
+ clickCount = 1;
+ lastButtonType = buttonType;
+ }
+}
+
+//
+// Implemented javascript methods.
+//
+
+void EventSender::mouseDown(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (result) // Could be 0 if invoked asynchronously.
+ result->setNull();
+
+ webview()->layout();
+
+ int buttonNumber = getButtonNumberFromSingleArg(arguments);
+ ASSERT(buttonNumber != -1);
+
+ WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
+
+ updateClickCountForButton(buttonType);
+
+ WebMouseEvent event;
+ pressedButton = buttonType;
+ initMouseEvent(WebInputEvent::MouseDown, buttonType, lastMousePos, &event);
+ if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
+ applyKeyModifiers(&(arguments[1]), &event);
+ webview()->handleInputEvent(event);
+}
+
+void EventSender::mouseUp(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (result) // Could be 0 if invoked asynchronously.
+ result->setNull();
+
+ webview()->layout();
+
+ int buttonNumber = getButtonNumberFromSingleArg(arguments);
+ ASSERT(buttonNumber != -1);
+
+ WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
+
+ if (isDragMode() && !replayingSavedEvents) {
+ SavedEvent savedEvent;
+ savedEvent.type = SavedEvent::MouseUp;
+ savedEvent.buttonType = buttonType;
+ mouseEventQueue.append(savedEvent);
+ replaySavedEvents();
+ } else {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseUp, buttonType, lastMousePos, &event);
+ if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
+ applyKeyModifiers(&(arguments[1]), &event);
+ doMouseUp(event);
+ }
+}
+
+void EventSender::doMouseUp(const WebMouseEvent& e)
+{
+ webview()->handleInputEvent(e);
+
+ pressedButton = WebMouseEvent::ButtonNone;
+ lastClickTimeSec = e.timeStampSeconds;
+ lastClickPos = lastMousePos;
+
+ // If we're in a drag operation, complete it.
+ if (currentDragData.isNull())
+ return;
+ WebPoint clientPoint(e.x, e.y);
+ WebPoint screenPoint(e.globalX, e.globalY);
+
+ currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed);
+ if (currentDragEffect)
+ webview()->dragTargetDrop(clientPoint, screenPoint);
+ else
+ webview()->dragTargetDragLeave();
+ webview()->dragSourceEndedAt(clientPoint, screenPoint, currentDragEffect);
+ webview()->dragSourceSystemDragEnded();
+
+ currentDragData.reset();
+}
+
+void EventSender::mouseMoveTo(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+ webview()->layout();
+
+ WebPoint mousePos(arguments[0].toInt32(), arguments[1].toInt32());
+
+ if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
+ SavedEvent savedEvent;
+ savedEvent.type = SavedEvent::MouseMove;
+ savedEvent.pos = mousePos;
+ mouseEventQueue.append(savedEvent);
+ } else {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseMove, pressedButton, mousePos, &event);
+ doMouseMove(event);
+ }
+}
+
+void EventSender::doMouseMove(const WebMouseEvent& e)
+{
+ lastMousePos = WebPoint(e.x, e.y);
+
+ webview()->handleInputEvent(e);
+
+ if (pressedButton == WebMouseEvent::ButtonNone || currentDragData.isNull())
+ return;
+ WebPoint clientPoint(e.x, e.y);
+ WebPoint screenPoint(e.globalX, e.globalY);
+ currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed);
+}
+
+void EventSender::keyDown(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (result)
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+ bool generateChar = false;
+
+ // FIXME: I'm not exactly sure how we should convert the string to a key
+ // event. This seems to work in the cases I tested.
+ // FIXME: Should we also generate a KEY_UP?
+ string codeStr = arguments[0].toString();
+
+ // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
+ // Windows uses \r for "Enter".
+ int code = 0;
+ int text = 0;
+ bool needsShiftKeyModifier = false;
+ if ("\n" == codeStr) {
+ generateChar = true;
+ text = code = webkit_support::VKEY_RETURN;
+ } else if ("rightArrow" == codeStr)
+ code = webkit_support::VKEY_RIGHT;
+ else if ("downArrow" == codeStr)
+ code = webkit_support::VKEY_DOWN;
+ else if ("leftArrow" == codeStr)
+ code = webkit_support::VKEY_LEFT;
+ else if ("upArrow" == codeStr)
+ code = webkit_support::VKEY_UP;
+ else if ("insert" == codeStr)
+ code = webkit_support::VKEY_INSERT;
+ else if ("delete" == codeStr)
+ code = webkit_support::VKEY_DELETE;
+ else if ("pageUp" == codeStr)
+ code = webkit_support::VKEY_PRIOR;
+ else if ("pageDown" == codeStr)
+ code = webkit_support::VKEY_NEXT;
+ else if ("home" == codeStr)
+ code = webkit_support::VKEY_HOME;
+ else if ("end" == codeStr)
+ code = webkit_support::VKEY_END;
+ else if ("printScreen" == codeStr)
+ code = webkit_support::VKEY_SNAPSHOT;
+ else if ("menu" == codeStr)
+ // FIXME: Change this to webkit_support::VKEY_APPS.
+ code = 0x5D;
+ else {
+ // Compare the input string with the function-key names defined by the
+ // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
+ // name, set its key code.
+ for (int i = 1; i <= 24; ++i) {
+ char functionChars[10];
+ snprintf(functionChars, 10, "F%d", i);
+ string functionKeyName(functionChars);
+ if (functionKeyName == codeStr) {
+ code = webkit_support::VKEY_F1 + (i - 1);
+ break;
+ }
+ }
+ if (!code) {
+ WebString webCodeStr = WebString::fromUTF8(codeStr.data(), codeStr.size());
+ ASSERT(webCodeStr.length() == 1);
+ text = code = webCodeStr.data()[0];
+ needsShiftKeyModifier = needsShiftModifier(code);
+ if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
+ code -= 'a' - 'A';
+ generateChar = true;
+ }
+ }
+
+ // For one generated keyboard event, we need to generate a keyDown/keyUp
+ // pair; refer to EventSender.cpp in Tools/DumpRenderTree/win.
+ // On Windows, we might also need to generate a char event to mimic the
+ // Windows event flow; on other platforms we create a merged event and test
+ // the event flow that that platform provides.
+ WebKeyboardEvent eventDown, eventChar, eventUp;
+ eventDown.type = WebInputEvent::RawKeyDown;
+ eventDown.modifiers = 0;
+ eventDown.windowsKeyCode = code;
+#if OS(LINUX) && USE(GTK)
+ eventDown.nativeKeyCode = webkit_support::NativeKeyCodeForWindowsKeyCode(code, needsShiftKeyModifier);
+#endif
+
+ if (generateChar) {
+ eventDown.text[0] = text;
+ eventDown.unmodifiedText[0] = text;
+ }
+ eventDown.setKeyIdentifierFromWindowsKeyCode();
+
+ if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
+ eventDown.isSystemKey = applyKeyModifiers(&(arguments[1]), &eventDown);
+
+ if (needsShiftKeyModifier)
+ eventDown.modifiers |= WebInputEvent::ShiftKey;
+
+ // See if KeyLocation argument is given.
+ if (arguments.size() >= 3 && arguments[2].isNumber()) {
+ int location = arguments[2].toInt32();
+ if (location == DOMKeyLocationNumpad)
+ eventDown.modifiers |= WebInputEvent::IsKeyPad;
+ }
+
+ eventChar = eventUp = eventDown;
+ eventUp.type = WebInputEvent::KeyUp;
+ // EventSender.m forces a layout here, with at least one
+ // test (fast/forms/focus-control-to-page.html) relying on this.
+ webview()->layout();
+
+ // In the browser, if a keyboard event corresponds to an editor command,
+ // the command will be dispatched to the renderer just before dispatching
+ // the keyboard event, and then it will be executed in the
+ // RenderView::handleCurrentKeyboardEvent() method, which is called from
+ // third_party/WebKit/Source/WebKit/chromium/src/EditorClientImpl.cpp.
+ // We just simulate the same behavior here.
+ string editCommand;
+ if (getEditCommand(eventDown, &editCommand))
+ m_shell->webViewHost()->setEditCommand(editCommand, "");
+
+ webview()->handleInputEvent(eventDown);
+
+ m_shell->webViewHost()->clearEditCommand();
+
+ if (generateChar) {
+ eventChar.type = WebInputEvent::Char;
+ eventChar.keyIdentifier[0] = '\0';
+ webview()->handleInputEvent(eventChar);
+ }
+
+ webview()->handleInputEvent(eventUp);
+}
+
+void EventSender::dispatchMessage(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+#if OS(WINDOWS)
+ if (arguments.size() == 3) {
+ // Grab the message id to see if we need to dispatch it.
+ int msg = arguments[0].toInt32();
+
+ // WebKit's version of this function stuffs a MSG struct and uses
+ // TranslateMessage and DispatchMessage. We use a WebKeyboardEvent, which
+ // doesn't need to receive the DeadChar and SysDeadChar messages.
+ if (msg == WM_DEADCHAR || msg == WM_SYSDEADCHAR)
+ return;
+
+ webview()->layout();
+
+ unsigned long lparam = static_cast<unsigned long>(arguments[2].toDouble());
+ webview()->handleInputEvent(WebInputEventFactory::keyboardEvent(0, msg, arguments[1].toInt32(), lparam));
+ } else
+ ASSERT_NOT_REACHED();
+#endif
+}
+
+bool EventSender::needsShiftModifier(int keyCode)
+{
+ // If code is an uppercase letter, assign a SHIFT key to
+ // eventDown.modifier, this logic comes from
+ // Tools/DumpRenderTree/win/EventSender.cpp
+ return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
+}
+
+void EventSender::leapForward(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isNumber())
+ return;
+
+ int milliseconds = arguments[0].toInt32();
+ if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
+ SavedEvent savedEvent;
+ savedEvent.type = SavedEvent::LeapForward;
+ savedEvent.milliseconds = milliseconds;
+ mouseEventQueue.append(savedEvent);
+ } else
+ doLeapForward(milliseconds);
+}
+
+void EventSender::doLeapForward(int milliseconds)
+{
+ advanceEventTime(milliseconds);
+}
+
+// Apple's port of WebKit zooms by a factor of 1.2 (see
+// WebKit/WebView/WebView.mm)
+void EventSender::textZoomIn(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(true, webview()->zoomLevel() + 1);
+ result->setNull();
+}
+
+void EventSender::textZoomOut(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(true, webview()->zoomLevel() - 1);
+ result->setNull();
+}
+
+void EventSender::zoomPageIn(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(false, webview()->zoomLevel() + 1);
+ result->setNull();
+}
+
+void EventSender::zoomPageOut(const CppArgumentList&, CppVariant* result)
+{
+ webview()->setZoomLevel(false, webview()->zoomLevel() - 1);
+ result->setNull();
+}
+
+void EventSender::scalePageBy(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber())
+ return;
+
+ float scaleFactor = static_cast<float>(arguments[0].toDouble());
+ int x = arguments[1].toInt32();
+ int y = arguments[2].toInt32();
+ webview()->setPageScaleFactor(scaleFactor, WebPoint(x, y));
+ result->setNull();
+}
+
+void EventSender::mouseScrollBy(const CppArgumentList& arguments, CppVariant* result)
+{
+ handleMouseWheel(arguments, result, false);
+}
+
+void EventSender::continuousMouseScrollBy(const CppArgumentList& arguments, CppVariant* result)
+{
+ handleMouseWheel(arguments, result, true);
+}
+
+void EventSender::replaySavedEvents()
+{
+ replayingSavedEvents = true;
+ while (!mouseEventQueue.isEmpty()) {
+ SavedEvent e = mouseEventQueue.takeFirst();
+
+ switch (e.type) {
+ case SavedEvent::MouseMove: {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseMove, pressedButton, e.pos, &event);
+ doMouseMove(event);
+ break;
+ }
+ case SavedEvent::LeapForward:
+ doLeapForward(e.milliseconds);
+ break;
+ case SavedEvent::MouseUp: {
+ WebMouseEvent event;
+ initMouseEvent(WebInputEvent::MouseUp, e.buttonType, lastMousePos, &event);
+ doMouseUp(event);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ replayingSavedEvents = false;
+}
+
+// Because actual context menu is implemented by the browser side,
+// this function does only what LayoutTests are expecting:
+// - Many test checks the count of items. So returning non-zero value makes sense.
+// - Some test compares the count before and after some action. So changing the count based on flags
+// also makes sense. This function is doing such for some flags.
+// - Some test even checks actual string content. So providing it would be also helpful.
+//
+static Vector<WebString> makeMenuItemStringsFor(WebContextMenuData* contextMenu, MockSpellCheck* spellcheck)
+{
+ // These constants are based on Safari's context menu because tests are made for it.
+ static const char* nonEditableMenuStrings[] = { "Back", "Reload Page", "Open in Dashbaord", "<separator>", "View Source", "Save Page As", "Print Page", "Inspect Element", 0 };
+ static const char* editableMenuStrings[] = { "Cut", "Copy", "<separator>", "Paste", "Spelling and Grammar", "Substitutions, Transformations", "Font", "Speech", "Paragraph Direction", "<separator>", 0 };
+
+ // This is possible because mouse events are cancelleable.
+ if (!contextMenu)
+ return Vector<WebString>();
+
+ Vector<WebString> strings;
+
+ if (contextMenu->isEditable) {
+ for (const char** item = editableMenuStrings; *item; ++item)
+ strings.append(WebString::fromUTF8(*item));
+ Vector<WebString> suggestions;
+ spellcheck->fillSuggestionList(contextMenu->misspelledWord, &suggestions);
+ for (size_t i = 0; i < suggestions.size(); ++i)
+ strings.append(suggestions[i]);
+ } else {
+ for (const char** item = nonEditableMenuStrings; *item; ++item)
+ strings.append(WebString::fromUTF8(*item));
+ }
+
+ return strings;
+}
+
+
+void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ webview()->layout();
+
+ updateClickCountForButton(WebMouseEvent::ButtonRight);
+
+ // Clears last context menu data because we need to know if the context menu be requested
+ // after following mouse events.
+ m_shell->webViewHost()->clearContextMenuData();
+
+ // Generate right mouse down and up.
+ WebMouseEvent event;
+ pressedButton = WebMouseEvent::ButtonRight;
+ initMouseEvent(WebInputEvent::MouseDown, WebMouseEvent::ButtonRight, lastMousePos, &event);
+ webview()->handleInputEvent(event);
+
+ initMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight, lastMousePos, &event);
+ webview()->handleInputEvent(event);
+
+ pressedButton = WebMouseEvent::ButtonNone;
+
+ WebContextMenuData* lastContextMenu = m_shell->webViewHost()->lastContextMenuData();
+ result->set(WebBindings::makeStringArray(makeMenuItemStringsFor(lastContextMenu, m_shell->webViewHost()->mockSpellCheck())));
+}
+
+class MouseDownTask: public MethodTask<EventSender> {
+public:
+ MouseDownTask(EventSender* obj, const CppArgumentList& arg)
+ : MethodTask<EventSender>(obj), m_arguments(arg) { }
+ virtual void runIfValid() { m_object->mouseDown(m_arguments, 0); }
+
+private:
+ CppArgumentList m_arguments;
+};
+
+class MouseUpTask: public MethodTask<EventSender> {
+public:
+ MouseUpTask(EventSender* obj, const CppArgumentList& arg)
+ : MethodTask<EventSender>(obj), m_arguments(arg) { }
+ virtual void runIfValid() { m_object->mouseUp(m_arguments, 0); }
+
+private:
+ CppArgumentList m_arguments;
+};
+
+void EventSender::scheduleAsynchronousClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ postTask(new MouseDownTask(this, arguments));
+ postTask(new MouseUpTask(this, arguments));
+}
+
+class KeyDownTask : public MethodTask<EventSender> {
+public:
+ KeyDownTask(EventSender* obj, const CppArgumentList& arg)
+ : MethodTask<EventSender>(obj), m_arguments(arg) { }
+ virtual void runIfValid() { m_object->keyDown(m_arguments, 0); }
+
+private:
+ CppArgumentList m_arguments;
+};
+
+void EventSender::scheduleAsynchronousKeyDown(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ postTask(new KeyDownTask(this, arguments));
+}
+
+void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result)
+{
+ currentDragData.initialize();
+ Vector<string> files = arguments[0].toStringVector();
+ for (size_t i = 0; i < files.size(); ++i)
+ currentDragData.appendToFilenames(webkit_support::GetAbsoluteWebStringFromUTF8Path(files[i]));
+ currentDragEffectsAllowed = WebKit::WebDragOperationCopy;
+
+ // Provide a drag source.
+ webview()->dragTargetDragEnter(currentDragData, lastMousePos, lastMousePos, currentDragEffectsAllowed);
+
+ // dragMode saves events and then replays them later. We don't need/want that.
+ dragMode.set(false);
+
+ // Make the rest of eventSender think a drag is in progress.
+ pressedButton = WebMouseEvent::ButtonLeft;
+
+ result->setNull();
+}
+
+void EventSender::addTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebTouchPoint touchPoint;
+ touchPoint.state = WebTouchPoint::StatePressed;
+ touchPoint.position = WebPoint(arguments[0].toInt32(), arguments[1].toInt32());
+ touchPoint.screenPosition = touchPoint.position;
+
+ int lowestId = 0;
+ for (size_t i = 0; i < touchPoints.size(); i++) {
+ if (touchPoints[i].id == lowestId)
+ lowestId++;
+ }
+ touchPoint.id = lowestId;
+ touchPoints.append(touchPoint);
+}
+
+void EventSender::clearTouchPoints(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ touchPoints.clear();
+}
+
+void EventSender::releaseTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ const unsigned index = arguments[0].toInt32();
+ ASSERT(index < touchPoints.size());
+
+ WebTouchPoint* touchPoint = &touchPoints[index];
+ touchPoint->state = WebTouchPoint::StateReleased;
+}
+
+void EventSender::setTouchModifier(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ int mask = 0;
+ const string keyName = arguments[0].toString();
+ if (keyName == "shift")
+ mask = WebInputEvent::ShiftKey;
+ else if (keyName == "alt")
+ mask = WebInputEvent::AltKey;
+ else if (keyName == "ctrl")
+ mask = WebInputEvent::ControlKey;
+ else if (keyName == "meta")
+ mask = WebInputEvent::MetaKey;
+
+ if (arguments[1].toBoolean())
+ touchModifiers |= mask;
+ else
+ touchModifiers &= ~mask;
+}
+
+void EventSender::updateTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ const unsigned index = arguments[0].toInt32();
+ ASSERT(index < touchPoints.size());
+
+ WebPoint position(arguments[1].toInt32(), arguments[2].toInt32());
+ WebTouchPoint* touchPoint = &touchPoints[index];
+ touchPoint->state = WebTouchPoint::StateMoved;
+ touchPoint->position = position;
+ touchPoint->screenPosition = position;
+}
+
+void EventSender::cancelTouchPoint(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ const unsigned index = arguments[0].toInt32();
+ ASSERT(index < touchPoints.size());
+
+ WebTouchPoint* touchPoint = &touchPoints[index];
+ touchPoint->state = WebTouchPoint::StateCancelled;
+}
+
+void EventSender::sendCurrentTouchEvent(const WebInputEvent::Type type)
+{
+ ASSERT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap) > touchPoints.size());
+ webview()->layout();
+
+ WebTouchEvent touchEvent;
+ touchEvent.type = type;
+ touchEvent.modifiers = touchModifiers;
+ touchEvent.timeStampSeconds = getCurrentEventTimeSec();
+ touchEvent.touchesLength = touchPoints.size();
+ for (unsigned i = 0; i < touchPoints.size(); ++i)
+ touchEvent.touches[i] = touchPoints[i];
+ webview()->handleInputEvent(touchEvent);
+
+ for (unsigned i = 0; i < touchPoints.size(); ++i) {
+ WebTouchPoint* touchPoint = &touchPoints[i];
+ if (touchPoint->state == WebTouchPoint::StateReleased) {
+ touchPoints.remove(i);
+ --i;
+ } else
+ touchPoint->state = WebTouchPoint::StateStationary;
+ }
+}
+
+void EventSender::handleMouseWheel(const CppArgumentList& arguments, CppVariant* result, bool continuous)
+{
+ result->setNull();
+
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ // Force a layout here just to make sure every position has been
+ // determined before we send events (as well as all the other methods
+ // that send an event do).
+ webview()->layout();
+
+ int horizontal = arguments[0].toInt32();
+ int vertical = arguments[1].toInt32();
+ int paged = false;
+
+ if (arguments.size() > 2 && arguments[2].isBool())
+ paged = arguments[2].toBoolean();
+
+ WebMouseWheelEvent event;
+ initMouseEvent(WebInputEvent::MouseWheel, pressedButton, lastMousePos, &event);
+ event.wheelTicksX = static_cast<float>(horizontal);
+ event.wheelTicksY = static_cast<float>(vertical);
+ event.deltaX = event.wheelTicksX;
+ event.deltaY = event.wheelTicksY;
+ event.scrollByPage = paged;
+ if (continuous) {
+ event.wheelTicksX /= scrollbarPixelsPerTick;
+ event.wheelTicksY /= scrollbarPixelsPerTick;
+ } else {
+ event.deltaX *= scrollbarPixelsPerTick;
+ event.deltaY *= scrollbarPixelsPerTick;
+ }
+ webview()->handleInputEvent(event);
+}
+
+void EventSender::touchEnd(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ sendCurrentTouchEvent(WebInputEvent::TouchEnd);
+}
+
+void EventSender::touchMove(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ sendCurrentTouchEvent(WebInputEvent::TouchMove);
+}
+
+void EventSender::touchStart(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ sendCurrentTouchEvent(WebInputEvent::TouchStart);
+}
+
+void EventSender::touchCancel(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ sendCurrentTouchEvent(WebInputEvent::TouchCancel);
+}
+
+void EventSender::gestureScrollBegin(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ gestureEvent(WebInputEvent::GestureScrollBegin, arguments);
+}
+
+void EventSender::gestureScrollEnd(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ gestureEvent(WebInputEvent::GestureScrollEnd, arguments);
+}
+
+void EventSender::gestureScrollUpdate(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ gestureEvent(WebInputEvent::GestureScrollUpdate, arguments);
+}
+
+void EventSender::gestureTap(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ gestureEvent(WebInputEvent::GestureTap, arguments);
+}
+
+void EventSender::gestureEvent(WebInputEvent::Type type, const CppArgumentList& arguments)
+{
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ WebPoint point(arguments[0].toInt32(), arguments[1].toInt32());
+
+ WebGestureEvent event;
+ event.type = type;
+
+ switch (type) {
+ case WebInputEvent::GestureScrollUpdate:
+ event.deltaX = static_cast<float>(arguments[0].toDouble());
+ event.deltaY = static_cast<float>(arguments[1].toDouble());
+ event.x = m_gestureStartLocation.x + event.deltaX;
+ event.y = m_gestureStartLocation.y + event.deltaY;
+ break;
+
+ case WebInputEvent::GestureScrollBegin:
+ m_gestureStartLocation = WebPoint(point.x, point.y);
+ // Fallthrough
+ case WebInputEvent::GestureScrollEnd:
+ case WebInputEvent::GestureTap:
+ event.x = point.x;
+ event.y = point.y;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ event.globalX = event.x;
+ event.globalY = event.y;
+ event.timeStampSeconds = getCurrentEventTimeSec();
+ webview()->handleInputEvent(event);
+}
+
+//
+// Unimplemented stubs
+//
+
+void EventSender::enableDOMUIEventLogging(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void EventSender::fireKeyboardEventsToElement(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
+
+void EventSender::clearKillRing(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+}
diff --git a/Tools/DumpRenderTree/chromium/EventSender.h b/Tools/DumpRenderTree/chromium/EventSender.h
new file mode 100644
index 000000000..bbecc5488
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/EventSender.h
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+/*
+ EventSender class:
+ Bound to a JavaScript window.eventSender object using
+ CppBoundClass::bindToJavascript(), this allows layout tests to fire DOM events.
+*/
+
+#ifndef EventSender_h
+#define EventSender_h
+
+#include "CppBoundClass.h"
+#include "Task.h"
+#include "WebDragOperation.h"
+#include "WebInputEvent.h"
+#include "platform/WebPoint.h"
+
+class TestShell;
+
+namespace WebKit {
+class WebDragData;
+class WebView;
+}
+
+class EventSender : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ EventSender(TestShell*);
+
+ // Resets some static variable state.
+ void reset();
+
+ // Simulate drag&drop system call.
+ void doDragDrop(const WebKit::WebDragData&, WebKit::WebDragOperationsMask);
+
+ // Test helper for dragging out images.
+ void dumpFilenameBeingDragged(const CppArgumentList&, CppVariant*);
+
+ // JS callback methods.
+ void mouseDown(const CppArgumentList&, CppVariant*);
+ void mouseUp(const CppArgumentList&, CppVariant*);
+ void mouseMoveTo(const CppArgumentList&, CppVariant*);
+ void leapForward(const CppArgumentList&, CppVariant*);
+ void keyDown(const CppArgumentList&, CppVariant*);
+ void dispatchMessage(const CppArgumentList&, CppVariant*);
+ // FIXME: These aren't really events. They should be moved to layout controller.
+ void textZoomIn(const CppArgumentList&, CppVariant*);
+ void textZoomOut(const CppArgumentList&, CppVariant*);
+ void zoomPageIn(const CppArgumentList&, CppVariant*);
+ void zoomPageOut(const CppArgumentList&, CppVariant*);
+ void scalePageBy(const CppArgumentList&, CppVariant*);
+
+ void mouseScrollBy(const CppArgumentList&, CppVariant*);
+ void continuousMouseScrollBy(const CppArgumentList&, CppVariant*);
+ void scheduleAsynchronousClick(const CppArgumentList&, CppVariant*);
+ void scheduleAsynchronousKeyDown(const CppArgumentList&, CppVariant*);
+ void beginDragWithFiles(const CppArgumentList&, CppVariant*);
+ CppVariant dragMode;
+
+ void addTouchPoint(const CppArgumentList&, CppVariant*);
+ void cancelTouchPoint(const CppArgumentList&, CppVariant*);
+ void clearTouchPoints(const CppArgumentList&, CppVariant*);
+ void releaseTouchPoint(const CppArgumentList&, CppVariant*);
+ void setTouchModifier(const CppArgumentList&, CppVariant*);
+ void touchCancel(const CppArgumentList&, CppVariant*);
+ void touchEnd(const CppArgumentList&, CppVariant*);
+ void touchMove(const CppArgumentList&, CppVariant*);
+ void touchStart(const CppArgumentList&, CppVariant*);
+ void updateTouchPoint(const CppArgumentList&, CppVariant*);
+
+ void gestureScrollBegin(const CppArgumentList&, CppVariant*);
+ void gestureScrollEnd(const CppArgumentList&, CppVariant*);
+ void gestureScrollUpdate(const CppArgumentList&, CppVariant*);
+ void gestureTap(const CppArgumentList&, CppVariant*);
+ void gestureEvent(WebKit::WebInputEvent::Type, const CppArgumentList&);
+
+ // Unimplemented stubs
+ void contextClick(const CppArgumentList&, CppVariant*);
+ void enableDOMUIEventLogging(const CppArgumentList&, CppVariant*);
+ void fireKeyboardEventsToElement(const CppArgumentList&, CppVariant*);
+ void clearKillRing(const CppArgumentList&, CppVariant*);
+
+ // Properties used in layout tests.
+#if defined(OS_WIN)
+ CppVariant wmKeyDown;
+ CppVariant wmKeyUp;
+ CppVariant wmChar;
+ CppVariant wmDeadChar;
+ CppVariant wmSysKeyDown;
+ CppVariant wmSysKeyUp;
+ CppVariant wmSysChar;
+ CppVariant wmSysDeadChar;
+#endif
+
+ TaskList* taskList() { return &m_taskList; }
+
+private:
+ // Returns the test shell's webview.
+ WebKit::WebView* webview();
+
+ // Returns true if dragMode is true.
+ bool isDragMode() { return dragMode.isBool() && dragMode.toBoolean(); }
+
+ // Sometimes we queue up mouse move and mouse up events for drag drop
+ // handling purposes. These methods dispatch the event.
+ void doMouseMove(const WebKit::WebMouseEvent&);
+ void doMouseUp(const WebKit::WebMouseEvent&);
+ static void doLeapForward(int milliseconds);
+ void replaySavedEvents();
+
+ // Helper to return the button type given a button code
+ static WebKit::WebMouseEvent::Button getButtonTypeFromButtonNumber(int);
+
+ // Helper to extract the button number from the optional argument in
+ // mouseDown and mouseUp
+ static int getButtonNumberFromSingleArg(const CppArgumentList&);
+
+ // Returns true if the specified key code passed in needs a shift key
+ // modifier to be passed into the generated event.
+ bool needsShiftModifier(int);
+
+ void updateClickCountForButton(WebKit::WebMouseEvent::Button);
+
+ // Compose a touch event from the current touch points and send it.
+ void sendCurrentTouchEvent(const WebKit::WebInputEvent::Type);
+
+ // Handle a request to send a wheel event.
+ void handleMouseWheel(const CppArgumentList&, CppVariant*, bool continuous);
+
+ TaskList m_taskList;
+
+ // Non-owning pointer. The EventSender is owned by the TestShell.
+ TestShell* m_shell;
+
+ // Location of the touch point that initiated a gesture.
+ WebKit::WebPoint m_gestureStartLocation;
+
+ // Location of last mouseMoveTo event.
+ static WebKit::WebPoint lastMousePos;
+
+ // Currently pressed mouse button (Left/Right/Middle or None)
+ static WebKit::WebMouseEvent::Button pressedButton;
+
+ // The last button number passed to mouseDown and mouseUp.
+ // Used to determine whether the click count continues to
+ // increment or not.
+ static WebKit::WebMouseEvent::Button lastButtonType;
+};
+
+#endif // EventSender_h
diff --git a/Tools/DumpRenderTree/chromium/GamepadController.cpp b/Tools/DumpRenderTree/chromium/GamepadController.cpp
new file mode 100644
index 000000000..2974d3bcd
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/GamepadController.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2011 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 "GamepadController.h"
+
+#include "TestShell.h"
+
+using namespace WebKit;
+
+GamepadController::GamepadController(TestShell* shell)
+ : m_shell(shell)
+{
+ bindMethod("connect", &GamepadController::connect);
+ bindMethod("disconnect", &GamepadController::disconnect);
+ bindMethod("setId", &GamepadController::setId);
+ bindMethod("setButtonCount", &GamepadController::setButtonCount);
+ bindMethod("setButtonData", &GamepadController::setButtonData);
+ bindMethod("setAxisCount", &GamepadController::setAxisCount);
+ bindMethod("setAxisData", &GamepadController::setAxisData);
+
+ bindFallbackMethod(&GamepadController::fallbackCallback);
+
+ reset();
+}
+
+void GamepadController::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ CppBoundClass::bindToJavascript(frame, classname);
+}
+
+void GamepadController::reset()
+{
+ memset(&internalData, 0, sizeof(internalData));
+}
+
+void GamepadController::connect(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 1) {
+ printf("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ internalData.items[index].connected = true;
+ internalData.length = 0;
+ for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; ++i)
+ if (internalData.items[i].connected)
+ internalData.length = i + 1;
+ webkit_support::SetGamepadData(internalData);
+ result->setNull();
+}
+
+void GamepadController::disconnect(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 1) {
+ printf("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ internalData.items[index].connected = false;
+ internalData.length = 0;
+ for (unsigned i = 0; i < WebKit::WebGamepads::itemsLengthCap; ++i)
+ if (internalData.items[i].connected)
+ internalData.length = i + 1;
+ webkit_support::SetGamepadData(internalData);
+ result->setNull();
+}
+
+void GamepadController::setId(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 2) {
+ printf("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ std::string src = args[1].toString();
+ const char* p = src.c_str();
+ memset(internalData.items[index].id, 0, sizeof(internalData.items[index].id));
+ for (unsigned i = 0; *p && i < WebKit::WebGamepad::idLengthCap - 1; ++i)
+ internalData.items[index].id[i] = *p++;
+ webkit_support::SetGamepadData(internalData);
+ result->setNull();
+}
+
+void GamepadController::setButtonCount(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 2) {
+ printf("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ int buttons = args[1].toInt32();
+ internalData.items[index].buttonsLength = buttons;
+ webkit_support::SetGamepadData(internalData);
+ result->setNull();
+}
+
+void GamepadController::setButtonData(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 3) {
+ printf("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ int button = args[1].toInt32();
+ double data = args[2].toDouble();
+ internalData.items[index].buttons[button] = data;
+ webkit_support::SetGamepadData(internalData);
+ result->setNull();
+}
+
+void GamepadController::setAxisCount(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 2) {
+ printf("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ int axes = args[1].toInt32();
+ internalData.items[index].axesLength = axes;
+ webkit_support::SetGamepadData(internalData);
+ result->setNull();
+}
+
+void GamepadController::setAxisData(const CppArgumentList& args, CppVariant* result)
+{
+ if (args.size() < 3) {
+ printf("Invalid args");
+ return;
+ }
+ int index = args[0].toInt32();
+ int axis = args[1].toInt32();
+ double data = args[2].toDouble();
+ internalData.items[index].axes[axis] = data;
+ webkit_support::SetGamepadData(internalData);
+ result->setNull();
+}
+
+void GamepadController::fallbackCallback(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on "
+ "GamepadController\n");
+ result->setNull();
+}
diff --git a/Tools/DumpRenderTree/chromium/GamepadController.h b/Tools/DumpRenderTree/chromium/GamepadController.h
new file mode 100644
index 000000000..414228855
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/GamepadController.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 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 GamepadController_h
+#define GamepadController_h
+
+#include "CppBoundClass.h"
+#include "platform/WebGamepads.h"
+
+namespace WebKit {
+class WebGamepads;
+class WebFrame;
+}
+
+class TestShell;
+
+class GamepadController : public CppBoundClass {
+public:
+ explicit GamepadController(TestShell*);
+
+ void bindToJavascript(WebKit::WebFrame*, const WebKit::WebString& classname);
+ void reset();
+
+private:
+ // Bound methods and properties
+ void connect(const CppArgumentList&, CppVariant*);
+ void disconnect(const CppArgumentList&, CppVariant*);
+ void setId(const CppArgumentList&, CppVariant*);
+ void setButtonCount(const CppArgumentList&, CppVariant*);
+ void setButtonData(const CppArgumentList&, CppVariant*);
+ void setAxisCount(const CppArgumentList&, CppVariant*);
+ void setAxisData(const CppArgumentList&, CppVariant*);
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ TestShell* m_shell;
+
+ WebKit::WebGamepads internalData;
+};
+
+#endif // GamepadController_h
diff --git a/Tools/DumpRenderTree/chromium/ImageDiff.cpp b/Tools/DumpRenderTree/chromium/ImageDiff.cpp
new file mode 100644
index 000000000..966554bab
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/ImageDiff.cpp
@@ -0,0 +1,521 @@
+/*
+ * 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.
+ */
+
+// This file input format is based loosely on
+// WebKitTools/DumpRenderTree/ImageDiff.m
+
+// The exact format of this tool's output to stdout is important, to match
+// what the run-webkit-tests script expects.
+
+#include "config.h"
+
+#include "webkit/support/webkit_support_gfx.h"
+#include <algorithm>
+#include <iterator>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <vector>
+
+#if OS(WINDOWS)
+#include <windows.h>
+#define PATH_MAX MAX_PATH
+#endif
+
+// Define macro here to make ImageDiff independent of JavaScriptCore.
+#ifdef NDEBUG
+#define ASSERT(assertion) do { } while (0)
+#else
+#define ASSERT(assertion) do \
+ if (!(assertion)) { \
+ fprintf(stderr, "ASSERT failed at %s:%d: " #assertion ".", __FILE__, __LINE__); \
+ exit(1); \
+ } \
+while (0)
+#endif
+
+using namespace std;
+
+// Causes the app to remain open, waiting for pairs of filenames on stdin.
+// The caller is then responsible for terminating this app.
+static const char optionPollStdin[] = "--use-stdin";
+static const char optionGenerateDiff[] = "--diff";
+
+// If --diff is passed, causes the app to output the image difference
+// metric (percentageDifferent()) on stdout.
+static const char optionWrite[] = "--write-image-diff-metrics";
+
+// Use weightedPercentageDifferent() instead of the default image
+// comparator proc.
+static const char optionWeightedIntensity[] = "--weighted-intensity";
+
+// Return codes used by this utility.
+static const int statusSame = 0;
+static const int statusDifferent = 1;
+static const int statusError = 2;
+
+// Color codes.
+static const unsigned int rgbaRed = 0x000000ff;
+static const unsigned int rgbaAlpha = 0xff000000;
+
+class Image {
+public:
+ Image()
+ : m_width(0)
+ , m_height(0) { }
+
+ Image(const Image& image)
+ : m_width(image.m_width)
+ , m_height(image.m_height)
+ , m_data(image.m_data) { }
+
+ bool hasImage() const { return m_width > 0 && m_height > 0; }
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+ const unsigned char* data() const { return &m_data.front(); }
+
+ // Creates the image from stdin with the given data length. On success, it
+ // will return true. On failure, no other methods should be accessed.
+ bool createFromStdin(size_t byteLength)
+ {
+ if (!byteLength)
+ return false;
+
+ unsigned char* source = new unsigned char[byteLength];
+ if (fread(source, 1, byteLength, stdin) != byteLength) {
+ delete [] source;
+ return false;
+ }
+
+ if (!webkit_support::DecodePNG(source, byteLength, &m_data, &m_width, &m_height)) {
+ delete [] source;
+ clear();
+ return false;
+ }
+ delete [] source;
+ return true;
+ }
+
+ // Creates the image from the given filename on disk, and returns true on
+ // success.
+ bool createFromFilename(const char* filename)
+ {
+ FILE* f = fopen(filename, "rb");
+ if (!f)
+ return false;
+
+ vector<unsigned char> compressed;
+ const int bufSize = 1024;
+ unsigned char buf[bufSize];
+ size_t numRead = 0;
+ while ((numRead = fread(buf, 1, bufSize, f)) > 0)
+ std::copy(buf, &buf[numRead], std::back_inserter(compressed));
+
+ fclose(f);
+
+ if (!webkit_support::DecodePNG(&compressed[0], compressed.size(), &m_data, &m_width, &m_height)) {
+ clear();
+ return false;
+ }
+ return true;
+ }
+
+ void clear()
+ {
+ m_width = m_height = 0;
+ m_data.clear();
+ }
+
+ // Returns the RGBA value of the pixel at the given location
+ const unsigned int pixelAt(int x, int y) const
+ {
+ ASSERT(x >= 0 && x < m_width);
+ ASSERT(y >= 0 && y < m_height);
+ return *reinterpret_cast<const unsigned int*>(&(m_data[(y * m_width + x) * 4]));
+ }
+
+ void setPixelAt(int x, int y, unsigned int color) const
+ {
+ ASSERT(x >= 0 && x < m_width);
+ ASSERT(y >= 0 && y < m_height);
+ void* addr = &const_cast<unsigned char*>(&m_data.front())[(y * m_width + x) * 4];
+ *reinterpret_cast<unsigned int*>(addr) = color;
+ }
+
+private:
+ // pixel dimensions of the image
+ int m_width, m_height;
+
+ vector<unsigned char> m_data;
+};
+
+typedef float (*ImageComparisonProc) (const Image&, const Image&);
+
+float percentageDifferent(const Image& baseline, const Image& actual)
+{
+ int w = min(baseline.width(), actual.width());
+ int h = min(baseline.height(), actual.height());
+
+ // Compute pixels different in the overlap
+ int pixelsDifferent = 0;
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ if (baseline.pixelAt(x, y) != actual.pixelAt(x, y))
+ pixelsDifferent++;
+ }
+ }
+
+ // Count pixels that are a difference in size as also being different
+ int maxWidth = max(baseline.width(), actual.width());
+ int maxHeight = max(baseline.height(), actual.height());
+
+ // ...pixels off the right side, but not including the lower right corner
+ pixelsDifferent += (maxWidth - w) * h;
+
+ // ...pixels along the bottom, including the lower right corner
+ pixelsDifferent += (maxHeight - h) * maxWidth;
+
+ // Like the WebKit ImageDiff tool, we define percentage different in terms
+ // of the size of the 'actual' bitmap.
+ float totalPixels = static_cast<float>(actual.width()) * static_cast<float>(actual.height());
+ if (!totalPixels)
+ return 100.0f; // When the bitmap is empty, they are 100% different.
+ return static_cast<float>(pixelsDifferent) / totalPixels * 100;
+}
+
+inline unsigned int maxOf3(unsigned int a, unsigned int b, unsigned int c)
+{
+ if (a < b)
+ return std::max(b, c);
+ return std::max(a, c);
+}
+
+inline unsigned int getRedComponent(unsigned int color)
+{
+ return (color << 24) >> 24;
+}
+
+inline unsigned int getGreenComponent(unsigned int color)
+{
+ return (color << 16) >> 24;
+}
+
+inline unsigned int getBlueComponent(unsigned int color)
+{
+ return (color << 8) >> 24;
+}
+
+/// Rank small-pixel-count high-intensity changes as more important than
+/// large-pixel-count low-intensity changes.
+float weightedPercentageDifferent(const Image& baseline, const Image& actual)
+{
+ int w = min(baseline.width(), actual.width());
+ int h = min(baseline.height(), actual.height());
+
+ float weightedPixelsDifferent = 0;
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ unsigned int actualColor = actual.pixelAt(x, y);
+ unsigned int baselineColor = baseline.pixelAt(x, y);
+ if (baselineColor != actualColor) {
+ unsigned int actualR = getRedComponent(actualColor);
+ unsigned int actualG = getGreenComponent(actualColor);
+ unsigned int actualB = getBlueComponent(actualColor);
+ unsigned int baselineR = getRedComponent(baselineColor);
+ unsigned int baselineG = getGreenComponent(baselineColor);
+ unsigned int baselineB = getBlueComponent(baselineColor);
+ unsigned int deltaR = std::max(actualR, baselineR)
+ - std::min(actualR, baselineR);
+ unsigned int deltaG = std::max(actualG, baselineG)
+ - std::min(actualG, baselineG);
+ unsigned int deltaB = std::max(actualB, baselineB)
+ - std::min(actualB, baselineB);
+ weightedPixelsDifferent +=
+ static_cast<float>(maxOf3(deltaR, deltaG, deltaB)) / 255;
+ }
+ }
+ }
+
+ int maxWidth = max(baseline.width(), actual.width());
+ int maxHeight = max(baseline.height(), actual.height());
+
+ weightedPixelsDifferent += (maxWidth - w) * h;
+
+ weightedPixelsDifferent += (maxHeight - h) * maxWidth;
+
+ float totalPixels = static_cast<float>(actual.width())
+ * static_cast<float>(actual.height());
+ if (!totalPixels)
+ return 100.0f;
+ return weightedPixelsDifferent / totalPixels * 100;
+}
+
+
+void printHelp()
+{
+ fprintf(stderr,
+ "Usage:\n"
+ " ImageDiff <compare file> <reference file>\n"
+ " Compares two files on disk, returning 0 when they are the same\n"
+ " ImageDiff --use-stdin\n"
+ " Stays open reading pairs of filenames from stdin, comparing them,\n"
+ " and sending 0 to stdout when they are the same\n"
+ " ImageDiff --diff <compare file> <reference file> <output file>\n"
+ " Compares two files on disk, outputs an image that visualizes the"
+ " difference to <output file>\n"
+ " --write-image-diff-metrics prints a difference metric to stdout\n"
+ " --weighted-intensity weights the difference metric by intensity\n"
+ " at each pixel\n");
+ /* For unfinished webkit-like-mode (see below)
+ "\n"
+ " ImageDiff -s\n"
+ " Reads stream input from stdin, should be EXACTLY of the format\n"
+ " \"Content-length: <byte length> <data>Content-length: ...\n"
+ " it will take as many file pairs as given, and will compare them as\n"
+ " (cmp_file, reference_file) pairs\n");
+ */
+}
+
+int compareImages(const char* file1, const char* file2,
+ ImageComparisonProc comparator)
+{
+ Image actualImage;
+ Image baselineImage;
+
+ if (!actualImage.createFromFilename(file1)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file1);
+ return statusError;
+ }
+ if (!baselineImage.createFromFilename(file2)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file2);
+ return statusError;
+ }
+
+ float percent = (*comparator)(actualImage, baselineImage);
+ if (percent > 0.0) {
+ // failure: The WebKit version also writes the difference image to
+ // stdout, which seems excessive for our needs.
+ printf("diff: %01.2f%% failed\n", percent);
+ return statusDifferent;
+ }
+
+ // success
+ printf("diff: %01.2f%% passed\n", percent);
+ return statusSame;
+
+}
+
+// Untested mode that acts like WebKit's image comparator. I wrote this but
+// decided it's too complicated. We may use it in the future if it looks useful.
+int untestedCompareImages(ImageComparisonProc comparator)
+{
+ Image actualImage;
+ Image baselineImage;
+ char buffer[2048];
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ if (!strncmp("Content-length: ", buffer, 16)) {
+ char* context;
+#if OS(WINDOWS)
+ strtok_s(buffer, " ", &context);
+ int imageSize = strtol(strtok_s(0, " ", &context), 0, 10);
+#else
+ strtok_r(buffer, " ", &context);
+ int imageSize = strtol(strtok_r(0, " ", &context), 0, 10);
+#endif
+
+ bool success = false;
+ if (imageSize > 0 && !actualImage.hasImage()) {
+ if (!actualImage.createFromStdin(imageSize)) {
+ fputs("Error, input image can't be decoded.\n", stderr);
+ return 1;
+ }
+ } else if (imageSize > 0 && !baselineImage.hasImage()) {
+ if (!baselineImage.createFromStdin(imageSize)) {
+ fputs("Error, baseline image can't be decoded.\n", stderr);
+ return 1;
+ }
+ } else {
+ fputs("Error, image size must be specified.\n", stderr);
+ return 1;
+ }
+ }
+
+ if (actualImage.hasImage() && baselineImage.hasImage()) {
+ float percent = (*comparator)(actualImage, baselineImage);
+ if (percent > 0.0) {
+ // failure: The WebKit version also writes the difference image to
+ // stdout, which seems excessive for our needs.
+ printf("diff: %01.2f%% failed\n", percent);
+ } else {
+ // success
+ printf("diff: %01.2f%% passed\n", percent);
+ }
+ actualImage.clear();
+ baselineImage.clear();
+ }
+ fflush(stdout);
+ }
+ return 0;
+}
+
+bool createImageDiff(const Image& image1, const Image& image2, Image* out)
+{
+ int w = min(image1.width(), image2.width());
+ int h = min(image1.height(), image2.height());
+ *out = Image(image1);
+ bool same = (image1.width() == image2.width()) && (image1.height() == image2.height());
+
+ // FIXME: do something with the extra pixels if the image sizes are different.
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ unsigned int basePixel = image1.pixelAt(x, y);
+ if (basePixel != image2.pixelAt(x, y)) {
+ // Set differing pixels red.
+ out->setPixelAt(x, y, rgbaRed | rgbaAlpha);
+ same = false;
+ } else {
+ // Set same pixels as faded.
+ unsigned int alpha = basePixel & rgbaAlpha;
+ unsigned int newPixel = basePixel - ((alpha / 2) & rgbaAlpha);
+ out->setPixelAt(x, y, newPixel);
+ }
+ }
+ }
+
+ return same;
+}
+
+static bool writeFile(const char* outFile, const unsigned char* data, size_t dataSize)
+{
+ FILE* file = fopen(outFile, "wb");
+ if (!file) {
+ fprintf(stderr, "ImageDiff: Unable to create file \"%s\"\n", outFile);
+ return false;
+ }
+ if (dataSize != fwrite(data, 1, dataSize, file)) {
+ fclose(file);
+ fprintf(stderr, "ImageDiff: Unable to write data to file \"%s\"\n", outFile);
+ return false;
+ }
+ fclose(file);
+ return true;
+}
+
+int diffImages(const char* file1, const char* file2, const char* outFile,
+ bool shouldWritePercentages, ImageComparisonProc comparator)
+{
+ Image actualImage;
+ Image baselineImage;
+
+ if (!actualImage.createFromFilename(file1)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file1);
+ return statusError;
+ }
+ if (!baselineImage.createFromFilename(file2)) {
+ fprintf(stderr, "ImageDiff: Unable to open file \"%s\"\n", file2);
+ return statusError;
+ }
+
+ Image diffImage;
+ bool same = createImageDiff(baselineImage, actualImage, &diffImage);
+ if (same)
+ return statusSame;
+
+ vector<unsigned char> pngData;
+ webkit_support::EncodeRGBAPNG(diffImage.data(), diffImage.width(), diffImage.height(),
+ diffImage.width() * 4, &pngData);
+ if (!writeFile(outFile, &pngData.front(), pngData.size()))
+ return statusError;
+
+ if (shouldWritePercentages) {
+ float percent = (*comparator)(actualImage, baselineImage);
+ fprintf(stdout, "%.3f\n", percent);
+ }
+
+ return statusDifferent;
+}
+
+int main(int argc, const char* argv[])
+{
+ std::vector<const char*> values;
+ bool pollStdin = false;
+ bool generateDiff = false;
+ bool shouldWritePercentages = false;
+ ImageComparisonProc comparator = percentageDifferent;
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], optionPollStdin))
+ pollStdin = true;
+ else if (!strcmp(argv[i], optionGenerateDiff))
+ generateDiff = true;
+ else if (!strcmp(argv[i], optionWrite))
+ shouldWritePercentages = true;
+ else if (!strcmp(argv[i], optionWeightedIntensity))
+ comparator = weightedPercentageDifferent;
+ else
+ values.push_back(argv[i]);
+ }
+
+ if (pollStdin) {
+ // Watch stdin for filenames.
+ const size_t bufferSize = PATH_MAX;
+ char stdinBuffer[bufferSize];
+ char firstName[bufferSize];
+ bool haveFirstName = false;
+ while (fgets(stdinBuffer, bufferSize, stdin)) {
+ if (!stdinBuffer[0])
+ continue;
+
+ if (haveFirstName) {
+ // compareImages writes results to stdout unless an error occurred.
+ if (compareImages(firstName, stdinBuffer,
+ comparator) == statusError)
+ printf("error\n");
+ fflush(stdout);
+ haveFirstName = false;
+ } else {
+ // Save the first filename in another buffer and wait for the second
+ // filename to arrive via stdin.
+ strcpy(firstName, stdinBuffer);
+ haveFirstName = true;
+ }
+ }
+ return 0;
+ }
+
+ if (generateDiff) {
+ if (values.size() == 3)
+ return diffImages(values[0], values[1], values[2],
+ shouldWritePercentages, comparator);
+ } else if (values.size() == 2)
+ return compareImages(argv[1], argv[2], comparator);
+
+ printHelp();
+ return statusError;
+}
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.cpp b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp
new file mode 100644
index 000000000..7fc21362f
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp
@@ -0,0 +1,2152 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * 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 "LayoutTestController.h"
+
+#include "DRTDevToolsAgent.h"
+#include "TestShell.h"
+#include "WebAnimationController.h"
+#include "WebBindings.h"
+#include "WebConsoleMessage.h"
+#include "platform/WebData.h"
+#include "WebDeviceOrientation.h"
+#include "WebDeviceOrientationClientMock.h"
+#include "WebDocument.h"
+#include "WebElement.h"
+#include "WebFindOptions.h"
+#include "WebFrame.h"
+#include "WebGeolocationClientMock.h"
+#include "WebIDBFactory.h"
+#include "WebInputElement.h"
+#include "WebKit.h"
+#include "WebNotificationPresenter.h"
+#include "WebPermissions.h"
+#include "WebScriptSource.h"
+#include "WebSecurityPolicy.h"
+#include "WebSettings.h"
+#include "platform/WebSize.h"
+#include "WebSpeechInputControllerMock.h"
+#include "platform/WebURL.h"
+#include "WebView.h"
+#include "WebViewHost.h"
+#include "webkit/support/webkit_support.h"
+#include <algorithm>
+#include <cctype>
+#include <clocale>
+#include <cstdlib>
+#include <limits>
+#include <sstream>
+#include <wtf/text/WTFString.h>
+
+#if OS(WINDOWS)
+#include <wtf/OwnArrayPtr.h>
+#endif
+
+using namespace WebCore;
+using namespace WebKit;
+using namespace std;
+
+LayoutTestController::LayoutTestController(TestShell* shell)
+ : m_shell(shell)
+ , m_closeRemainingWindows(false)
+ , m_deferMainResourceDataLoad(false)
+ , m_showDebugLayerTree(false)
+ , m_workQueue(this)
+ , m_shouldStayOnPageAfterHandlingBeforeUnload(false)
+{
+
+ // Initialize the map that associates methods of this class with the names
+ // they will use when called by JavaScript. The actual binding of those
+ // names to their methods will be done by calling bindToJavaScript() (defined
+ // by CppBoundClass, the parent to LayoutTestController).
+ bindMethod("addFileToPasteboardOnDrag", &LayoutTestController::addFileToPasteboardOnDrag);
+ bindMethod("addMockSpeechInputResult", &LayoutTestController::addMockSpeechInputResult);
+ bindMethod("addOriginAccessWhitelistEntry", &LayoutTestController::addOriginAccessWhitelistEntry);
+ bindMethod("addUserScript", &LayoutTestController::addUserScript);
+ bindMethod("addUserStyleSheet", &LayoutTestController::addUserStyleSheet);
+ bindMethod("clearAllDatabases", &LayoutTestController::clearAllDatabases);
+ bindMethod("closeWebInspector", &LayoutTestController::closeWebInspector);
+ bindMethod("counterValueForElementById", &LayoutTestController::counterValueForElementById);
+ bindMethod("disableImageLoading", &LayoutTestController::disableImageLoading);
+ bindMethod("display", &LayoutTestController::display);
+ bindMethod("displayInvalidatedRegion", &LayoutTestController::displayInvalidatedRegion);
+ bindMethod("dumpAsText", &LayoutTestController::dumpAsText);
+ bindMethod("dumpBackForwardList", &LayoutTestController::dumpBackForwardList);
+ bindMethod("dumpChildFramesAsText", &LayoutTestController::dumpChildFramesAsText);
+ bindMethod("dumpChildFrameScrollPositions", &LayoutTestController::dumpChildFrameScrollPositions);
+ bindMethod("dumpDatabaseCallbacks", &LayoutTestController::dumpDatabaseCallbacks);
+ bindMethod("dumpEditingCallbacks", &LayoutTestController::dumpEditingCallbacks);
+ bindMethod("dumpFrameLoadCallbacks", &LayoutTestController::dumpFrameLoadCallbacks);
+ bindMethod("dumpProgressFinishedCallback", &LayoutTestController::dumpProgressFinishedCallback);
+ bindMethod("dumpUserGestureInFrameLoadCallbacks", &LayoutTestController::dumpUserGestureInFrameLoadCallbacks);
+ bindMethod("dumpResourceLoadCallbacks", &LayoutTestController::dumpResourceLoadCallbacks);
+ bindMethod("dumpResourceResponseMIMETypes", &LayoutTestController::dumpResourceResponseMIMETypes);
+ bindMethod("dumpSelectionRect", &LayoutTestController::dumpSelectionRect);
+ bindMethod("dumpStatusCallbacks", &LayoutTestController::dumpWindowStatusChanges);
+ bindMethod("dumpTitleChanges", &LayoutTestController::dumpTitleChanges);
+ bindMethod("dumpPermissionClientCallbacks", &LayoutTestController::dumpPermissionClientCallbacks);
+ bindMethod("dumpCreateView", &LayoutTestController::dumpCreateView);
+ bindMethod("elementDoesAutoCompleteForElementWithId", &LayoutTestController::elementDoesAutoCompleteForElementWithId);
+ bindMethod("evaluateInWebInspector", &LayoutTestController::evaluateInWebInspector);
+ bindMethod("evaluateScriptInIsolatedWorld", &LayoutTestController::evaluateScriptInIsolatedWorld);
+ bindMethod("setIsolatedWorldSecurityOrigin", &LayoutTestController::setIsolatedWorldSecurityOrigin);
+ bindMethod("execCommand", &LayoutTestController::execCommand);
+ bindMethod("forceRedSelectionColors", &LayoutTestController::forceRedSelectionColors);
+ bindMethod("grantDesktopNotificationPermission", &LayoutTestController::grantDesktopNotificationPermission);
+ bindMethod("hasSpellingMarker", &LayoutTestController::hasSpellingMarker);
+ bindMethod("findString", &LayoutTestController::findString);
+ bindMethod("isCommandEnabled", &LayoutTestController::isCommandEnabled);
+ bindMethod("hasCustomPageSizeStyle", &LayoutTestController::hasCustomPageSizeStyle);
+ bindMethod("isPageBoxVisible", &LayoutTestController::isPageBoxVisible);
+ bindMethod("layerTreeAsText", &LayoutTestController::layerTreeAsText);
+ bindMethod("loseCompositorContext", &LayoutTestController::loseCompositorContext);
+ bindMethod("markerTextForListItem", &LayoutTestController::markerTextForListItem);
+ bindMethod("notifyDone", &LayoutTestController::notifyDone);
+ bindMethod("numberOfActiveAnimations", &LayoutTestController::numberOfActiveAnimations);
+ bindMethod("numberOfPages", &LayoutTestController::numberOfPages);
+ bindMethod("numberOfPendingGeolocationPermissionRequests", &LayoutTestController:: numberOfPendingGeolocationPermissionRequests);
+ bindMethod("objCIdentityIsEqual", &LayoutTestController::objCIdentityIsEqual);
+ bindMethod("overridePreference", &LayoutTestController::overridePreference);
+ bindMethod("pageNumberForElementById", &LayoutTestController::pageNumberForElementById);
+ bindMethod("pageProperty", &LayoutTestController::pageProperty);
+ bindMethod("pageSizeAndMarginsInPixels", &LayoutTestController::pageSizeAndMarginsInPixels);
+ bindMethod("pathToLocalResource", &LayoutTestController::pathToLocalResource);
+ bindMethod("pauseAnimationAtTimeOnElementWithId", &LayoutTestController::pauseAnimationAtTimeOnElementWithId);
+ bindMethod("pauseTransitionAtTimeOnElementWithId", &LayoutTestController::pauseTransitionAtTimeOnElementWithId);
+ bindMethod("queueBackNavigation", &LayoutTestController::queueBackNavigation);
+ bindMethod("queueForwardNavigation", &LayoutTestController::queueForwardNavigation);
+ bindMethod("queueLoadingScript", &LayoutTestController::queueLoadingScript);
+ bindMethod("queueLoad", &LayoutTestController::queueLoad);
+ bindMethod("queueLoadHTMLString", &LayoutTestController::queueLoadHTMLString);
+ bindMethod("queueNonLoadingScript", &LayoutTestController::queueNonLoadingScript);
+ bindMethod("queueReload", &LayoutTestController::queueReload);
+ bindMethod("removeOriginAccessWhitelistEntry", &LayoutTestController::removeOriginAccessWhitelistEntry);
+ bindMethod("repaintSweepHorizontally", &LayoutTestController::repaintSweepHorizontally);
+ bindMethod("resetPageVisibility", &LayoutTestController::resetPageVisibility);
+ bindMethod("resumeAnimations", &LayoutTestController::resumeAnimations);
+ bindMethod("sampleSVGAnimationForElementAtTime", &LayoutTestController::sampleSVGAnimationForElementAtTime);
+ bindMethod("setAcceptsEditing", &LayoutTestController::setAcceptsEditing);
+ bindMethod("setAllowDisplayOfInsecureContent", &LayoutTestController::setAllowDisplayOfInsecureContent);
+ bindMethod("setAllowFileAccessFromFileURLs", &LayoutTestController::setAllowFileAccessFromFileURLs);
+ bindMethod("setAllowRunningOfInsecureContent", &LayoutTestController::setAllowRunningOfInsecureContent);
+ bindMethod("setAllowUniversalAccessFromFileURLs", &LayoutTestController::setAllowUniversalAccessFromFileURLs);
+ bindMethod("setAlwaysAcceptCookies", &LayoutTestController::setAlwaysAcceptCookies);
+ bindMethod("setAuthorAndUserStylesEnabled", &LayoutTestController::setAuthorAndUserStylesEnabled);
+ bindMethod("setAutofilled", &LayoutTestController::setAutofilled);
+ bindMethod("setCanOpenWindows", &LayoutTestController::setCanOpenWindows);
+ bindMethod("setCloseRemainingWindowsWhenComplete", &LayoutTestController::setCloseRemainingWindowsWhenComplete);
+ bindMethod("setCustomPolicyDelegate", &LayoutTestController::setCustomPolicyDelegate);
+ bindMethod("setDatabaseQuota", &LayoutTestController::setDatabaseQuota);
+ bindMethod("setDeferMainResourceDataLoad", &LayoutTestController::setDeferMainResourceDataLoad);
+ bindMethod("setDomainRelaxationForbiddenForURLScheme", &LayoutTestController::setDomainRelaxationForbiddenForURLScheme);
+ bindMethod("setEditingBehavior", &LayoutTestController::setEditingBehavior);
+ bindMethod("setAudioData", &LayoutTestController::setAudioData);
+ bindMethod("setGeolocationPermission", &LayoutTestController::setGeolocationPermission);
+ bindMethod("setIconDatabaseEnabled", &LayoutTestController::setIconDatabaseEnabled);
+ bindMethod("setJavaScriptCanAccessClipboard", &LayoutTestController::setJavaScriptCanAccessClipboard);
+ bindMethod("setJavaScriptProfilingEnabled", &LayoutTestController::setJavaScriptProfilingEnabled);
+ bindMethod("setMinimumTimerInterval", &LayoutTestController::setMinimumTimerInterval);
+ bindMethod("setMockDeviceOrientation", &LayoutTestController::setMockDeviceOrientation);
+ bindMethod("setMockGeolocationError", &LayoutTestController::setMockGeolocationError);
+ bindMethod("setMockGeolocationPosition", &LayoutTestController::setMockGeolocationPosition);
+ bindMethod("setPageVisibility", &LayoutTestController::setPageVisibility);
+ bindMethod("setPluginsEnabled", &LayoutTestController::setPluginsEnabled);
+ bindMethod("setPopupBlockingEnabled", &LayoutTestController::setPopupBlockingEnabled);
+ bindMethod("setPOSIXLocale", &LayoutTestController::setPOSIXLocale);
+ bindMethod("setPrinting", &LayoutTestController::setPrinting);
+ bindMethod("setScrollbarPolicy", &LayoutTestController::setScrollbarPolicy);
+ bindMethod("setSelectTrailingWhitespaceEnabled", &LayoutTestController::setSelectTrailingWhitespaceEnabled);
+ bindMethod("setSmartInsertDeleteEnabled", &LayoutTestController::setSmartInsertDeleteEnabled);
+ bindMethod("setStopProvisionalFrameLoads", &LayoutTestController::setStopProvisionalFrameLoads);
+ bindMethod("setTabKeyCyclesThroughElements", &LayoutTestController::setTabKeyCyclesThroughElements);
+ bindMethod("setUserStyleSheetEnabled", &LayoutTestController::setUserStyleSheetEnabled);
+ bindMethod("setUserStyleSheetLocation", &LayoutTestController::setUserStyleSheetLocation);
+ bindMethod("setValueForUser", &LayoutTestController::setValueForUser);
+ bindMethod("setWillSendRequestClearHeader", &LayoutTestController::setWillSendRequestClearHeader);
+ bindMethod("setWillSendRequestReturnsNull", &LayoutTestController::setWillSendRequestReturnsNull);
+ bindMethod("setWillSendRequestReturnsNullOnRedirect", &LayoutTestController::setWillSendRequestReturnsNullOnRedirect);
+ bindMethod("setWindowIsKey", &LayoutTestController::setWindowIsKey);
+ bindMethod("setXSSAuditorEnabled", &LayoutTestController::setXSSAuditorEnabled);
+ bindMethod("setAsynchronousSpellCheckingEnabled", &LayoutTestController::setAsynchronousSpellCheckingEnabled);
+ bindMethod("showWebInspector", &LayoutTestController::showWebInspector);
+ bindMethod("simulateDesktopNotificationClick", &LayoutTestController::simulateDesktopNotificationClick);
+ bindMethod("startSpeechInput", &LayoutTestController::startSpeechInput);
+ bindMethod("suspendAnimations", &LayoutTestController::suspendAnimations);
+ bindMethod("testRepaint", &LayoutTestController::testRepaint);
+ bindMethod("waitForPolicyDelegate", &LayoutTestController::waitForPolicyDelegate);
+ bindMethod("waitUntilDone", &LayoutTestController::waitUntilDone);
+ bindMethod("windowCount", &LayoutTestController::windowCount);
+ bindMethod("setTextDirection", &LayoutTestController::setTextDirection);
+ bindMethod("setImagesAllowed", &LayoutTestController::setImagesAllowed);
+ bindMethod("setScriptsAllowed", &LayoutTestController::setScriptsAllowed);
+ bindMethod("setStorageAllowed", &LayoutTestController::setStorageAllowed);
+ bindMethod("setPluginsAllowed", &LayoutTestController::setPluginsAllowed);
+
+ // The following are stubs.
+ bindMethod("abortModal", &LayoutTestController::abortModal);
+ bindMethod("accessStoredWebScriptObject", &LayoutTestController::accessStoredWebScriptObject);
+ bindMethod("addDisallowedURL", &LayoutTestController::addDisallowedURL);
+ bindMethod("applicationCacheDiskUsageForOrigin", &LayoutTestController::applicationCacheDiskUsageForOrigin);
+ bindMethod("callShouldCloseOnWebView", &LayoutTestController::callShouldCloseOnWebView);
+ bindMethod("clearAllApplicationCaches", &LayoutTestController::clearAllApplicationCaches);
+ bindMethod("clearApplicationCacheForOrigin", &LayoutTestController::clearApplicationCacheForOrigin);
+ bindMethod("clearBackForwardList", &LayoutTestController::clearBackForwardList);
+ bindMethod("dumpAsWebArchive", &LayoutTestController::dumpAsWebArchive);
+ bindMethod("keepWebHistory", &LayoutTestController::keepWebHistory);
+ bindMethod("objCClassNameOf", &LayoutTestController::objCClassNameOf);
+ bindMethod("setApplicationCacheOriginQuota", &LayoutTestController::setApplicationCacheOriginQuota);
+ bindMethod("setCallCloseOnWebViews", &LayoutTestController::setCallCloseOnWebViews);
+ bindMethod("setMainFrameIsFirstResponder", &LayoutTestController::setMainFrameIsFirstResponder);
+ bindMethod("setPrivateBrowsingEnabled", &LayoutTestController::setPrivateBrowsingEnabled);
+ bindMethod("setUseDashboardCompatibilityMode", &LayoutTestController::setUseDashboardCompatibilityMode);
+ bindMethod("storeWebScriptObject", &LayoutTestController::storeWebScriptObject);
+ bindMethod("deleteAllLocalStorage", &LayoutTestController::deleteAllLocalStorage);
+ bindMethod("localStorageDiskUsageForOrigin", &LayoutTestController::localStorageDiskUsageForOrigin);
+ bindMethod("originsWithLocalStorage", &LayoutTestController::originsWithLocalStorage);
+ bindMethod("deleteLocalStorageForOrigin", &LayoutTestController::deleteLocalStorageForOrigin);
+ bindMethod("observeStorageTrackerNotifications", &LayoutTestController::observeStorageTrackerNotifications);
+ bindMethod("syncLocalStorage", &LayoutTestController::syncLocalStorage);
+ bindMethod("setShouldStayOnPageAfterHandlingBeforeUnload", &LayoutTestController::setShouldStayOnPageAfterHandlingBeforeUnload);
+ bindMethod("enableFixedLayoutMode", &LayoutTestController::enableFixedLayoutMode);
+ bindMethod("setFixedLayoutSize", &LayoutTestController::setFixedLayoutSize);
+
+ // The fallback method is called when an unknown method is invoked.
+ bindFallbackMethod(&LayoutTestController::fallbackMethod);
+
+ // Shared properties.
+ // globalFlag is used by a number of layout tests in
+ // LayoutTests\http\tests\security\dataURL.
+ bindProperty("globalFlag", &m_globalFlag);
+ // webHistoryItemCount is used by tests in LayoutTests\http\tests\history
+ bindProperty("webHistoryItemCount", &m_webHistoryItemCount);
+ bindProperty("titleTextDirection", &m_titleTextDirection);
+ bindProperty("platformName", &m_platformName);
+ bindProperty("interceptPostMessage", &m_interceptPostMessage);
+}
+
+LayoutTestController::~LayoutTestController()
+{
+}
+
+LayoutTestController::WorkQueue::~WorkQueue()
+{
+ reset();
+}
+
+void LayoutTestController::WorkQueue::processWorkSoon()
+{
+ if (m_controller->m_shell->webViewHost()->topLoadingFrame())
+ return;
+
+ if (!m_queue.isEmpty()) {
+ // We delay processing queued work to avoid recursion problems.
+ postTask(new WorkQueueTask(this));
+ } else if (!m_controller->m_waitUntilDone)
+ m_controller->m_shell->testFinished();
+}
+
+void LayoutTestController::WorkQueue::processWork()
+{
+ TestShell* shell = m_controller->m_shell;
+ // Quit doing work once a load is in progress.
+ while (!m_queue.isEmpty()) {
+ bool startedLoad = m_queue.first()->run(shell);
+ delete m_queue.takeFirst();
+ if (startedLoad)
+ return;
+ }
+
+ if (!m_controller->m_waitUntilDone && !shell->webViewHost()->topLoadingFrame())
+ shell->testFinished();
+}
+
+void LayoutTestController::WorkQueue::reset()
+{
+ m_frozen = false;
+ while (!m_queue.isEmpty())
+ delete m_queue.takeFirst();
+}
+
+void LayoutTestController::WorkQueue::addWork(WorkItem* work)
+{
+ if (m_frozen) {
+ delete work;
+ return;
+ }
+ m_queue.append(work);
+}
+
+void LayoutTestController::dumpAsText(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_dumpAsText = true;
+ m_generatePixelResults = false;
+
+ // Optional paramater, describing whether it's allowed to dump pixel results in dumpAsText mode.
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_generatePixelResults = arguments[0].value.boolValue;
+
+ result->setNull();
+}
+
+void LayoutTestController::dumpDatabaseCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ // Do nothing; we don't use this flag anywhere for now
+ result->setNull();
+}
+
+void LayoutTestController::dumpEditingCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpEditingCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpBackForwardList(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpBackForwardList = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpFrameLoadCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpProgressFinishedCallback(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpProgressFinishedCallback = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpUserGestureInFrameLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpUserGestureInFrameLoadCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpResourceLoadCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpResourceResponseMIMETypes(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpResourceResponseMIMETypes = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpChildFrameScrollPositions = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpChildFramesAsText(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpChildFramesAsText = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpWindowStatusChanges(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpWindowStatusChanges = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpTitleChanges(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpTitleChanges = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpPermissionClientCallbacks(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpPermissionClientCallbacks = true;
+ result->setNull();
+}
+
+void LayoutTestController::dumpCreateView(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpCreateView = true;
+ result->setNull();
+}
+
+void LayoutTestController::setAcceptsEditing(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_acceptsEditing = arguments[0].value.boolValue;
+ result->setNull();
+}
+
+void LayoutTestController::waitUntilDone(const CppArgumentList&, CppVariant* result)
+{
+ if (!webkit_support::BeingDebugged())
+ postDelayedTask(new NotifyDoneTimedOutTask(this), m_shell->layoutTestTimeout());
+ m_waitUntilDone = true;
+ result->setNull();
+}
+
+void LayoutTestController::notifyDone(const CppArgumentList&, CppVariant* result)
+{
+ // Test didn't timeout. Kill the timeout timer.
+ m_taskList.revokeAll();
+
+ completeNotifyDone(false);
+ result->setNull();
+}
+
+void LayoutTestController::completeNotifyDone(bool isTimeout)
+{
+ if (m_waitUntilDone && !m_shell->webViewHost()->topLoadingFrame() && m_workQueue.isEmpty()) {
+ if (isTimeout)
+ m_shell->testTimedOut();
+ else
+ m_shell->testFinished();
+ }
+ m_waitUntilDone = false;
+}
+
+class WorkItemBackForward : public LayoutTestController::WorkItem {
+public:
+ WorkItemBackForward(int distance) : m_distance(distance) { }
+ bool run(TestShell* shell)
+ {
+ shell->goToOffset(m_distance);
+ return true; // FIXME: Did it really start a navigation?
+ }
+
+private:
+ int m_distance;
+};
+
+void LayoutTestController::queueBackNavigation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isNumber())
+ m_workQueue.addWork(new WorkItemBackForward(-arguments[0].toInt32()));
+ result->setNull();
+}
+
+void LayoutTestController::queueForwardNavigation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isNumber())
+ m_workQueue.addWork(new WorkItemBackForward(arguments[0].toInt32()));
+ result->setNull();
+}
+
+class WorkItemReload : public LayoutTestController::WorkItem {
+public:
+ bool run(TestShell* shell)
+ {
+ shell->reload();
+ return true;
+ }
+};
+
+void LayoutTestController::queueReload(const CppArgumentList&, CppVariant* result)
+{
+ m_workQueue.addWork(new WorkItemReload);
+ result->setNull();
+}
+
+class WorkItemLoadingScript : public LayoutTestController::WorkItem {
+public:
+ WorkItemLoadingScript(const string& script) : m_script(script) { }
+ bool run(TestShell* shell)
+ {
+ shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
+ return true; // FIXME: Did it really start a navigation?
+ }
+
+private:
+ string m_script;
+};
+
+class WorkItemNonLoadingScript : public LayoutTestController::WorkItem {
+public:
+ WorkItemNonLoadingScript(const string& script) : m_script(script) { }
+ bool run(TestShell* shell)
+ {
+ shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
+ return false;
+ }
+
+private:
+ string m_script;
+};
+
+void LayoutTestController::queueLoadingScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString())
+ m_workQueue.addWork(new WorkItemLoadingScript(arguments[0].toString()));
+ result->setNull();
+}
+
+void LayoutTestController::queueNonLoadingScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString())
+ m_workQueue.addWork(new WorkItemNonLoadingScript(arguments[0].toString()));
+ result->setNull();
+}
+
+class WorkItemLoad : public LayoutTestController::WorkItem {
+public:
+ WorkItemLoad(const WebURL& url, const WebString& target)
+ : m_url(url)
+ , m_target(target) { }
+ bool run(TestShell* shell)
+ {
+ shell->webViewHost()->loadURLForFrame(m_url, m_target);
+ return true; // FIXME: Did it really start a navigation?
+ }
+
+private:
+ WebURL m_url;
+ WebString m_target;
+};
+
+void LayoutTestController::queueLoad(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ // FIXME: Implement WebURL::resolve() and avoid GURL.
+ GURL currentURL = m_shell->webView()->mainFrame()->document().url();
+ GURL fullURL = currentURL.Resolve(arguments[0].toString());
+
+ string target = "";
+ if (arguments.size() > 1 && arguments[1].isString())
+ target = arguments[1].toString();
+
+ m_workQueue.addWork(new WorkItemLoad(fullURL, WebString::fromUTF8(target)));
+ }
+ result->setNull();
+}
+
+class WorkItemLoadHTMLString : public LayoutTestController::WorkItem {
+public:
+ WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL)
+ : m_html(html)
+ , m_baseURL(baseURL) { }
+ WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL, const WebURL& unreachableURL)
+ : m_html(html)
+ , m_baseURL(baseURL)
+ , m_unreachableURL(unreachableURL) { }
+ bool run(TestShell* shell)
+ {
+ shell->webView()->mainFrame()->loadHTMLString(
+ WebKit::WebData(m_html.data(), m_html.length()), m_baseURL, m_unreachableURL);
+ return true;
+ }
+
+private:
+ std::string m_html;
+ WebURL m_baseURL;
+ WebURL m_unreachableURL;
+};
+
+void LayoutTestController::queueLoadHTMLString(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ string html = arguments[0].toString();
+ WebURL baseURL(GURL(""));
+ if (arguments.size() > 1 && arguments[1].isString())
+ baseURL = WebURL(GURL(arguments[1].toString()));
+ if (arguments.size() > 2 && arguments[2].isString())
+ m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL, WebURL(GURL(arguments[2].toString()))));
+ else
+ m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL));
+ }
+ result->setNull();
+}
+
+void LayoutTestController::objCIdentityIsEqual(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 2) {
+ // This is the best we can do to return an error.
+ result->setNull();
+ return;
+ }
+ result->set(arguments[0].isEqual(arguments[1]));
+}
+
+void LayoutTestController::reset()
+{
+ if (m_shell) {
+ m_shell->webView()->setZoomLevel(false, 0);
+ m_shell->webView()->setTabKeyCyclesThroughElements(true);
+#if !OS(DARWIN) && !OS(WINDOWS) // Actually, TOOLKIT_GTK
+ // (Constants copied because we can't depend on the header that defined
+ // them from this file.)
+ m_shell->webView()->setSelectionColors(0xff1e90ff, 0xff000000, 0xffc8c8c8, 0xff323232);
+#endif
+ m_shell->webView()->removeAllUserContent();
+ }
+ m_dumpAsText = false;
+ m_dumpAsAudio = false;
+ m_dumpCreateView = false;
+ m_dumpEditingCallbacks = false;
+ m_dumpFrameLoadCallbacks = false;
+ m_dumpProgressFinishedCallback = false;
+ m_dumpUserGestureInFrameLoadCallbacks = false;
+ m_dumpResourceLoadCallbacks = false;
+ m_dumpResourceResponseMIMETypes = false;
+ m_dumpBackForwardList = false;
+ m_dumpChildFrameScrollPositions = false;
+ m_dumpChildFramesAsText = false;
+ m_dumpWindowStatusChanges = false;
+ m_dumpSelectionRect = false;
+ m_dumpTitleChanges = false;
+ m_dumpPermissionClientCallbacks = false;
+ m_generatePixelResults = true;
+ m_acceptsEditing = true;
+ m_waitUntilDone = false;
+ m_canOpenWindows = false;
+ m_testRepaint = false;
+ m_sweepHorizontally = false;
+ m_shouldAddFileToPasteboard = false;
+ m_stopProvisionalFrameLoads = false;
+ m_deferMainResourceDataLoad = true;
+ m_globalFlag.set(false);
+ m_webHistoryItemCount.set(0);
+ m_titleTextDirection.set("ltr");
+ m_platformName.set("chromium");
+ m_interceptPostMessage.set(false);
+ m_userStyleSheetLocation = WebURL();
+ m_isPrinting = false;
+
+ webkit_support::SetAcceptAllCookies(false);
+ WebSecurityPolicy::resetOriginAccessWhitelists();
+
+ // Reset the default quota for each origin to 5MB
+ webkit_support::SetDatabaseQuota(5 * 1024 * 1024);
+
+ setlocale(LC_ALL, "");
+
+ if (m_closeRemainingWindows)
+ m_shell->closeRemainingWindows();
+ else
+ m_closeRemainingWindows = true;
+ m_workQueue.reset();
+ m_taskList.revokeAll();
+ m_shouldStayOnPageAfterHandlingBeforeUnload = false;
+}
+
+void LayoutTestController::locationChangeDone()
+{
+ m_webHistoryItemCount.set(m_shell->navigationEntryCount());
+
+ // No more new work after the first complete load.
+ m_workQueue.setFrozen(true);
+
+ if (!m_waitUntilDone)
+ m_workQueue.processWorkSoon();
+}
+
+void LayoutTestController::policyDelegateDone()
+{
+ ASSERT(m_waitUntilDone);
+ m_shell->testFinished();
+ m_waitUntilDone = false;
+}
+
+void LayoutTestController::setCanOpenWindows(const CppArgumentList&, CppVariant* result)
+{
+ m_canOpenWindows = true;
+ result->setNull();
+}
+
+void LayoutTestController::setTabKeyCyclesThroughElements(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->setTabKeyCyclesThroughElements(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void LayoutTestController::windowCount(const CppArgumentList&, CppVariant* result)
+{
+ result->set(static_cast<int>(m_shell->windowCount()));
+}
+
+void LayoutTestController::setCloseRemainingWindowsWhenComplete(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_closeRemainingWindows = arguments[0].value.boolValue;
+ result->setNull();
+}
+
+void LayoutTestController::setAlwaysAcceptCookies(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0)
+ webkit_support::SetAcceptAllCookies(cppVariantToBool(arguments[0]));
+ result->setNull();
+}
+
+void LayoutTestController::setAsynchronousSpellCheckingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setAsynchronousSpellCheckingEnabled(cppVariantToBool(arguments[0]));
+ result->setNull();
+}
+
+void LayoutTestController::showWebInspector(const CppArgumentList&, CppVariant* result)
+{
+ m_shell->showDevTools();
+ result->setNull();
+}
+
+void LayoutTestController::closeWebInspector(const CppArgumentList& args, CppVariant* result)
+{
+ m_shell->closeDevTools();
+ result->setNull();
+}
+
+void LayoutTestController::setWindowIsKey(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->setFocus(m_shell->webView(), arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setUserStyleSheetEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->userStyleSheetLocation = arguments[0].value.boolValue ? m_userStyleSheetLocation : WebURL();
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setUserStyleSheetLocation(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ m_userStyleSheetLocation = webkit_support::LocalFileToDataURL(
+ webkit_support::RewriteLayoutTestsURL(arguments[0].toString()));
+ m_shell->preferences()->userStyleSheetLocation = m_userStyleSheetLocation;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setAuthorAndUserStylesEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->authorAndUserStylesEnabled = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::execCommand(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() <= 0 || !arguments[0].isString())
+ return;
+
+ std::string command = arguments[0].toString();
+ std::string value("");
+ // Ignore the second parameter (which is userInterface)
+ // since this command emulates a manual action.
+ if (arguments.size() >= 3 && arguments[2].isString())
+ value = arguments[2].toString();
+
+ // Note: webkit's version does not return the boolean, so neither do we.
+ m_shell->webView()->focusedFrame()->executeCommand(WebString::fromUTF8(command), WebString::fromUTF8(value));
+}
+
+void LayoutTestController::isCommandEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() <= 0 || !arguments[0].isString()) {
+ result->setNull();
+ return;
+ }
+
+ std::string command = arguments[0].toString();
+ bool rv = m_shell->webView()->focusedFrame()->isCommandEnabled(WebString::fromUTF8(command));
+ result->set(rv);
+}
+
+void LayoutTestController::setPopupBlockingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ bool blockPopups = arguments[0].toBoolean();
+ m_shell->preferences()->javaScriptCanOpenWindowsAutomatically = !blockPopups;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setImagesAllowed(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webPermissions()->setImagesAllowed(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void LayoutTestController::setScriptsAllowed(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webPermissions()->setScriptsAllowed(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void LayoutTestController::setStorageAllowed(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webPermissions()->setStorageAllowed(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void LayoutTestController::setPluginsAllowed(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webPermissions()->setPluginsAllowed(arguments[0].toBoolean());
+ result->setNull();
+}
+
+void LayoutTestController::setUseDashboardCompatibilityMode(const CppArgumentList&, CppVariant* result)
+{
+ // We have no need to support Dashboard Compatibility Mode (mac-only)
+ result->setNull();
+}
+
+void LayoutTestController::clearAllApplicationCaches(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement to support application cache quotas.
+ result->setNull();
+}
+
+void LayoutTestController::clearApplicationCacheForOrigin(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement to support deleting all application cache for an origin.
+ result->setNull();
+}
+
+void LayoutTestController::setApplicationCacheOriginQuota(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement to support application cache quotas.
+ result->setNull();
+}
+
+void LayoutTestController::originsWithApplicationCache(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement to support getting origins that have application caches.
+ result->setNull();
+}
+
+void LayoutTestController::applicationCacheDiskUsageForOrigin(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement to support getting disk usage by all application cache for an origin.
+ result->setNull();
+}
+
+void LayoutTestController::setScrollbarPolicy(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: implement.
+ // Currently only has a non-null implementation on QT.
+ result->setNull();
+}
+
+void LayoutTestController::setCustomPolicyDelegate(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ bool enable = arguments[0].value.boolValue;
+ bool permissive = false;
+ if (arguments.size() > 1 && arguments[1].isBool())
+ permissive = arguments[1].value.boolValue;
+ m_shell->webViewHost()->setCustomPolicyDelegate(enable, permissive);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::waitForPolicyDelegate(const CppArgumentList&, CppVariant* result)
+{
+ m_shell->webViewHost()->waitForPolicyDelegate();
+ m_waitUntilDone = true;
+ result->setNull();
+}
+
+void LayoutTestController::setWillSendRequestClearHeader(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ string header = arguments[0].toString();
+ if (!header.empty())
+ m_shell->webViewHost()->addClearHeader(String::fromUTF8(header.c_str()));
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setWillSendRequestReturnsNullOnRedirect(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setBlockRedirects(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setWillSendRequestReturnsNull(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setRequestReturnNull(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::pathToLocalResource(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() <= 0 || !arguments[0].isString())
+ return;
+
+ string url = arguments[0].toString();
+#if OS(WINDOWS)
+ if (!url.find("/tmp/")) {
+ // We want a temp file.
+ const unsigned tempPrefixLength = 5;
+ size_t bufferSize = MAX_PATH;
+ OwnArrayPtr<WCHAR> tempPath = adoptArrayPtr(new WCHAR[bufferSize]);
+ DWORD tempLength = ::GetTempPathW(bufferSize, tempPath.get());
+ if (tempLength + url.length() - tempPrefixLength + 1 > bufferSize) {
+ bufferSize = tempLength + url.length() - tempPrefixLength + 1;
+ tempPath = adoptArrayPtr(new WCHAR[bufferSize]);
+ tempLength = GetTempPathW(bufferSize, tempPath.get());
+ ASSERT(tempLength < bufferSize);
+ }
+ string resultPath(WebString(tempPath.get(), tempLength).utf8());
+ resultPath.append(url.substr(tempPrefixLength));
+ result->set(resultPath);
+ return;
+ }
+#endif
+
+ // Some layout tests use file://// which we resolve as a UNC path. Normalize
+ // them to just file:///.
+ string lowerUrl = url;
+ transform(lowerUrl.begin(), lowerUrl.end(), lowerUrl.begin(), ::tolower);
+ while (!lowerUrl.find("file:////")) {
+ url = url.substr(0, 8) + url.substr(9);
+ lowerUrl = lowerUrl.substr(0, 8) + lowerUrl.substr(9);
+ }
+ result->set(webkit_support::RewriteLayoutTestsURL(url).spec());
+}
+
+void LayoutTestController::addFileToPasteboardOnDrag(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ m_shouldAddFileToPasteboard = true;
+}
+
+void LayoutTestController::setStopProvisionalFrameLoads(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+ m_stopProvisionalFrameLoads = true;
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setSmartInsertDeleteEnabled(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webViewHost()->setSelectTrailingWhitespaceEnabled(arguments[0].value.boolValue);
+ result->setNull();
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const WebString& animationName, double time, const WebString& elementId)
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return false;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return false;
+
+ WebElement element = webFrame->document().getElementById(elementId);
+ if (element.isNull())
+ return false;
+ return controller->pauseAnimationAtTime(element, animationName, time);
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const WebString& propertyName, double time, const WebString& elementId)
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return false;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return false;
+
+ WebElement element = webFrame->document().getElementById(elementId);
+ if (element.isNull())
+ return false;
+ return controller->pauseTransitionAtTime(element, propertyName, time);
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(const WebString& elementId)
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return false;
+
+ WebElement element = webFrame->document().getElementById(elementId);
+ if (element.isNull() || !element.hasTagName("input"))
+ return false;
+
+ WebInputElement inputElement = element.to<WebInputElement>();
+ return inputElement.autoComplete();
+}
+
+int LayoutTestController::numberOfActiveAnimations()
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return -1;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return -1;
+
+ return controller->numberOfActiveAnimations();
+}
+
+void LayoutTestController::suspendAnimations()
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return;
+
+ controller->suspendAnimations();
+}
+
+void LayoutTestController::resumeAnimations()
+{
+ WebFrame* webFrame = m_shell->webView()->mainFrame();
+ if (!webFrame)
+ return;
+
+ WebAnimationController* controller = webFrame->animationController();
+ if (!controller)
+ return;
+
+ controller->resumeAnimations();
+}
+
+void LayoutTestController::pauseAnimationAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(false);
+ if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) {
+ WebString animationName = cppVariantToWebString(arguments[0]);
+ double time = arguments[1].toDouble();
+ WebString elementId = cppVariantToWebString(arguments[2]);
+ result->set(pauseAnimationAtTimeOnElementWithId(animationName, time, elementId));
+ }
+}
+
+void LayoutTestController::pauseTransitionAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(false);
+ if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) {
+ WebString propertyName = cppVariantToWebString(arguments[0]);
+ double time = arguments[1].toDouble();
+ WebString elementId = cppVariantToWebString(arguments[2]);
+ result->set(pauseTransitionAtTimeOnElementWithId(propertyName, time, elementId));
+ }
+}
+
+void LayoutTestController::elementDoesAutoCompleteForElementWithId(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+ WebString elementId = cppVariantToWebString(arguments[0]);
+ result->set(elementDoesAutoCompleteForElementWithId(elementId));
+}
+
+void LayoutTestController::numberOfActiveAnimations(const CppArgumentList&, CppVariant* result)
+{
+ result->set(numberOfActiveAnimations());
+}
+
+void LayoutTestController::suspendAnimations(const CppArgumentList&, CppVariant* result)
+{
+ suspendAnimations();
+ result->setNull();
+}
+
+void LayoutTestController::resumeAnimations(const CppArgumentList&, CppVariant* result)
+{
+ resumeAnimations();
+ result->setNull();
+}
+
+void LayoutTestController::sampleSVGAnimationForElementAtTime(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 3) {
+ result->setNull();
+ return;
+ }
+ WebString animationId = cppVariantToWebString(arguments[0]);
+ double time = arguments[1].toDouble();
+ WebString elementId = cppVariantToWebString(arguments[2]);
+ bool success = m_shell->webView()->mainFrame()->pauseSVGAnimation(animationId, time, elementId);
+ result->set(success);
+}
+
+void LayoutTestController::disableImageLoading(const CppArgumentList&, CppVariant* result)
+{
+ m_shell->preferences()->loadsImagesAutomatically = false;
+ m_shell->applyPreferences();
+ result->setNull();
+}
+
+void LayoutTestController::setIconDatabaseEnabled(const CppArgumentList&, CppVariant* result)
+{
+ // We don't use the WebKit icon database.
+ result->setNull();
+}
+
+void LayoutTestController::callShouldCloseOnWebView(const CppArgumentList&, CppVariant* result)
+{
+ result->set(m_shell->webView()->dispatchBeforeUnloadEvent());
+}
+
+void LayoutTestController::grantDesktopNotificationPermission(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+#if ENABLE(NOTIFICATIONS)
+ m_shell->notificationPresenter()->grantPermission(cppVariantToWebString(arguments[0]));
+#endif
+ result->set(true);
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+#if ENABLE(NOTIFICATIONS)
+ if (m_shell->notificationPresenter()->simulateClick(cppVariantToWebString(arguments[0])))
+ result->set(true);
+ else
+#endif
+ result->set(false);
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 2 || !arguments[0].isBool() || !arguments[1].isString())
+ return;
+ m_shell->webView()->setDomainRelaxationForbidden(cppVariantToBool(arguments[0]), cppVariantToWebString(arguments[1]));
+}
+
+void LayoutTestController::setDeferMainResourceDataLoad(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() == 1)
+ m_deferMainResourceDataLoad = cppVariantToBool(arguments[0]);
+}
+
+//
+// Unimplemented stubs
+//
+
+void LayoutTestController::dumpAsWebArchive(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::dumpSelectionRect(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_dumpSelectionRect = true;
+ result->setNull();
+}
+
+void LayoutTestController::display(const CppArgumentList& arguments, CppVariant* result)
+{
+ WebViewHost* host = m_shell->webViewHost();
+ const WebKit::WebSize& size = m_shell->webView()->size();
+ WebRect rect(0, 0, size.width, size.height);
+ host->updatePaintRect(rect);
+ host->paintInvalidatedRegion();
+ host->displayRepaintMask();
+ result->setNull();
+}
+
+void LayoutTestController::displayInvalidatedRegion(const CppArgumentList& arguments, CppVariant* result)
+{
+ WebViewHost* host = m_shell->webViewHost();
+ host->paintInvalidatedRegion();
+ host->displayRepaintMask();
+ result->setNull();
+}
+
+void LayoutTestController::testRepaint(const CppArgumentList&, CppVariant* result)
+{
+ m_testRepaint = true;
+ result->setNull();
+}
+
+void LayoutTestController::repaintSweepHorizontally(const CppArgumentList&, CppVariant* result)
+{
+ m_sweepHorizontally = true;
+ result->setNull();
+}
+
+void LayoutTestController::clearBackForwardList(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::keepWebHistory(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::storeWebScriptObject(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::accessStoredWebScriptObject(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::objCClassNameOf(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::addDisallowedURL(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setCallCloseOnWebViews(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::setJavaScriptCanAccessClipboard(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->javaScriptCanAccessClipboard = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setXSSAuditorEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->XSSAuditorEnabled = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() >= 2 && arguments[0].isNumber() && arguments[1].isString()) {
+ WebScriptSource source(cppVariantToWebString(arguments[1]));
+ // This relies on the iframe focusing itself when it loads. This is a bit
+ // sketchy, but it seems to be what other tests do.
+ m_shell->webView()->focusedFrame()->executeScriptInIsolatedWorld(arguments[0].toInt32(), &source, 1, 1);
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setIsolatedWorldSecurityOrigin(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isString())
+ return;
+
+ m_shell->webView()->focusedFrame()->setIsolatedWorldSecurityOrigin(
+ arguments[0].toInt32(),
+ WebSecurityOrigin::createFromString(cppVariantToWebString(arguments[1])));
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->allowUniversalAccessFromFileURLs = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setAllowDisplayOfInsecureContent(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webPermissions()->setDisplayingInsecureContentAllowed(arguments[0].toBoolean());
+
+ result->setNull();
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->allowFileAccessFromFileURLs = arguments[0].value.boolValue;
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::setAllowRunningOfInsecureContent(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webPermissions()->setRunningInsecureContentAllowed(arguments[0].value.boolValue);
+
+ result->setNull();
+}
+
+// Need these conversions because the format of the value for booleans
+// may vary - for example, on mac "1" and "0" are used for boolean.
+bool LayoutTestController::cppVariantToBool(const CppVariant& value)
+{
+ if (value.isBool())
+ return value.toBoolean();
+ if (value.isNumber())
+ return value.toInt32();
+ if (value.isString()) {
+ string valueString = value.toString();
+ if (valueString == "true" || valueString == "1")
+ return true;
+ if (valueString == "false" || valueString == "0")
+ return false;
+ }
+ logErrorToConsole("Invalid value. Expected boolean value.");
+ return false;
+}
+
+int32_t LayoutTestController::cppVariantToInt32(const CppVariant& value)
+{
+ if (value.isNumber())
+ return value.toInt32();
+ if (value.isString()) {
+ string stringSource = value.toString();
+ const char* source = stringSource.data();
+ char* end;
+ long number = strtol(source, &end, 10);
+ if (end == source + stringSource.length() && number >= numeric_limits<int32_t>::min() && number <= numeric_limits<int32_t>::max())
+ return static_cast<int32_t>(number);
+ }
+ logErrorToConsole("Invalid value for preference. Expected integer value.");
+ return 0;
+}
+
+WebString LayoutTestController::cppVariantToWebString(const CppVariant& value)
+{
+ if (!value.isString()) {
+ logErrorToConsole("Invalid value for preference. Expected string value.");
+ return WebString();
+ }
+ return WebString::fromUTF8(value.toString());
+}
+
+Vector<WebString> LayoutTestController::cppVariantToWebStringArray(const CppVariant& value)
+{
+ if (!value.isObject()) {
+ logErrorToConsole("Invalid value for preference. Expected object value.");
+ return Vector<WebString>();
+ }
+ Vector<WebString> resultVector;
+ Vector<string> stringVector = value.toStringVector();
+ for (size_t i = 0; i < stringVector.size(); ++i)
+ resultVector.append(WebString::fromUTF8(stringVector[i].c_str()));
+ return resultVector;
+}
+
+// Sets map based on scriptFontPairs, a collapsed vector of pairs of ISO 15924
+// four-letter script code and font such as:
+// { "Arab", "My Arabic Font", "Grek", "My Greek Font" }
+static void setFontMap(WebPreferences::ScriptFontFamilyMap& map, const Vector<WebString>& scriptFontPairs)
+{
+ map.clear();
+ size_t i = 0;
+ while (i + 1 < scriptFontPairs.size()) {
+ const WebString& script = scriptFontPairs[i++];
+ const WebString& font = scriptFontPairs[i++];
+
+ int32_t code = u_getPropertyValueEnum(UCHAR_SCRIPT, script.utf8().data());
+ if (code >= 0 && code < USCRIPT_CODE_LIMIT)
+ map.set(static_cast<int>(code), font);
+ }
+}
+
+void LayoutTestController::overridePreference(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 2 || !arguments[0].isString())
+ return;
+
+ string key = arguments[0].toString();
+ CppVariant value = arguments[1];
+ WebPreferences* prefs = m_shell->preferences();
+ if (key == "WebKitStandardFont")
+ prefs->standardFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitFixedFont")
+ prefs->fixedFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitSerifFont")
+ prefs->serifFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitSansSerifFont")
+ prefs->sansSerifFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitCursiveFont")
+ prefs->cursiveFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitFantasyFont")
+ prefs->fantasyFontFamily = cppVariantToWebString(value);
+ else if (key == "WebKitStandardFontMap")
+ setFontMap(prefs->standardFontMap, cppVariantToWebStringArray(value));
+ else if (key == "WebKitFixedFontMap")
+ setFontMap(prefs->fixedFontMap, cppVariantToWebStringArray(value));
+ else if (key == "WebKitSerifFontMap")
+ setFontMap(prefs->serifFontMap, cppVariantToWebStringArray(value));
+ else if (key == "WebKitSansSerifFontMap")
+ setFontMap(prefs->sansSerifFontMap, cppVariantToWebStringArray(value));
+ else if (key == "WebKitCursiveFontMap")
+ setFontMap(prefs->cursiveFontMap, cppVariantToWebStringArray(value));
+ else if (key == "WebKitFantasyFontMap")
+ setFontMap(prefs->fantasyFontMap, cppVariantToWebStringArray(value));
+ else if (key == "WebKitDefaultFontSize")
+ prefs->defaultFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitDefaultFixedFontSize")
+ prefs->defaultFixedFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitMinimumFontSize")
+ prefs->minimumFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitMinimumLogicalFontSize")
+ prefs->minimumLogicalFontSize = cppVariantToInt32(value);
+ else if (key == "WebKitDefaultTextEncodingName")
+ prefs->defaultTextEncodingName = cppVariantToWebString(value);
+ else if (key == "WebKitJavaScriptEnabled")
+ prefs->javaScriptEnabled = cppVariantToBool(value);
+ else if (key == "WebKitWebSecurityEnabled")
+ prefs->webSecurityEnabled = cppVariantToBool(value);
+ else if (key == "WebKitJavaScriptCanOpenWindowsAutomatically")
+ prefs->javaScriptCanOpenWindowsAutomatically = cppVariantToBool(value);
+ else if (key == "WebKitDisplayImagesKey")
+ prefs->loadsImagesAutomatically = cppVariantToBool(value);
+ else if (key == "WebKitPluginsEnabled")
+ prefs->pluginsEnabled = cppVariantToBool(value);
+ else if (key == "WebKitDOMPasteAllowedPreferenceKey")
+ prefs->DOMPasteAllowed = cppVariantToBool(value);
+ else if (key == "WebKitDeveloperExtrasEnabledPreferenceKey")
+ prefs->developerExtrasEnabled = cppVariantToBool(value);
+ else if (key == "WebKitShrinksStandaloneImagesToFit")
+ prefs->shrinksStandaloneImagesToFit = cppVariantToBool(value);
+ else if (key == "WebKitTextAreasAreResizable")
+ prefs->textAreasAreResizable = cppVariantToBool(value);
+ else if (key == "WebKitJavaEnabled")
+ prefs->javaEnabled = cppVariantToBool(value);
+ else if (key == "WebKitUsesPageCachePreferenceKey")
+ prefs->usesPageCache = cppVariantToBool(value);
+ else if (key == "WebKitPageCacheSupportsPluginsPreferenceKey")
+ prefs->pageCacheSupportsPlugins = cppVariantToBool(value);
+ else if (key == "WebKitJavaScriptCanAccessClipboard")
+ prefs->javaScriptCanAccessClipboard = cppVariantToBool(value);
+ else if (key == "WebKitXSSAuditorEnabled")
+ prefs->XSSAuditorEnabled = cppVariantToBool(value);
+ else if (key == "WebKitLocalStorageEnabledPreferenceKey")
+ prefs->localStorageEnabled = cppVariantToBool(value);
+ else if (key == "WebKitOfflineWebApplicationCacheEnabled")
+ prefs->offlineWebApplicationCacheEnabled = cppVariantToBool(value);
+ else if (key == "WebKitTabToLinksPreferenceKey")
+ prefs->tabsToLinks = cppVariantToBool(value);
+ else if (key == "WebKitWebGLEnabled")
+ prefs->experimentalWebGLEnabled = cppVariantToBool(value);
+ else if (key == "WebKitHyperlinkAuditingEnabled")
+ prefs->hyperlinkAuditingEnabled = cppVariantToBool(value);
+ else if (key == "WebKitEnableCaretBrowsing")
+ prefs->caretBrowsingEnabled = cppVariantToBool(value);
+ else if (key == "WebKitAllowDisplayingInsecureContent")
+ prefs->allowDisplayOfInsecureContent = cppVariantToBool(value);
+ else if (key == "WebKitAllowRunningInsecureContent")
+ prefs->allowRunningOfInsecureContent = cppVariantToBool(value);
+ else if (key == "WebKitHixie76WebSocketProtocolEnabled")
+ prefs->hixie76WebSocketProtocolEnabled = cppVariantToBool(value);
+ else if (key == "WebKitWebAudioEnabled") {
+ ASSERT(cppVariantToBool(value));
+ } else {
+ string message("Invalid name for preference: ");
+ message.append(key);
+ logErrorToConsole(message);
+ }
+ m_shell->applyPreferences();
+}
+
+void LayoutTestController::fallbackMethod(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on LayoutTestController\n");
+ result->setNull();
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString()
+ || !arguments[2].isString() || !arguments[3].isBool())
+ return;
+
+ WebKit::WebURL url(GURL(arguments[0].toString()));
+ if (!url.isValid())
+ return;
+
+ WebSecurityPolicy::addOriginAccessWhitelistEntry(
+ url,
+ cppVariantToWebString(arguments[1]),
+ cppVariantToWebString(arguments[2]),
+ arguments[3].toBoolean());
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString()
+ || !arguments[2].isString() || !arguments[3].isBool())
+ return;
+
+ WebKit::WebURL url(GURL(arguments[0].toString()));
+ if (!url.isValid())
+ return;
+
+ WebSecurityPolicy::removeOriginAccessWhitelistEntry(
+ url,
+ cppVariantToWebString(arguments[1]),
+ cppVariantToWebString(arguments[2]),
+ arguments[3].toBoolean());
+}
+
+void LayoutTestController::clearAllDatabases(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ webkit_support::ClearAllDatabases();
+}
+
+void LayoutTestController::setDatabaseQuota(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if ((arguments.size() >= 1) && arguments[0].isNumber())
+ webkit_support::SetDatabaseQuota(arguments[0].toInt32());
+}
+
+void LayoutTestController::setPOSIXLocale(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() == 1 && arguments[0].isString())
+ setlocale(LC_ALL, arguments[0].toString().c_str());
+}
+
+void LayoutTestController::counterValueForElementById(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ WebString counterValue = frame->counterValueForElementById(cppVariantToWebString(arguments[0]));
+ if (counterValue.isNull())
+ return;
+ result->set(counterValue.utf8());
+}
+
+// Parse a single argument. The method returns true if there is an argument that
+// is a number or if there is no argument at all. It returns false only if there
+// is some argument that is not a number. The value parameter is filled with the
+// parsed number, or given the default if there is no argument.
+static bool parseCppArgumentInt32(const CppArgumentList& arguments, int argIndex, int* value, int defaultValue)
+{
+ if (static_cast<int>(arguments.size()) > argIndex) {
+ if (!arguments[argIndex].isNumber())
+ return false;
+ *value = arguments[argIndex].toInt32();
+ return true;
+ }
+ *value = defaultValue;
+ return true;
+}
+
+static bool parsePageSizeParameters(const CppArgumentList& arguments,
+ int argOffset,
+ int* pageWidthInPixels,
+ int* pageHeightInPixels)
+{
+ // WebKit is using the window width/height of DumpRenderTree as the
+ // default value of the page size.
+ // FIXME: share the default values with other ports.
+ int argCount = static_cast<int>(arguments.size()) - argOffset;
+ if (argCount && argCount != 2)
+ return false;
+ if (!parseCppArgumentInt32(arguments, argOffset, pageWidthInPixels, 800)
+ || !parseCppArgumentInt32(arguments, argOffset + 1, pageHeightInPixels, 600))
+ return false;
+ return true;
+}
+
+static bool parsePageNumber(const CppArgumentList& arguments, int argOffset, int* pageNumber)
+{
+ if (static_cast<int>(arguments.size()) > argOffset + 1)
+ return false;
+ if (!parseCppArgumentInt32(arguments, argOffset, pageNumber, 0))
+ return false;
+ return true;
+}
+
+static bool parsePageNumberSizeMargins(const CppArgumentList& arguments, int argOffset,
+ int* pageNumber, int* width, int* height,
+ int* marginTop, int* marginRight, int* marginBottom, int* marginLeft)
+{
+ int argCount = static_cast<int>(arguments.size()) - argOffset;
+ if (argCount && argCount != 7)
+ return false;
+ if (!parseCppArgumentInt32(arguments, argOffset, pageNumber, 0)
+ || !parseCppArgumentInt32(arguments, argOffset + 1, width, 0)
+ || !parseCppArgumentInt32(arguments, argOffset + 2, height, 0)
+ || !parseCppArgumentInt32(arguments, argOffset + 3, marginTop, 0)
+ || !parseCppArgumentInt32(arguments, argOffset + 4, marginRight, 0)
+ || !parseCppArgumentInt32(arguments, argOffset + 5, marginBottom, 0)
+ || !parseCppArgumentInt32(arguments, argOffset + 6, marginLeft, 0))
+ return false;
+ return true;
+}
+
+void LayoutTestController::setPrinting(const CppArgumentList& arguments, CppVariant* result)
+{
+ setIsPrinting(true);
+ result->setNull();
+}
+
+void LayoutTestController::pageNumberForElementById(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ int pageWidthInPixels = 0;
+ int pageHeightInPixels = 0;
+ if (!parsePageSizeParameters(arguments, 1,
+ &pageWidthInPixels, &pageHeightInPixels))
+ return;
+ if (!arguments[0].isString())
+ return;
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ result->set(frame->pageNumberForElementById(cppVariantToWebString(arguments[0]),
+ static_cast<float>(pageWidthInPixels),
+ static_cast<float>(pageHeightInPixels)));
+}
+
+void LayoutTestController::pageSizeAndMarginsInPixels(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set("");
+ int pageNumber = 0;
+ int width = 0;
+ int height = 0;
+ int marginTop = 0;
+ int marginRight = 0;
+ int marginBottom = 0;
+ int marginLeft = 0;
+ if (!parsePageNumberSizeMargins(arguments, 0, &pageNumber, &width, &height, &marginTop, &marginRight, &marginBottom,
+ &marginLeft))
+ return;
+
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ WebSize pageSize(width, height);
+ frame->pageSizeAndMarginsInPixels(pageNumber, pageSize, marginTop, marginRight, marginBottom, marginLeft);
+ stringstream resultString;
+ resultString << "(" << pageSize.width << ", " << pageSize.height << ") " << marginTop << " " << marginRight << " "
+ << marginBottom << " " << marginLeft;
+ result->set(resultString.str());
+}
+
+void LayoutTestController::hasCustomPageSizeStyle(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set(false);
+ int pageIndex = 0;
+ if (!parsePageNumber(arguments, 0, &pageIndex))
+ return;
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ result->set(frame->hasCustomPageSizeStyle(pageIndex));
+}
+
+void LayoutTestController::isPageBoxVisible(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ int pageNumber = 0;
+ if (!parsePageNumber(arguments, 0, &pageNumber))
+ return;
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ result->set(frame->isPageBoxVisible(pageNumber));
+}
+
+void LayoutTestController::pageProperty(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->set("");
+ int pageNumber = 0;
+ if (!parsePageNumber(arguments, 1, &pageNumber))
+ return;
+ if (!arguments[0].isString())
+ return;
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ WebSize pageSize(800, 800);
+ frame->printBegin(pageSize);
+ result->set(frame->pageProperty(cppVariantToWebString(arguments[0]), pageNumber).utf8());
+ frame->printEnd();
+}
+
+void LayoutTestController::numberOfPages(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ int pageWidthInPixels = 0;
+ int pageHeightInPixels = 0;
+ if (!parsePageSizeParameters(arguments, 0, &pageWidthInPixels, &pageHeightInPixels))
+ return;
+
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ if (!frame)
+ return;
+ WebSize size(pageWidthInPixels, pageHeightInPixels);
+ int numberOfPages = frame->printBegin(size);
+ frame->printEnd();
+ result->set(numberOfPages);
+}
+
+void LayoutTestController::numberOfPendingGeolocationPermissionRequests(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ Vector<WebViewHost*> windowList = m_shell->windowList();
+ int numberOfRequests = 0;
+ for (size_t i = 0; i < windowList.size(); i++)
+ numberOfRequests += windowList[i]->geolocationClientMock()->numberOfPendingPermissionRequests();
+ result->set(numberOfRequests);
+}
+
+void LayoutTestController::logErrorToConsole(const std::string& text)
+{
+ m_shell->webViewHost()->didAddMessageToConsole(
+ WebConsoleMessage(WebConsoleMessage::LevelError, WebString::fromUTF8(text)),
+ WebString(), 0);
+}
+
+void LayoutTestController::setJavaScriptProfilingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+ m_shell->drtDevToolsAgent()->setJavaScriptProfilingEnabled(arguments[0].toBoolean());
+}
+
+void LayoutTestController::evaluateInWebInspector(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString())
+ return;
+ m_shell->drtDevToolsAgent()->evaluateInWebInspector(arguments[0].toInt32(), arguments[1].toString());
+}
+
+void LayoutTestController::forceRedSelectionColors(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ m_shell->webView()->setSelectionColors(0xffee0000, 0xff00ee00, 0xff000000, 0xffc0c0c0);
+}
+
+void LayoutTestController::addUserScript(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isBool() || !arguments[2].isBool())
+ return;
+ WebView::addUserScript(
+ cppVariantToWebString(arguments[0]), WebVector<WebString>(),
+ arguments[1].toBoolean() ? WebView::UserScriptInjectAtDocumentStart : WebView::UserScriptInjectAtDocumentEnd,
+ arguments[2].toBoolean() ? WebView::UserContentInjectInAllFrames : WebView::UserContentInjectInTopFrameOnly);
+}
+
+void LayoutTestController::addUserStyleSheet(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isString() || !arguments[1].isBool())
+ return;
+ WebView::addUserStyleSheet(
+ cppVariantToWebString(arguments[0]), WebVector<WebString>(),
+ arguments[1].toBoolean() ? WebView::UserContentInjectInAllFrames : WebView::UserContentInjectInTopFrameOnly,
+ // Chromium defaults to InjectInSubsequentDocuments, but for compatibility
+ // with the other ports' DRTs, we use UserStyleInjectInExistingDocuments.
+ WebView::UserStyleInjectInExistingDocuments);
+}
+
+void LayoutTestController::setEditingBehavior(const CppArgumentList& arguments, CppVariant* results)
+{
+ string key = arguments[0].toString();
+ if (key == "mac") {
+ m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorMac;
+ m_shell->applyPreferences();
+ } else if (key == "win") {
+ m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorWin;
+ m_shell->applyPreferences();
+ } else if (key == "unix") {
+ m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorUnix;
+ m_shell->applyPreferences();
+ } else
+ logErrorToConsole("Passed invalid editing behavior. Should be 'mac', 'win', or 'unix'.");
+}
+
+void LayoutTestController::setMockDeviceOrientation(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 6 || !arguments[0].isBool() || !arguments[1].isNumber() || !arguments[2].isBool() || !arguments[3].isNumber() || !arguments[4].isBool() || !arguments[5].isNumber())
+ return;
+
+ WebDeviceOrientation orientation(arguments[0].toBoolean(), arguments[1].toDouble(), arguments[2].toBoolean(), arguments[3].toDouble(), arguments[4].toBoolean(), arguments[5].toDouble());
+ // Note that we only call setOrientation on the main page's mock since this is all that the
+ // tests require. If necessary, we could get a list of WebViewHosts from the TestShell and
+ // call setOrientation on each DeviceOrientationClientMock.
+ m_shell->webViewHost()->deviceOrientationClientMock()->setOrientation(orientation);
+}
+
+// FIXME: For greater test flexibility, we should be able to set each page's geolocation mock individually.
+// https://bugs.webkit.org/show_bug.cgi?id=52368
+void LayoutTestController::setGeolocationPermission(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+ Vector<WebViewHost*> windowList = m_shell->windowList();
+ for (size_t i = 0; i < windowList.size(); i++)
+ windowList[i]->geolocationClientMock()->setPermission(arguments[0].toBoolean());
+}
+
+void LayoutTestController::setMockGeolocationPosition(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber())
+ return;
+ Vector<WebViewHost*> windowList = m_shell->windowList();
+ for (size_t i = 0; i < windowList.size(); i++)
+ windowList[i]->geolocationClientMock()->setPosition(arguments[0].toDouble(), arguments[1].toDouble(), arguments[2].toDouble());
+}
+
+void LayoutTestController::setMockGeolocationError(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString())
+ return;
+ Vector<WebViewHost*> windowList = m_shell->windowList();
+ for (size_t i = 0; i < windowList.size(); i++)
+ windowList[i]->geolocationClientMock()->setError(arguments[0].toInt32(), cppVariantToWebString(arguments[1]));
+}
+
+void LayoutTestController::abortModal(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+}
+
+void LayoutTestController::addMockSpeechInputResult(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isNumber() || !arguments[2].isString())
+ return;
+
+ if (WebSpeechInputControllerMock* controller = m_shell->webViewHost()->speechInputControllerMock())
+ controller->addMockRecognitionResult(cppVariantToWebString(arguments[0]), arguments[1].toDouble(), cppVariantToWebString(arguments[2]));
+}
+
+void LayoutTestController::startSpeechInput(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 1)
+ return;
+
+ WebElement element;
+ if (!WebBindings::getElement(arguments[0].value.objectValue, &element))
+ return;
+
+ WebInputElement* input = toWebInputElement(&element);
+ if (!input)
+ return;
+
+ if (!input->isSpeechInputEnabled())
+ return;
+
+ input->startSpeechInput();
+}
+
+void LayoutTestController::layerTreeAsText(const CppArgumentList& args, CppVariant* result)
+{
+ result->set(m_shell->webView()->mainFrame()->layerTreeAsText(m_showDebugLayerTree).utf8());
+}
+
+void LayoutTestController::loseCompositorContext(const CppArgumentList& args, CppVariant*)
+{
+ int numTimes;
+ if (args.size() == 1 || !args[0].isNumber())
+ numTimes = 1;
+ else
+ numTimes = args[0].toInt32();
+ m_shell->webView()->loseCompositorContext(numTimes);
+}
+
+void LayoutTestController::markerTextForListItem(const CppArgumentList& args, CppVariant* result)
+{
+ WebElement element;
+ if (!WebBindings::getElement(args[0].value.objectValue, &element))
+ result->setNull();
+ else
+ result->set(element.document().frame()->markerTextForListItem(element).utf8());
+}
+
+void LayoutTestController::hasSpellingMarker(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+ result->set(m_shell->webView()->mainFrame()->selectionStartHasSpellingMarkerFor(arguments[0].toInt32(), arguments[1].toInt32()));
+}
+
+void LayoutTestController::findString(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+
+ WebFindOptions findOptions;
+ bool wrapAround = false;
+ if (arguments.size() >= 2) {
+ Vector<std::string> optionsArray = arguments[1].toStringVector();
+ findOptions.matchCase = true;
+
+ for (size_t i = 0; i < optionsArray.size(); ++i) {
+ const std::string& option = optionsArray[i];
+ // FIXME: Support all the options, so we can run findString.html too.
+ if (option == "CaseInsensitive")
+ findOptions.matchCase = false;
+ else if (option == "Backwards")
+ findOptions.forward = false;
+ else if (option == "WrapAround")
+ wrapAround = true;
+ }
+ }
+
+ WebFrame* frame = m_shell->webView()->mainFrame();
+ const bool findResult = frame->find(0, cppVariantToWebString(arguments[0]), findOptions, wrapAround, 0);
+ result->set(findResult);
+}
+
+void LayoutTestController::setMinimumTimerInterval(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isNumber())
+ return;
+ m_shell->webView()->settings()->setMinimumTimerInterval(arguments[0].toDouble());
+}
+
+void LayoutTestController::setAutofilled(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 2 || !arguments[1].isBool())
+ return;
+
+ WebElement element;
+ if (!WebBindings::getElement(arguments[0].value.objectValue, &element))
+ return;
+
+ WebInputElement* input = toWebInputElement(&element);
+ if (!input)
+ return;
+
+ input->setAutofilled(arguments[1].value.boolValue);
+}
+
+void LayoutTestController::setValueForUser(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 2)
+ return;
+
+ WebElement element;
+ if (!WebBindings::getElement(arguments[0].value.objectValue, &element))
+ return;
+
+ WebInputElement* input = toWebInputElement(&element);
+ if (!input)
+ return;
+
+ input->setValue(cppVariantToWebString(arguments[1]), true);
+}
+
+void LayoutTestController::deleteAllLocalStorage(const CppArgumentList& arguments, CppVariant*)
+{
+ // Not Implemented
+}
+
+void LayoutTestController::localStorageDiskUsageForOrigin(const CppArgumentList& arguments, CppVariant*)
+{
+ // Not Implemented
+}
+
+void LayoutTestController::originsWithLocalStorage(const CppArgumentList& arguments, CppVariant*)
+{
+ // Not Implemented
+}
+
+void LayoutTestController::deleteLocalStorageForOrigin(const CppArgumentList& arguments, CppVariant*)
+{
+ // Not Implemented
+}
+
+void LayoutTestController::observeStorageTrackerNotifications(const CppArgumentList&, CppVariant*)
+{
+ // Not Implemented
+}
+
+void LayoutTestController::syncLocalStorage(const CppArgumentList&, CppVariant*)
+{
+ // Not Implemented
+}
+
+void LayoutTestController::setShouldStayOnPageAfterHandlingBeforeUnload(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() == 1 && arguments[0].isBool())
+ m_shouldStayOnPageAfterHandlingBeforeUnload = arguments[0].toBoolean();
+
+ result->setNull();
+}
+
+void LayoutTestController::enableFixedLayoutMode(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+ bool enableFixedLayout = arguments[0].toBoolean();
+ m_shell->webView()->enableFixedLayoutMode(enableFixedLayout);
+}
+
+void LayoutTestController::setFixedLayoutSize(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+ int width = arguments[0].toInt32();
+ int height = arguments[1].toInt32();
+ m_shell->webView()->setFixedLayoutSize(WebSize(width, height));
+}
+
+void LayoutTestController::setPluginsEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isBool()) {
+ m_shell->preferences()->pluginsEnabled = arguments[0].toBoolean();
+ m_shell->applyPreferences();
+ }
+ result->setNull();
+}
+
+void LayoutTestController::resetPageVisibility(const CppArgumentList& arguments, CppVariant* result)
+{
+ m_shell->webView()->setVisibilityState(WebPageVisibilityStateVisible, true);
+}
+
+void LayoutTestController::setPageVisibility(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ string newVisibility = arguments[0].toString();
+ if (newVisibility == "visible")
+ m_shell->webView()->setVisibilityState(WebPageVisibilityStateVisible, false);
+ else if (newVisibility == "hidden")
+ m_shell->webView()->setVisibilityState(WebPageVisibilityStateHidden, false);
+ else if (newVisibility == "prerender")
+ m_shell->webView()->setVisibilityState(WebPageVisibilityStatePrerender, false);
+ }
+}
+
+void LayoutTestController::setTextDirection(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() != 1 || !arguments[0].isString())
+ return;
+
+ // Map a direction name to a WebTextDirection value.
+ std::string directionName = arguments[0].toString();
+ WebKit::WebTextDirection direction;
+ if (directionName == "auto")
+ direction = WebKit::WebTextDirectionDefault;
+ else if (directionName == "rtl")
+ direction = WebKit::WebTextDirectionRightToLeft;
+ else if (directionName == "ltr")
+ direction = WebKit::WebTextDirectionLeftToRight;
+ else
+ return;
+
+ m_shell->webView()->setTextDirection(direction);
+}
+
+void LayoutTestController::setAudioData(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isObject())
+ return;
+
+ // Check that passed-in object is, in fact, an ArrayBufferView.
+ NPObject* npobject = NPVARIANT_TO_OBJECT(arguments[0]);
+ if (!npobject)
+ return;
+ if (!WebBindings::getArrayBufferView(npobject, &m_audioData))
+ return;
+
+ setShouldDumpAsAudio(true);
+}
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.h b/Tools/DumpRenderTree/chromium/LayoutTestController.h
new file mode 100644
index 000000000..71b1b4226
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/LayoutTestController.h
@@ -0,0 +1,701 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * 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.
+ */
+
+/*
+ LayoutTestController class:
+ Bound to a JavaScript window.layoutTestController object using the
+ CppBoundClass::bindToJavascript(), this allows layout tests that are run in
+ the test_shell (or, in principle, any web page loaded into a client app built
+ with this class) to control various aspects of how the tests are run and what
+ sort of output they produce.
+*/
+
+#ifndef LayoutTestController_h
+#define LayoutTestController_h
+
+#include "CppBoundClass.h"
+#include "Task.h"
+#include "platform/WebArrayBufferView.h"
+#include "platform/WebString.h"
+#include "WebTextDirection.h"
+#include "platform/WebURL.h"
+#include <wtf/Deque.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebKit {
+class WebGeolocationClientMock;
+class WebSpeechInputController;
+class WebSpeechInputControllerMock;
+class WebSpeechInputListener;
+}
+
+namespace webkit_support {
+class ScopedTempDirectory;
+}
+
+class TestShell;
+
+class LayoutTestController : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ LayoutTestController(TestShell*);
+
+ ~LayoutTestController();
+
+ // This function sets a flag that tells the test_shell to dump pages as
+ // plain text, rather than as a text representation of the renderer's state.
+ // It takes an optional argument, whether to dump pixels results or not.
+ void dumpAsText(const CppArgumentList&, CppVariant*);
+
+ // This function should set a flag that tells the test_shell to print a line
+ // of descriptive text for each database command. It should take no
+ // arguments, and ignore any that may be present. However, at the moment, we
+ // don't have any DB function that prints messages, so for now this function
+ // doesn't do anything.
+ void dumpDatabaseCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for each editing command. It takes no arguments, and
+ // ignores any that may be present.
+ void dumpEditingCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for each frame load callback. It takes no arguments, and
+ // ignores any that may be present.
+ void dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // descriptive text for the progress finished callback. It takes no
+ // arguments, and ignores any that may be present.
+ void dumpProgressFinishedCallback(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print a line of
+ // user gesture status text for some frame load callbacks. It takes no
+ // arguments, and ignores any that may be present.
+ void dumpUserGestureInFrameLoadCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print out a text
+ // representation of the back/forward list. It ignores all arguments.
+ void dumpBackForwardList(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to print out the
+ // scroll offsets of the child frames. It ignores all.
+ void dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to recursively
+ // dump all frames as plain text if the dumpAsText flag is set.
+ // It takes no arguments, and ignores any that may be present.
+ void dumpChildFramesAsText(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump a descriptive
+ // line for each resource load callback. It takes no arguments, and ignores
+ // any that may be present.
+ void dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump the MIME type
+ // for each resource that was loaded. It takes no arguments, and ignores any
+ // that may be present.
+ void dumpResourceResponseMIMETypes(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump all calls
+ // to window.status().
+ // It takes no arguments, and ignores any that may be present.
+ void dumpWindowStatusChanges(const CppArgumentList&, CppVariant*);
+
+ // This function sets a flag that tells the test_shell to dump all calls to
+ // WebViewClient::createView().
+ // It takes no arguments, and ignores any that may be present.
+ void dumpCreateView(const CppArgumentList&, CppVariant*);
+
+ // When called with a boolean argument, this sets a flag that controls
+ // whether content-editable elements accept editing focus when an editing
+ // attempt is made. It ignores any additional arguments.
+ void setAcceptsEditing(const CppArgumentList&, CppVariant*);
+
+ // Functions for dealing with windows. By default we block all new windows.
+ void windowCount(const CppArgumentList&, CppVariant*);
+ void setCanOpenWindows(const CppArgumentList&, CppVariant*);
+ void setCloseRemainingWindowsWhenComplete(const CppArgumentList&, CppVariant*);
+
+ // By default, tests end when page load is complete. These methods are used
+ // to delay the completion of the test until notifyDone is called.
+ void waitUntilDone(const CppArgumentList&, CppVariant*);
+ void notifyDone(const CppArgumentList&, CppVariant*);
+
+ // Methods for adding actions to the work queue. Used in conjunction with
+ // waitUntilDone/notifyDone above.
+ void queueBackNavigation(const CppArgumentList&, CppVariant*);
+ void queueForwardNavigation(const CppArgumentList&, CppVariant*);
+ void queueReload(const CppArgumentList&, CppVariant*);
+ void queueLoadingScript(const CppArgumentList&, CppVariant*);
+ void queueNonLoadingScript(const CppArgumentList&, CppVariant*);
+ void queueLoad(const CppArgumentList&, CppVariant*);
+ void queueLoadHTMLString(const CppArgumentList&, CppVariant*);
+
+ // Although this is named "objC" to match the Mac version, it actually tests
+ // the identity of its two arguments in C++.
+ void objCIdentityIsEqual(const CppArgumentList&, CppVariant*);
+
+ // Changes the cookie policy from the default to allow all cookies.
+ void setAlwaysAcceptCookies(const CppArgumentList&, CppVariant*);
+
+ // Changes asynchronous spellchecking flag on the settings.
+ void setAsynchronousSpellCheckingEnabled(const CppArgumentList&, CppVariant*);
+
+ // Shows DevTools window.
+ void showWebInspector(const CppArgumentList&, CppVariant*);
+ void closeWebInspector(const CppArgumentList&, CppVariant*);
+
+ // Gives focus to the window.
+ void setWindowIsKey(const CppArgumentList&, CppVariant*);
+
+ // Method that controls whether pressing Tab key cycles through page elements
+ // or inserts a '\t' char in text area
+ void setTabKeyCyclesThroughElements(const CppArgumentList&, CppVariant*);
+
+ // Passes through to WebPreferences which allows the user to have a custom
+ // style sheet.
+ void setUserStyleSheetEnabled(const CppArgumentList&, CppVariant*);
+ void setUserStyleSheetLocation(const CppArgumentList&, CppVariant*);
+
+ // Passes this preference through to WebSettings.
+ void setAuthorAndUserStylesEnabled(const CppArgumentList&, CppVariant*);
+
+ // Puts Webkit in "dashboard compatibility mode", which is used in obscure
+ // Mac-only circumstances. It's not really necessary, and will most likely
+ // never be used by Chrome, but some layout tests depend on its presence.
+ void setUseDashboardCompatibilityMode(const CppArgumentList&, CppVariant*);
+
+ void setScrollbarPolicy(const CppArgumentList&, CppVariant*);
+
+ // Causes navigation actions just printout the intended navigation instead
+ // of taking you to the page. This is used for cases like mailto, where you
+ // don't actually want to open the mail program.
+ void setCustomPolicyDelegate(const CppArgumentList&, CppVariant*);
+
+ // Delays completion of the test until the policy delegate runs.
+ void waitForPolicyDelegate(const CppArgumentList&, CppVariant*);
+
+ // Causes WillSendRequest to clear certain headers.
+ void setWillSendRequestClearHeader(const CppArgumentList&, CppVariant*);
+
+ // Causes WillSendRequest to block redirects.
+ void setWillSendRequestReturnsNullOnRedirect(const CppArgumentList&, CppVariant*);
+
+ // Causes WillSendRequest to return an empty request.
+ void setWillSendRequestReturnsNull(const CppArgumentList&, CppVariant*);
+
+ // Converts a URL starting with file:///tmp/ to the local mapping.
+ void pathToLocalResource(const CppArgumentList&, CppVariant*);
+
+ // Sets a bool such that when a drag is started, we fill the drag clipboard
+ // with a fake file object.
+ void addFileToPasteboardOnDrag(const CppArgumentList&, CppVariant*);
+
+ // Executes an internal command (superset of document.execCommand() commands).
+ void execCommand(const CppArgumentList&, CppVariant*);
+
+ // Checks if an internal command is currently available.
+ void isCommandEnabled(const CppArgumentList&, CppVariant*);
+
+ // Set the WebPreference that controls webkit's popup blocking.
+ void setPopupBlockingEnabled(const CppArgumentList&, CppVariant*);
+
+ // If true, causes provisional frame loads to be stopped for the remainder of
+ // the test.
+ void setStopProvisionalFrameLoads(const CppArgumentList&, CppVariant*);
+
+ // Enable or disable smart insert/delete. This is enabled by default.
+ void setSmartInsertDeleteEnabled(const CppArgumentList&, CppVariant*);
+
+ // Enable or disable trailing whitespace selection on double click.
+ void setSelectTrailingWhitespaceEnabled(const CppArgumentList&, CppVariant*);
+
+ void pauseAnimationAtTimeOnElementWithId(const CppArgumentList&, CppVariant*);
+ void pauseTransitionAtTimeOnElementWithId(const CppArgumentList&, CppVariant*);
+ void elementDoesAutoCompleteForElementWithId(const CppArgumentList&, CppVariant*);
+ void numberOfActiveAnimations(const CppArgumentList&, CppVariant*);
+ void suspendAnimations(const CppArgumentList&, CppVariant*);
+ void resumeAnimations(const CppArgumentList&, CppVariant*);
+ void sampleSVGAnimationForElementAtTime(const CppArgumentList&, CppVariant*);
+ void disableImageLoading(const CppArgumentList&, CppVariant*);
+ void setIconDatabaseEnabled(const CppArgumentList&, CppVariant*);
+ void dumpSelectionRect(const CppArgumentList&, CppVariant*);
+
+ // Grants permission for desktop notifications to an origin
+ void grantDesktopNotificationPermission(const CppArgumentList&, CppVariant*);
+ // Simulates a click on a desktop notification.
+ void simulateDesktopNotificationClick(const CppArgumentList&, CppVariant*);
+
+ void setDomainRelaxationForbiddenForURLScheme(const CppArgumentList&, CppVariant*);
+ void setDeferMainResourceDataLoad(const CppArgumentList&, CppVariant*);
+ void setEditingBehavior(const CppArgumentList&, CppVariant*);
+
+ // Deals with Web Audio WAV file data.
+ void setAudioData(const CppArgumentList&, CppVariant*);
+ const WebKit::WebArrayBufferView& audioData() const { return m_audioData; }
+
+ // The following are only stubs.
+ // FIXME: Implement any of these that are needed to pass the layout tests.
+ void dumpAsWebArchive(const CppArgumentList&, CppVariant*);
+ void dumpTitleChanges(const CppArgumentList&, CppVariant*);
+ void setMainFrameIsFirstResponder(const CppArgumentList&, CppVariant*);
+ void display(const CppArgumentList&, CppVariant*);
+ void displayInvalidatedRegion(const CppArgumentList&, CppVariant*);
+ void testRepaint(const CppArgumentList&, CppVariant*);
+ void repaintSweepHorizontally(const CppArgumentList&, CppVariant*);
+ void clearBackForwardList(const CppArgumentList&, CppVariant*);
+ void keepWebHistory(const CppArgumentList&, CppVariant*);
+ void storeWebScriptObject(const CppArgumentList&, CppVariant*);
+ void accessStoredWebScriptObject(const CppArgumentList&, CppVariant*);
+ void objCClassNameOf(const CppArgumentList&, CppVariant*);
+ void addDisallowedURL(const CppArgumentList&, CppVariant*);
+ void callShouldCloseOnWebView(const CppArgumentList&, CppVariant*);
+ void setCallCloseOnWebViews(const CppArgumentList&, CppVariant*);
+ void setPrivateBrowsingEnabled(const CppArgumentList&, CppVariant*);
+
+ void setJavaScriptCanAccessClipboard(const CppArgumentList&, CppVariant*);
+ void setXSSAuditorEnabled(const CppArgumentList&, CppVariant*);
+ void overridePreference(const CppArgumentList&, CppVariant*);
+ void setAllowUniversalAccessFromFileURLs(const CppArgumentList&, CppVariant*);
+ void setAllowDisplayOfInsecureContent(const CppArgumentList&, CppVariant*);
+ void setAllowFileAccessFromFileURLs(const CppArgumentList&, CppVariant*);
+ void setAllowRunningOfInsecureContent(const CppArgumentList&, CppVariant*);
+
+ void evaluateScriptInIsolatedWorld(const CppArgumentList&, CppVariant*);
+ void setIsolatedWorldSecurityOrigin(const CppArgumentList&, CppVariant*);
+
+ // The fallback method is called when a nonexistent method is called on
+ // the layout test controller object.
+ // It is usefull to catch typos in the JavaScript code (a few layout tests
+ // do have typos in them) and it allows the script to continue running in
+ // that case (as the Mac does).
+ void fallbackMethod(const CppArgumentList&, CppVariant*);
+
+ // Allows layout tests to manage origins' whitelisting.
+ void addOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*);
+ void removeOriginAccessWhitelistEntry(const CppArgumentList&, CppVariant*);
+
+ // Clears all application caches.
+ void clearAllApplicationCaches(const CppArgumentList&, CppVariant*);
+ // Clears an application cache for an origin.
+ void clearApplicationCacheForOrigin(const CppArgumentList&, CppVariant*);
+ // Returns origins that have application caches.
+ void originsWithApplicationCache(const CppArgumentList&, CppVariant*);
+ // Sets the application cache quota for the localhost origin.
+ void setApplicationCacheOriginQuota(const CppArgumentList&, CppVariant*);
+ // Returns disk usage by all application caches for an origin.
+ void applicationCacheDiskUsageForOrigin(const CppArgumentList&, CppVariant*);
+
+ // Clears all databases.
+ void clearAllDatabases(const CppArgumentList&, CppVariant*);
+ // Sets the default quota for all origins
+ void setDatabaseQuota(const CppArgumentList&, CppVariant*);
+
+ // Calls setlocale(LC_ALL, ...) for a specified locale.
+ // Resets between tests.
+ void setPOSIXLocale(const CppArgumentList&, CppVariant*);
+
+ // Gets the value of the counter in the element specified by its ID.
+ void counterValueForElementById(const CppArgumentList&, CppVariant*);
+
+ // Causes layout to happen as if targetted to printed pages.
+ void setPrinting(const CppArgumentList&, CppVariant*);
+
+ // Gets the number of page where the specified element will be put.
+ void pageNumberForElementById(const CppArgumentList&, CppVariant*);
+
+ // Gets the page size and margins for a printed page.
+ void pageSizeAndMarginsInPixels(const CppArgumentList&, CppVariant*);
+
+ // Returns true if the current page box has custom page size style for
+ // printing.
+ void hasCustomPageSizeStyle(const CppArgumentList&, CppVariant*);
+
+ // Returns the visibililty status of a page box for printing
+ void isPageBoxVisible(const CppArgumentList&, CppVariant*);
+
+ // Gets the page-related property for printed content
+ void pageProperty(const CppArgumentList&, CppVariant*);
+
+ // Gets the number of pages to be printed.
+ void numberOfPages(const CppArgumentList&, CppVariant*);
+
+ // Gets the number of geolocation permissions requests pending.
+ void numberOfPendingGeolocationPermissionRequests(const CppArgumentList&, CppVariant*);
+
+ // Allows layout tests to start JavaScript profiling.
+ void setJavaScriptProfilingEnabled(const CppArgumentList&, CppVariant*);
+
+ // Allows layout tests to exec scripts at WebInspector side.
+ void evaluateInWebInspector(const CppArgumentList&, CppVariant*);
+
+ // Forces the selection colors for testing under Linux.
+ void forceRedSelectionColors(const CppArgumentList&, CppVariant*);
+
+ // Adds a user script or user style sheet to be injected into new documents.
+ void addUserScript(const CppArgumentList&, CppVariant*);
+ void addUserStyleSheet(const CppArgumentList&, CppVariant*);
+
+ // DeviceOrientation related functions
+ void setMockDeviceOrientation(const CppArgumentList&, CppVariant*);
+
+ // Geolocation related functions.
+ void setGeolocationPermission(const CppArgumentList&, CppVariant*);
+ void setMockGeolocationPosition(const CppArgumentList&, CppVariant*);
+ void setMockGeolocationError(const CppArgumentList&, CppVariant*);
+
+ // Empty stub method to keep parity with object model exposed by global LayoutTestController.
+ void abortModal(const CppArgumentList&, CppVariant*);
+
+ // Speech input related functions.
+ void addMockSpeechInputResult(const CppArgumentList&, CppVariant*);
+ void startSpeechInput(const CppArgumentList&, CppVariant*);
+
+ void layerTreeAsText(const CppArgumentList& args, CppVariant* result);
+
+ void loseCompositorContext(const CppArgumentList& args, CppVariant* result);
+
+ void markerTextForListItem(const CppArgumentList&, CppVariant*);
+ void hasSpellingMarker(const CppArgumentList&, CppVariant*);
+ void findString(const CppArgumentList&, CppVariant*);
+
+ void setMinimumTimerInterval(const CppArgumentList&, CppVariant*);
+
+ // Expects the first argument to be an input element and the second argument to be a boolean.
+ // Forwards the setAutofilled() call to the element.
+ void setAutofilled(const CppArgumentList&, CppVariant*);
+
+ // Expects the first argument to be an input element and the second argument to be a string value.
+ // Forwards the setValueForUser() call to the element.
+ void setValueForUser(const CppArgumentList&, CppVariant*);
+
+ // LocalStorage origin-related
+ void deleteAllLocalStorage(const CppArgumentList&, CppVariant*);
+ void originsWithLocalStorage(const CppArgumentList&, CppVariant*);
+ void deleteLocalStorageForOrigin(const CppArgumentList&, CppVariant*);
+ void localStorageDiskUsageForOrigin(const CppArgumentList&, CppVariant*);
+ void observeStorageTrackerNotifications(const CppArgumentList&, CppVariant*);
+ void syncLocalStorage(const CppArgumentList&, CppVariant*);
+
+ // WebPermissionClient related.
+ void setImagesAllowed(const CppArgumentList&, CppVariant*);
+ void setScriptsAllowed(const CppArgumentList&, CppVariant*);
+ void setStorageAllowed(const CppArgumentList&, CppVariant*);
+ void setPluginsAllowed(const CppArgumentList&, CppVariant*);
+ void dumpPermissionClientCallbacks(const CppArgumentList&, CppVariant*);
+
+ // Enable or disable plugins.
+ void setPluginsEnabled(const CppArgumentList&, CppVariant*);
+
+ // Switch the visibility of the page.
+ void setPageVisibility(const CppArgumentList&, CppVariant*);
+ void resetPageVisibility(const CppArgumentList&, CppVariant*);
+
+ // Changes the direction of the focused element.
+ void setTextDirection(const CppArgumentList&, CppVariant*);
+
+ void setShouldStayOnPageAfterHandlingBeforeUnload(const CppArgumentList&, CppVariant*);
+
+ void enableFixedLayoutMode(const CppArgumentList&, CppVariant*);
+ void setFixedLayoutSize(const CppArgumentList&, CppVariant*);
+
+public:
+ // The following methods are not exposed to JavaScript.
+ void setWorkQueueFrozen(bool frozen) { m_workQueue.setFrozen(frozen); }
+
+ WebKit::WebSpeechInputController* speechInputController(WebKit::WebSpeechInputListener*);
+ bool shouldDumpAsAudio() const { return m_dumpAsAudio; }
+ void setShouldDumpAsAudio(bool dumpAsAudio) { m_dumpAsAudio = dumpAsAudio; }
+ bool shouldDumpAsText() { return m_dumpAsText; }
+ void setShouldDumpAsText(bool value) { m_dumpAsText = value; }
+ bool shouldDumpEditingCallbacks() { return m_dumpEditingCallbacks; }
+ bool shouldDumpFrameLoadCallbacks() { return m_dumpFrameLoadCallbacks; }
+ void setShouldDumpFrameLoadCallbacks(bool value) { m_dumpFrameLoadCallbacks = value; }
+ bool shouldDumpProgressFinishedCallback() { return m_dumpProgressFinishedCallback; }
+ void setShouldDumpProgressFinishedCallback(bool value) { m_dumpProgressFinishedCallback = value; }
+ bool shouldDumpUserGestureInFrameLoadCallbacks() { return m_dumpUserGestureInFrameLoadCallbacks; }
+ void setShouldDumpUserGestureInFrameLoadCallbacks(bool value) { m_dumpUserGestureInFrameLoadCallbacks = value; }
+ bool shouldDumpResourceLoadCallbacks() {return m_dumpResourceLoadCallbacks; }
+ void setShouldDumpResourceResponseMIMETypes(bool value) { m_dumpResourceResponseMIMETypes = value; }
+ bool shouldDumpResourceResponseMIMETypes() {return m_dumpResourceResponseMIMETypes; }
+ bool shouldDumpStatusCallbacks() { return m_dumpWindowStatusChanges; }
+ bool shouldDumpSelectionRect() { return m_dumpSelectionRect; }
+ bool shouldDumpBackForwardList() { return m_dumpBackForwardList; }
+ bool shouldDumpTitleChanges() { return m_dumpTitleChanges; }
+ bool shouldDumpPermissionClientCallbacks() { return m_dumpPermissionClientCallbacks; }
+ bool shouldDumpChildFrameScrollPositions() { return m_dumpChildFrameScrollPositions; }
+ bool shouldDumpChildFramesAsText() { return m_dumpChildFramesAsText; }
+ bool shouldGeneratePixelResults() { return m_generatePixelResults; }
+ void setShouldGeneratePixelResults(bool value) { m_generatePixelResults = value; }
+ bool shouldDumpCreateView() { return m_dumpCreateView; }
+ bool acceptsEditing() { return m_acceptsEditing; }
+ bool canOpenWindows() { return m_canOpenWindows; }
+ bool shouldAddFileToPasteboard() { return m_shouldAddFileToPasteboard; }
+ bool stopProvisionalFrameLoads() { return m_stopProvisionalFrameLoads; }
+ bool deferMainResourceDataLoad() { return m_deferMainResourceDataLoad; }
+ void setShowDebugLayerTree(bool value) { m_showDebugLayerTree = value; }
+ void setTitleTextDirection(WebKit::WebTextDirection dir)
+ {
+ m_titleTextDirection.set(dir == WebKit::WebTextDirectionLeftToRight ? "ltr" : "rtl");
+ }
+
+ bool shouldInterceptPostMessage()
+ {
+ return m_interceptPostMessage.isBool() && m_interceptPostMessage.toBoolean();
+ }
+
+ void setIsPrinting(bool value) { m_isPrinting = value; }
+ bool isPrinting() { return m_isPrinting; }
+
+ bool testRepaint() const { return m_testRepaint; }
+ bool sweepHorizontally() const { return m_sweepHorizontally; }
+
+ // Called by the webview delegate when the toplevel frame load is done.
+ void locationChangeDone();
+
+ // Called by the webview delegate when the policy delegate runs if the
+ // waitForPolicyDelegate was called.
+ void policyDelegateDone();
+
+ // Reinitializes all static values. The reset() method should be called
+ // before the start of each test (currently from TestShell::runFileTest).
+ void reset();
+
+ // A single item in the work queue.
+ class WorkItem {
+ public:
+ virtual ~WorkItem() { }
+
+ // Returns true if this started a load.
+ virtual bool run(TestShell*) = 0;
+ };
+
+ TaskList* taskList() { return &m_taskList; }
+
+ bool shouldStayOnPageAfterHandlingBeforeUnload() const { return m_shouldStayOnPageAfterHandlingBeforeUnload; }
+
+private:
+ friend class WorkItem;
+ friend class WorkQueue;
+
+ // Helper class for managing events queued by methods like queueLoad or
+ // queueScript.
+ class WorkQueue {
+ public:
+ WorkQueue(LayoutTestController* controller) : m_frozen(false), m_controller(controller) { }
+ virtual ~WorkQueue();
+ void processWorkSoon();
+
+ // Reset the state of the class between tests.
+ void reset();
+
+ void addWork(WorkItem*);
+
+ void setFrozen(bool frozen) { m_frozen = frozen; }
+ bool isEmpty() { return m_queue.isEmpty(); }
+ TaskList* taskList() { return &m_taskList; }
+
+ private:
+ void processWork();
+ class WorkQueueTask: public MethodTask<WorkQueue> {
+ public:
+ WorkQueueTask(WorkQueue* object): MethodTask<WorkQueue>(object) { }
+ virtual void runIfValid() { m_object->processWork(); }
+ };
+
+ TaskList m_taskList;
+ Deque<WorkItem*> m_queue;
+ bool m_frozen;
+ LayoutTestController* m_controller;
+ };
+
+ // Support for overridePreference.
+ bool cppVariantToBool(const CppVariant&);
+ int32_t cppVariantToInt32(const CppVariant&);
+ WebKit::WebString cppVariantToWebString(const CppVariant&);
+ Vector<WebKit::WebString> cppVariantToWebStringArray(const CppVariant&);
+
+ void logErrorToConsole(const std::string&);
+ void completeNotifyDone(bool isTimeout);
+ class NotifyDoneTimedOutTask: public MethodTask<LayoutTestController> {
+ public:
+ NotifyDoneTimedOutTask(LayoutTestController* object): MethodTask<LayoutTestController>(object) { }
+ virtual void runIfValid() { m_object->completeNotifyDone(true); }
+ };
+
+
+ bool pauseAnimationAtTimeOnElementWithId(const WebKit::WebString& animationName, double time, const WebKit::WebString& elementId);
+ bool pauseTransitionAtTimeOnElementWithId(const WebKit::WebString& propertyName, double time, const WebKit::WebString& elementId);
+ bool elementDoesAutoCompleteForElementWithId(const WebKit::WebString&);
+ int numberOfActiveAnimations();
+ void suspendAnimations();
+ void resumeAnimations();
+
+ // Used for test timeouts.
+ TaskList m_taskList;
+
+ // Non-owning pointer. The LayoutTestController is owned by the host.
+ TestShell* m_shell;
+
+ // If true, the test_shell will produce a plain text dump rather than a
+ // text representation of the renderer.
+ bool m_dumpAsText;
+
+ // If true, the test_shell will output a base64 encoded WAVE file.
+ bool m_dumpAsAudio;
+
+ // If true, the test_shell will write a descriptive line for each editing
+ // command.
+ bool m_dumpEditingCallbacks;
+
+ // If true, the test_shell will draw the bounds of the current selection rect
+ // taking possible transforms of the selection rect into account.
+ bool m_dumpSelectionRect;
+
+ // If true, the test_shell will output a descriptive line for each frame
+ // load callback.
+ bool m_dumpFrameLoadCallbacks;
+
+ // If true, the test_shell will output a descriptive line for the progress
+ // finished callback.
+ bool m_dumpProgressFinishedCallback;
+
+ // If true, the test_shell will output a line of the user gesture status
+ // text for some frame load callbacks.
+ bool m_dumpUserGestureInFrameLoadCallbacks;
+
+ // If true, the test_shell will output a descriptive line for each resource
+ // load callback.
+ bool m_dumpResourceLoadCallbacks;
+
+ // If true, the test_shell will output the MIME type for each resource that
+ // was loaded.
+ bool m_dumpResourceResponseMIMETypes;
+
+ // If true, the test_shell will produce a dump of the back forward list as
+ // well.
+ bool m_dumpBackForwardList;
+
+ // If true, the test_shell will print out the child frame scroll offsets as
+ // well.
+ bool m_dumpChildFrameScrollPositions;
+
+ // If true and if dump_as_text_ is true, the test_shell will recursively
+ // dump all frames as plain text.
+ bool m_dumpChildFramesAsText;
+
+ // If true, the test_shell will dump all changes to window.status.
+ bool m_dumpWindowStatusChanges;
+
+ // If true, output a message when the page title is changed.
+ bool m_dumpTitleChanges;
+
+ // If true, output a descriptive line each time a permission client
+ // callback is invoked. Currently only implemented for allowImage.
+ bool m_dumpPermissionClientCallbacks;
+
+ // If true, the test_shell will generate pixel results in dumpAsText mode
+ bool m_generatePixelResults;
+
+ // If true, output a descriptive line each time WebViewClient::createView
+ // is invoked.
+ bool m_dumpCreateView;
+
+ // If true, the element will be treated as editable. This value is returned
+ // from various editing callbacks that are called just before edit operations
+ // are allowed.
+ bool m_acceptsEditing;
+
+ // If true, new windows can be opened via javascript or by plugins. By
+ // default, set to false and can be toggled to true using
+ // setCanOpenWindows().
+ bool m_canOpenWindows;
+
+ // When reset is called, go through and close all but the main test shell
+ // window. By default, set to true but toggled to false using
+ // setCloseRemainingWindowsWhenComplete().
+ bool m_closeRemainingWindows;
+
+ // If true, pixel dump will be produced as a series of 1px-tall, view-wide
+ // individual paints over the height of the view.
+ bool m_testRepaint;
+ // If true and test_repaint_ is true as well, pixel dump will be produced as
+ // a series of 1px-wide, view-tall paints across the width of the view.
+ bool m_sweepHorizontally;
+
+ // If true and a drag starts, adds a file to the drag&drop clipboard.
+ bool m_shouldAddFileToPasteboard;
+
+ // If true, stops provisional frame loads during the
+ // DidStartProvisionalLoadForFrame callback.
+ bool m_stopProvisionalFrameLoads;
+
+ // If true, don't dump output until notifyDone is called.
+ bool m_waitUntilDone;
+
+ // If false, all new requests will not defer the main resource data load.
+ bool m_deferMainResourceDataLoad;
+
+ // If true, we will show extended information in the graphics layer tree.
+ bool m_showDebugLayerTree;
+
+ // If true, layout is to target printed pages.
+ bool m_isPrinting;
+
+ WorkQueue m_workQueue;
+
+ CppVariant m_globalFlag;
+
+ // Bound variable counting the number of top URLs visited.
+ CppVariant m_webHistoryItemCount;
+
+ // Bound variable tracking the directionality of the <title> tag.
+ CppVariant m_titleTextDirection;
+
+ // Bound variable to return the name of this platform (chromium).
+ CppVariant m_platformName;
+
+ // Bound variable to set whether postMessages should be intercepted or not
+ CppVariant m_interceptPostMessage;
+
+ WebKit::WebURL m_userStyleSheetLocation;
+
+ OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock;
+
+ // WAV audio data is stored here.
+ WebKit::WebArrayBufferView m_audioData;
+
+ bool m_shouldStayOnPageAfterHandlingBeforeUnload;
+};
+
+#endif // LayoutTestController_h
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm b/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm
new file mode 100644
index 000000000..e34cf5fca
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#import <AppKit/AppKit.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// This is a simple helper app that changes the color sync profile to the
+// generic profile and back when done. This program is managed by the layout
+// test script, so it can do the job for multiple DumpRenderTree while they are
+// running layout tests.
+
+static CMProfileRef userColorProfile = 0;
+
+static void saveCurrentColorProfile()
+{
+ CGDirectDisplayID displayID = CGMainDisplayID();
+ CMProfileRef previousProfile;
+ CMError error = CMGetProfileByAVID((UInt32)displayID, &previousProfile);
+ if (error) {
+ NSLog(@"failed to get the current color profile, pixmaps won't match. "
+ @"Error: %d", (int)error);
+ } else {
+ userColorProfile = previousProfile;
+ }
+}
+
+static void installLayoutTestColorProfile()
+{
+ // To make sure we get consistent colors (not dependent on the Main display),
+ // we force the generic rgb color profile. This cases a change the user can
+ // see.
+
+ CGDirectDisplayID displayID = CGMainDisplayID();
+ NSColorSpace* genericSpace = [NSColorSpace genericRGBColorSpace];
+ CMProfileRef genericProfile = (CMProfileRef)[genericSpace colorSyncProfile];
+ CMError error = CMSetProfileByAVID((UInt32)displayID, genericProfile);
+ if (error) {
+ NSLog(@"failed install the generic color profile, pixmaps won't match. "
+ @"Error: %d", (int)error);
+ }
+}
+
+static void restoreUserColorProfile(void)
+{
+ if (!userColorProfile)
+ return;
+ CGDirectDisplayID displayID = CGMainDisplayID();
+ CMError error = CMSetProfileByAVID((UInt32)displayID, userColorProfile);
+ CMCloseProfile(userColorProfile);
+ if (error) {
+ NSLog(@"Failed to restore color profile, use System Preferences -> "
+ @"Displays -> Color to reset. Error: %d", (int)error);
+ }
+ userColorProfile = 0;
+}
+
+static void simpleSignalHandler(int sig)
+{
+ // Try to restore the color profile and try to go down cleanly
+ restoreUserColorProfile();
+ exit(128 + sig);
+}
+
+int main(int argc, char* argv[])
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ // Hooks the ways we might get told to clean up...
+ signal(SIGINT, simpleSignalHandler);
+ signal(SIGHUP, simpleSignalHandler);
+ signal(SIGTERM, simpleSignalHandler);
+
+ // Save off the current profile, and then install the layout test profile.
+ saveCurrentColorProfile();
+ installLayoutTestColorProfile();
+
+ // Let the script know we're ready
+ printf("ready\n");
+ fflush(stdout);
+
+ // Wait for any key (or signal)
+ getchar();
+
+ // Restore the profile
+ restoreUserColorProfile();
+
+ [pool release];
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp b/Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp
new file mode 100644
index 000000000..25efdcdcb
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+
+static BOOL fontSmoothingEnabled = FALSE;
+
+static void saveInitialSettings(void)
+{
+ ::SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0);
+}
+
+// Technically, all we need to do is disable ClearType. However,
+// for some reason, the call to SPI_SETFONTSMOOTHINGTYPE doesn't
+// seem to work, so we just disable font smoothing all together
+// (which works reliably)
+static void installLayoutTestSettings(void)
+{
+ ::SystemParametersInfo(SPI_SETFONTSMOOTHING, FALSE, 0, 0);
+}
+
+static void restoreInitialSettings(void)
+{
+ ::SystemParametersInfo(SPI_SETFONTSMOOTHING, static_cast<UINT>(fontSmoothingEnabled), 0, 0);
+}
+
+static void simpleSignalHandler(int signalNumber)
+{
+ // Try to restore the settings and then go down cleanly
+ restoreInitialSettings();
+ exit(128 + signalNumber);
+}
+
+int main(int, char*[])
+{
+ // Hooks the ways we might get told to clean up...
+ signal(SIGINT, simpleSignalHandler);
+ signal(SIGTERM, simpleSignalHandler);
+
+ saveInitialSettings();
+
+ installLayoutTestSettings();
+
+ // Let the script know we're ready
+ printf("ready\n");
+ fflush(stdout);
+
+ // Wait for any key (or signal)
+ getchar();
+
+ restoreInitialSettings();
+
+ return EXIT_SUCCESS;
+}
diff --git a/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp b/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp
new file mode 100644
index 000000000..56b0f1eff
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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 "MockSpellCheck.h"
+
+#include "platform/WebString.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
+#include <wtf/text/WTFString.h>
+
+using namespace WebKit;
+
+MockSpellCheck::MockSpellCheck()
+ : m_initialized(false) { }
+
+MockSpellCheck::~MockSpellCheck() { }
+
+static bool isNotASCIIAlpha(UChar ch) { return !isASCIIAlpha(ch); }
+
+bool MockSpellCheck::spellCheckWord(const WebString& text, int* misspelledOffset, int* misspelledLength)
+{
+ ASSERT(misspelledOffset);
+ ASSERT(misspelledLength);
+
+ // Initialize this spellchecker.
+ initializeIfNeeded();
+
+ // Reset the result values as our spellchecker does.
+ *misspelledOffset = 0;
+ *misspelledLength = 0;
+
+ // Convert to a String because we store String instances in
+ // m_misspelledWords and WebString has no find().
+ WTF::String stringText(text.data(), text.length());
+ int skippedLength = 0;
+
+ while (!stringText.isEmpty()) {
+ // Extract the first possible English word from the given string.
+ // The given string may include non-ASCII characters or numbers. So, we
+ // should filter out such characters before start looking up our
+ // misspelled-word table.
+ // (This is a simple version of our SpellCheckWordIterator class.)
+ // If the given string doesn't include any ASCII characters, we can treat the
+ // string as valid one.
+ // Unfortunately, This implementation splits a contraction, i.e. "isn't" is
+ // split into two pieces "isn" and "t". This is OK because webkit tests
+ // don't have misspelled contractions.
+ int wordOffset = stringText.find(isASCIIAlpha);
+ if (wordOffset == -1)
+ return true;
+ int wordEnd = stringText.find(isNotASCIIAlpha, wordOffset);
+ int wordLength = wordEnd == -1 ? static_cast<int>(stringText.length()) - wordOffset : wordEnd - wordOffset;
+
+ // Look up our misspelled-word table to check if the extracted word is a
+ // known misspelled word, and return the offset and the length of the
+ // extracted word if this word is a known misspelled word.
+ // (See the comment in MockSpellCheck::initializeIfNeeded() why we use a
+ // misspelled-word table.)
+ WTF::String word = stringText.substring(wordOffset, wordLength);
+ if (m_misspelledWords.contains(word)) {
+ *misspelledOffset = wordOffset + skippedLength;
+ *misspelledLength = wordLength;
+ break;
+ }
+
+ ASSERT(0 < wordOffset + wordLength);
+ stringText = stringText.substring(wordOffset + wordLength);
+ skippedLength += wordOffset + wordLength;
+ }
+
+ return false;
+}
+
+void MockSpellCheck::fillSuggestionList(const WebString& word, Vector<WebString>* suggestions)
+{
+ if (word == WebString::fromUTF8("wellcome"))
+ suggestions->append(WebString::fromUTF8("welcome"));
+}
+
+bool MockSpellCheck::initializeIfNeeded()
+{
+ // Exit if we have already initialized this object.
+ if (m_initialized)
+ return false;
+
+ // Create a table that consists of misspelled words used in WebKit layout
+ // tests.
+ // Since WebKit layout tests don't have so many misspelled words as
+ // well-spelled words, it is easier to compare the given word with misspelled
+ // ones than to compare with well-spelled ones.
+ static const char* misspelledWords[] = {
+ // These words are known misspelled words in webkit tests.
+ // If there are other misspelled words in webkit tests, please add them in
+ // this array.
+ "foo",
+ "Foo",
+ "baz",
+ "fo",
+ "LibertyF",
+ "chello",
+ "xxxtestxxx",
+ "XXxxx",
+ "Textx",
+ "blockquoted",
+ "asd",
+ "Lorem",
+ "Nunc",
+ "Curabitur",
+ "eu",
+ "adlj",
+ "adaasj",
+ "sdklj",
+ "jlkds",
+ "jsaada",
+ "jlda",
+ "zz",
+ "contentEditable",
+ // The following words are used by unit tests.
+ "ifmmp",
+ "qwertyuiopasd",
+ "qwertyuiopasdf",
+ "wellcome"
+ };
+
+ m_misspelledWords.clear();
+ for (size_t i = 0; i < arraysize(misspelledWords); ++i)
+ m_misspelledWords.add(WTF::String::fromUTF8(misspelledWords[i]), false);
+
+ // Mark as initialized to prevent this object from being initialized twice
+ // or more.
+ m_initialized = true;
+
+ // Since this MockSpellCheck class doesn't download dictionaries, this
+ // function always returns false.
+ return false;
+}
diff --git a/Tools/DumpRenderTree/chromium/MockSpellCheck.h b/Tools/DumpRenderTree/chromium/MockSpellCheck.h
new file mode 100644
index 000000000..bce05c772
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/MockSpellCheck.h
@@ -0,0 +1,84 @@
+/*
+ * 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 MockSpellCheck_h
+#define MockSpellCheck_h
+
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+class WebString;
+}
+
+// A mock implementation of a spell-checker used for WebKit tests.
+// This class only implements the minimal functionarities required by WebKit
+// tests, i.e. this class just compares the given string with known misspelled
+// words in webkit tests and mark them as missspelled.
+// Even though this is sufficent for webkit tests, this class is not suitable
+// for any other usages.
+class MockSpellCheck {
+public:
+ MockSpellCheck();
+ ~MockSpellCheck();
+
+ // Checks the spellings of the specified text.
+ // This function returns true if the text consists of valid words, and
+ // returns false if it includes invalid words.
+ // When the given text includes invalid words, this function sets the
+ // position of the first invalid word to misspelledOffset, and the length of
+ // the first invalid word to misspelledLength, respectively.
+ // For example, when the given text is " zz zz", this function sets 3 to
+ // misspelledOffset and 2 to misspelledLength, respectively.
+ bool spellCheckWord(const WebKit::WebString& text,
+ int* misspelledOffset,
+ int* misspelledLength);
+
+ void fillSuggestionList(const WebKit::WebString& word, Vector<WebKit::WebString>* suggestions);
+
+private:
+ // Initialize the internal resources if we need to initialize it.
+ // Initializing this object may take long time. To prevent from hurting
+ // the performance of test_shell, we initialize this object when
+ // SpellCheckWord() is called for the first time.
+ // To be compliant with SpellCheck:InitializeIfNeeded(), this function
+ // returns true if this object is downloading a dictionary, otherwise
+ // it returns false.
+ bool initializeIfNeeded();
+
+ // A table that consists of misspelled words.
+ HashMap<WTF::String, bool> m_misspelledWords;
+
+ // A flag representing whether or not this object is initialized.
+ bool m_initialized;
+};
+
+#endif // MockSpellCheck_h
diff --git a/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp b/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp
new file mode 100644
index 000000000..7809821aa
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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 "NotificationPresenter.h"
+
+#if ENABLE(NOTIFICATIONS)
+
+#include "WebKit.h"
+#include "platform/WebKitPlatformSupport.h"
+#include "WebNotification.h"
+#include "WebNotificationPermissionCallback.h"
+#include "WebSecurityOrigin.h"
+#include "platform/WebString.h"
+#include "platform/WebURL.h"
+#include "googleurl/src/gurl.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+using namespace WebKit;
+
+static WebString identifierForNotification(const WebNotification& notification)
+{
+ if (notification.isHTML())
+ return notification.url().spec().utf16();
+ return notification.title();
+}
+
+static void deferredDisplayDispatch(void* context)
+{
+ WebNotification* notification = static_cast<WebNotification*>(context);
+ notification->dispatchDisplayEvent();
+ delete notification;
+}
+
+NotificationPresenter::~NotificationPresenter()
+{
+}
+
+void NotificationPresenter::grantPermission(const WebString& origin)
+{
+ m_allowedOrigins.add(WTF::String(origin.data(), origin.length()));
+}
+
+bool NotificationPresenter::simulateClick(const WebString& title)
+{
+ WTF::String id(title.data(), title.length());
+ if (m_activeNotifications.find(id) == m_activeNotifications.end())
+ return false;
+
+ const WebNotification& notification = m_activeNotifications.find(id)->second;
+ WebNotification eventTarget(notification);
+ eventTarget.dispatchClickEvent();
+ return true;
+}
+
+// The output from all these methods matches what DumpRenderTree produces.
+bool NotificationPresenter::show(const WebNotification& notification)
+{
+ WebString identifier = identifierForNotification(notification);
+ if (!notification.replaceId().isEmpty()) {
+ WTF::String replaceId(notification.replaceId().data(), notification.replaceId().length());
+ if (m_replacements.find(replaceId) != m_replacements.end())
+ printf("REPLACING NOTIFICATION %s\n",
+ m_replacements.find(replaceId)->second.utf8().data());
+
+ m_replacements.set(replaceId, WTF::String(identifier.data(), identifier.length()));
+ }
+
+ if (notification.isHTML()) {
+ printf("DESKTOP NOTIFICATION: contents at %s\n",
+ notification.url().spec().data());
+ } else {
+ printf("DESKTOP NOTIFICATION:%s icon %s, title %s, text %s\n",
+ notification.direction() == WebTextDirectionRightToLeft ? "(RTL)" : "",
+ notification.iconURL().isEmpty() ? "" :
+ notification.iconURL().spec().data(),
+ notification.title().isEmpty() ? "" :
+ notification.title().utf8().data(),
+ notification.body().isEmpty() ? "" :
+ notification.body().utf8().data());
+ }
+
+ WTF::String id(identifier.data(), identifier.length());
+ m_activeNotifications.set(id, notification);
+
+ webKitPlatformSupport()->callOnMainThread(deferredDisplayDispatch, new WebNotification(notification));
+ return true;
+}
+
+void NotificationPresenter::cancel(const WebNotification& notification)
+{
+ WebString identifier = identifierForNotification(notification);
+ printf("DESKTOP NOTIFICATION CLOSED: %s\n", identifier.utf8().data());
+ WebNotification eventTarget(notification);
+ eventTarget.dispatchCloseEvent(false);
+
+ WTF::String id(identifier.data(), identifier.length());
+ m_activeNotifications.remove(id);
+}
+
+void NotificationPresenter::objectDestroyed(const WebKit::WebNotification& notification)
+{
+ WebString identifier = identifierForNotification(notification);
+ WTF::String id(identifier.data(), identifier.length());
+ m_activeNotifications.remove(id);
+}
+
+WebNotificationPresenter::Permission NotificationPresenter::checkPermission(const WebSecurityOrigin& origin)
+{
+ // Check with the layout test controller
+ WebString originString = origin.toString();
+ bool allowed = m_allowedOrigins.find(WTF::String(originString.data(), originString.length())) != m_allowedOrigins.end();
+ return allowed ? WebNotificationPresenter::PermissionAllowed
+ : WebNotificationPresenter::PermissionDenied;
+}
+
+void NotificationPresenter::requestPermission(
+ const WebSecurityOrigin& origin,
+ WebNotificationPermissionCallback* callback)
+{
+ printf("DESKTOP NOTIFICATION PERMISSION REQUESTED: %s\n",
+ origin.toString().utf8().data());
+ callback->permissionRequestComplete();
+}
+
+#endif // ENABLE(NOTIFICATIONS)
diff --git a/Tools/DumpRenderTree/chromium/NotificationPresenter.h b/Tools/DumpRenderTree/chromium/NotificationPresenter.h
new file mode 100644
index 000000000..b33df9138
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/NotificationPresenter.h
@@ -0,0 +1,78 @@
+/*
+ * 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 NotificationPresenter_h
+#define NotificationPresenter_h
+
+#include "WebNotification.h"
+#include "WebNotificationPresenter.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+class TestShell;
+
+// A class that implements WebNotificationPresenter for DRT.
+class NotificationPresenter : public WebKit::WebNotificationPresenter {
+public:
+ explicit NotificationPresenter(TestShell* shell) : m_shell(shell) { }
+ virtual ~NotificationPresenter();
+
+ // Called by the LayoutTestController to simulate a user granting permission.
+ void grantPermission(const WebKit::WebString& origin);
+
+ // Called by the LayoutTestController to simulate a user clicking on a notification.
+ bool simulateClick(const WebKit::WebString& notificationIdentifier);
+
+ // WebKit::WebNotificationPresenter interface
+ virtual bool show(const WebKit::WebNotification&);
+ virtual void cancel(const WebKit::WebNotification&);
+ virtual void objectDestroyed(const WebKit::WebNotification&);
+ virtual Permission checkPermission(const WebKit::WebSecurityOrigin&);
+ virtual void requestPermission(const WebKit::WebSecurityOrigin&, WebKit::WebNotificationPermissionCallback*);
+
+ void reset() { m_allowedOrigins.clear(); }
+
+private:
+ // Non-owned pointer. The NotificationPresenter is owned by the test shell.
+ TestShell* m_shell;
+
+ // Set of allowed origins.
+ HashSet<WTF::String> m_allowedOrigins;
+
+ // Map of active notifications.
+ HashMap<WTF::String, WebKit::WebNotification> m_activeNotifications;
+
+ // Map of active replacement IDs to the titles of those notifications
+ HashMap<WTF::String, WTF::String> m_replacements;
+};
+
+#endif // NotificationPresenter_h
diff --git a/Tools/DumpRenderTree/chromium/PlainTextController.cpp b/Tools/DumpRenderTree/chromium/PlainTextController.cpp
new file mode 100644
index 000000000..7287c2c83
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/PlainTextController.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org)
+ *
+ * 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 "PlainTextController.h"
+
+#include "TestShell.h"
+#include "WebBindings.h"
+#include "WebRange.h"
+#include "platform/WebString.h"
+
+using namespace WebKit;
+
+PlainTextController::PlainTextController()
+{
+ // Initialize the map that associates methods of this class with the names
+ // they will use when called by JavaScript. The actual binding of those
+ // names to their methods will be done by calling bindToJavaScript() (defined
+ // by CppBoundClass, the parent to PlainTextController).
+ bindMethod("plainText", &PlainTextController::plainText);
+
+ // The fallback method is called when an unknown method is invoked.
+ bindFallbackMethod(&PlainTextController::fallbackMethod);
+}
+
+void PlainTextController::plainText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isObject())
+ return;
+
+ // Check that passed-in object is, in fact, a range.
+ NPObject* npobject = NPVARIANT_TO_OBJECT(arguments[0]);
+ if (!npobject)
+ return;
+ WebRange range;
+ if (!WebBindings::getRange(npobject, &range))
+ return;
+
+ // Extract the text using the Range's text() method
+ WebString text = range.toPlainText();
+ result->set(text.utf8());
+}
+
+void PlainTextController::fallbackMethod(const CppArgumentList&, CppVariant* result)
+{
+ printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on PlainTextController\n");
+ result->setNull();
+}
+
diff --git a/Tools/DumpRenderTree/chromium/PlainTextController.h b/Tools/DumpRenderTree/chromium/PlainTextController.h
new file mode 100644
index 000000000..3d3a04c61
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/PlainTextController.h
@@ -0,0 +1,52 @@
+/*
+ * 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 PlainTextController_h
+#define PlainTextController_h
+
+#include "CppBoundClass.h"
+
+class TestShell;
+
+class PlainTextController : public CppBoundClass {
+public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ explicit PlainTextController();
+
+ // JS callback methods.
+ void plainText(const CppArgumentList&, CppVariant*);
+
+ // Fall-back method: called if an unknown method is invoked.
+ void fallbackMethod(const CppArgumentList&, CppVariant*);
+};
+
+#endif // PlainTextController_h
+
diff --git a/Tools/DumpRenderTree/chromium/Task.cpp b/Tools/DumpRenderTree/chromium/Task.cpp
new file mode 100644
index 000000000..d80beef34
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/Task.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "Task.h"
+
+#include "WebKit.h"
+#include "platform/WebKitPlatformSupport.h"
+
+WebTask::WebTask(TaskList* list)
+ : m_taskList(list)
+{
+ m_taskList->registerTask(this);
+}
+
+WebTask::~WebTask()
+{
+ if (m_taskList)
+ m_taskList->unregisterTask(this);
+}
+
+void TaskList::unregisterTask(WebTask* task)
+{
+ size_t index = m_tasks.find(task);
+ if (index != notFound)
+ m_tasks.remove(index);
+}
+
+void TaskList::revokeAll()
+{
+ while (!m_tasks.isEmpty())
+ m_tasks[0]->cancel();
+}
+
+static void invokeTask(void* context)
+{
+ WebTask* task = static_cast<WebTask*>(context);
+ task->run();
+ delete task;
+}
+
+void postTask(WebTask* task)
+{
+ WebKit::webKitPlatformSupport()->callOnMainThread(invokeTask, static_cast<void*>(task));
+}
+
+void postDelayedTask(WebTask* task, int64_t ms)
+{
+ webkit_support::PostDelayedTask(task, ms);
+}
+
+
diff --git a/Tools/DumpRenderTree/chromium/Task.h b/Tools/DumpRenderTree/chromium/Task.h
new file mode 100644
index 000000000..0b32c472b
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/Task.h
@@ -0,0 +1,96 @@
+/*
+ * 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 Task_h
+#define Task_h
+
+#include "webkit/support/webkit_support.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+class TaskList;
+
+// WebTask represents a task which can run by postTask() or postDelayedTask().
+// it is named "WebTask", not "Task", to avoid conflist with base/task.h.
+class WebTask : public webkit_support::TaskAdaptor {
+public:
+ WebTask(TaskList*);
+ // The main code of this task.
+ // An implementation of run() should return immediately if cancel() was called.
+ virtual void run() = 0;
+ virtual void cancel() = 0;
+ virtual ~WebTask();
+
+private:
+ virtual void Run() { run(); }
+
+protected:
+ TaskList* m_taskList;
+};
+
+class TaskList {
+public:
+ TaskList() { }
+ ~TaskList() { revokeAll(); }
+ void registerTask(WebTask* task) { m_tasks.append(task); }
+ void unregisterTask(WebTask*);
+ void revokeAll();
+
+private:
+ Vector<WebTask*> m_tasks;
+};
+
+// A task containing an object pointer of class T. Is is supposed that
+// runifValid() calls a member function of the object pointer.
+// Class T must have "TaskList* taskList()".
+template<class T> class MethodTask: public WebTask {
+public:
+ MethodTask(T* object): WebTask(object->taskList()), m_object(object) { }
+ virtual void run()
+ {
+ if (m_object)
+ runIfValid();
+ }
+ virtual void cancel()
+ {
+ m_object = 0;
+ m_taskList->unregisterTask(this);
+ m_taskList = 0;
+ }
+ virtual void runIfValid() = 0;
+
+protected:
+ T* m_object;
+};
+
+void postTask(WebTask*);
+void postDelayedTask(WebTask*, int64_t ms);
+
+#endif // Task_h
diff --git a/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp b/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp
new file mode 100644
index 000000000..8246c09be
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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 "TestEventPrinter.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <wtf/Assertions.h>
+
+class DRTPrinter : public TestEventPrinter {
+public:
+ DRTPrinter() { }
+ void handleTestHeader(const char* url) const;
+ void handleTimedOut() const;
+ void handleTextHeader() const;
+ void handleTextFooter() const;
+ void handleAudioHeader() const;
+ void handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char* fileName) const;
+ void handleImageFooter() const;
+ void handleTestFooter(bool dumpedAnything) const;
+};
+
+class TestShellPrinter : public TestEventPrinter {
+public:
+ TestShellPrinter() { }
+ void handleTestHeader(const char* url) const;
+ void handleTimedOut() const;
+ void handleTextHeader() const;
+ void handleTextFooter() const;
+ void handleAudioHeader() const;
+ void handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char* fileName) const;
+ void handleImageFooter() const;
+ void handleTestFooter(bool dumpedAnything) const;
+};
+
+TestEventPrinter::~TestEventPrinter()
+{
+}
+
+PassOwnPtr<TestEventPrinter> TestEventPrinter::createDRTPrinter()
+{
+ return adoptPtr(new DRTPrinter);
+}
+
+PassOwnPtr<TestEventPrinter> TestEventPrinter::createTestShellPrinter()
+{
+ return adoptPtr(new TestShellPrinter);
+}
+
+// ----------------------------------------------------------------
+
+void DRTPrinter::handleTestHeader(const char*) const
+{
+}
+
+void DRTPrinter::handleTimedOut() const
+{
+ fprintf(stderr, "FAIL: Timed out waiting for notifyDone to be called\n");
+ fprintf(stdout, "FAIL: Timed out waiting for notifyDone to be called\n");
+}
+
+void DRTPrinter::handleTextHeader() const
+{
+ printf("Content-Type: text/plain\n");
+}
+
+void DRTPrinter::handleTextFooter() const
+{
+ printf("#EOF\n");
+}
+
+void DRTPrinter::handleAudioHeader() const
+{
+ printf("Content-Type: audio/wav\n");
+}
+
+void DRTPrinter::handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char*) const
+{
+ ASSERT(actualHash);
+ printf("\nActualHash: %s\n", actualHash);
+ if (expectedHash && expectedHash[0])
+ printf("\nExpectedHash: %s\n", expectedHash);
+ if (imageData && imageSize) {
+ printf("Content-Type: image/png\n");
+ // Printf formatting for size_t on 32-bit, 64-bit, and on Windows is hard so just cast to an int.
+ printf("Content-Length: %d\n", static_cast<int>(imageSize));
+ if (fwrite(imageData, 1, imageSize, stdout) != imageSize) {
+ fprintf(stderr, "Short write to stdout.\n");
+ exit(1);
+ }
+ }
+}
+
+void DRTPrinter::handleImageFooter() const
+{
+ printf("#EOF\n");
+}
+
+void DRTPrinter::handleTestFooter(bool) const
+{
+}
+
+// ----------------------------------------------------------------
+
+void TestShellPrinter::handleTestHeader(const char* url) const
+{
+ printf("#URL:%s\n", url);
+}
+
+void TestShellPrinter::handleTimedOut() const
+{
+ puts("#TEST_TIMED_OUT\n");
+}
+
+void TestShellPrinter::handleTextHeader() const
+{
+}
+
+void TestShellPrinter::handleTextFooter() const
+{
+}
+
+void TestShellPrinter::handleAudioHeader() const
+{
+ printf("Content-Type: audio/wav\n");
+}
+
+void TestShellPrinter::handleImage(const char* actualHash, const char*, const unsigned char* imageData, size_t imageSize, const char* fileName) const
+{
+ ASSERT(actualHash);
+ if (imageData && imageSize) {
+ ASSERT(fileName);
+ FILE* fp = fopen(fileName, "wb");
+ if (!fp) {
+ perror(fileName);
+ exit(EXIT_FAILURE);
+ }
+ if (fwrite(imageData, 1, imageSize, fp) != imageSize) {
+ perror(fileName);
+ fclose(fp);
+ exit(EXIT_FAILURE);
+ }
+ fclose(fp);
+ }
+ printf("#MD5:%s\n", actualHash);
+}
+
+void TestShellPrinter::handleImageFooter() const
+{
+}
+
+void TestShellPrinter::handleTestFooter(bool dumpedAnything) const
+{
+ if (dumpedAnything)
+ printf("#EOF\n");
+}
diff --git a/Tools/DumpRenderTree/chromium/TestEventPrinter.h b/Tools/DumpRenderTree/chromium/TestEventPrinter.h
new file mode 100644
index 000000000..f69523c34
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestEventPrinter.h
@@ -0,0 +1,52 @@
+/*
+ * 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 TestEventPrinter_h
+#define TestEventPrinter_h
+
+#include <wtf/PassOwnPtr.h>
+
+class TestEventPrinter {
+public:
+ static PassOwnPtr<TestEventPrinter> createDRTPrinter();
+ static PassOwnPtr<TestEventPrinter> createTestShellPrinter();
+
+ virtual ~TestEventPrinter();
+ virtual void handleTestHeader(const char* url) const = 0;
+ virtual void handleTimedOut() const = 0;
+ virtual void handleTextHeader() const = 0;
+ virtual void handleTextFooter() const = 0;
+ virtual void handleAudioHeader() const = 0;
+ virtual void handleImage(const char* actualHash, const char* expectedHash, const unsigned char* imageData, size_t imageSize, const char* fileName) const = 0;
+ virtual void handleImageFooter() const = 0;
+ virtual void handleTestFooter(bool dumpedAnything) const = 0;
+};
+
+#endif // TestEventPrinter_h
diff --git a/Tools/DumpRenderTree/chromium/TestNavigationController.cpp b/Tools/DumpRenderTree/chromium/TestNavigationController.cpp
new file mode 100644
index 000000000..ad6fcfff4
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNavigationController.cpp
@@ -0,0 +1,277 @@
+/*
+ * 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 "TestNavigationController.h"
+
+#include "TestShell.h"
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+using namespace std;
+
+// ----------------------------------------------------------------------------
+// TestNavigationEntry
+
+PassRefPtr<TestNavigationEntry> TestNavigationEntry::create()
+{
+ return adoptRef(new TestNavigationEntry);
+}
+
+PassRefPtr<TestNavigationEntry> TestNavigationEntry::create(
+ int pageID, const WebURL& url, const WebString& title, const WebString& targetFrame)
+{
+ return adoptRef(new TestNavigationEntry(pageID, url, title, targetFrame));
+}
+
+TestNavigationEntry::TestNavigationEntry()
+ : m_pageID(-1) { }
+
+TestNavigationEntry::TestNavigationEntry(
+ int pageID, const WebURL& url, const WebString& title, const WebString& targetFrame)
+ : m_pageID(pageID)
+ , m_url(url)
+ , m_title(title)
+ , m_targetFrame(targetFrame) { }
+
+TestNavigationEntry::~TestNavigationEntry() { }
+
+void TestNavigationEntry::setContentState(const WebHistoryItem& state)
+{
+ m_state = state;
+}
+
+// ----------------------------------------------------------------------------
+// TestNavigationController
+
+TestNavigationController::TestNavigationController(NavigationHost* host)
+ : m_pendingEntry(0)
+ , m_lastCommittedEntryIndex(-1)
+ , m_pendingEntryIndex(-1)
+ , m_host(host)
+ , m_maxPageID(-1) { }
+
+TestNavigationController::~TestNavigationController()
+{
+ discardPendingEntry();
+}
+
+void TestNavigationController::reset()
+{
+ m_entries.clear();
+ discardPendingEntry();
+
+ m_lastCommittedEntryIndex = -1;
+}
+
+void TestNavigationController::reload()
+{
+ // Base the navigation on where we are now...
+ int currentIndex = currentEntryIndex();
+
+ // If we are no where, then we can't reload.
+ // FIXME: We should add a CanReload method.
+ if (currentIndex == -1)
+ return;
+
+ discardPendingEntry();
+
+ m_pendingEntryIndex = currentIndex;
+ navigateToPendingEntry(true);
+}
+
+void TestNavigationController::goToOffset(int offset)
+{
+ int index = m_lastCommittedEntryIndex + offset;
+ if (index < 0 || index >= entryCount())
+ return;
+
+ goToIndex(index);
+}
+
+void TestNavigationController::goToIndex(int index)
+{
+ ASSERT(index >= 0);
+ ASSERT(index < static_cast<int>(m_entries.size()));
+
+ discardPendingEntry();
+
+ m_pendingEntryIndex = index;
+ navigateToPendingEntry(false);
+}
+
+void TestNavigationController::loadEntry(TestNavigationEntry* entry)
+{
+ // When navigating to a new page, we don't know for sure if we will actually
+ // end up leaving the current page. The new page load could for example
+ // result in a download or a 'no content' response (e.g., a mailto: URL).
+ discardPendingEntry();
+ m_pendingEntry = entry;
+ navigateToPendingEntry(false);
+}
+
+
+TestNavigationEntry* TestNavigationController::lastCommittedEntry() const
+{
+ if (m_lastCommittedEntryIndex == -1)
+ return 0;
+ return m_entries[m_lastCommittedEntryIndex].get();
+}
+
+TestNavigationEntry* TestNavigationController::activeEntry() const
+{
+ TestNavigationEntry* entry = m_pendingEntry.get();
+ if (!entry)
+ entry = lastCommittedEntry();
+ return entry;
+}
+
+int TestNavigationController::currentEntryIndex() const
+{
+ if (m_pendingEntryIndex != -1)
+ return m_pendingEntryIndex;
+ return m_lastCommittedEntryIndex;
+}
+
+
+TestNavigationEntry* TestNavigationController::entryAtIndex(int index) const
+{
+ if (index < 0 || index >= entryCount())
+ return 0;
+ return m_entries[index].get();
+}
+
+TestNavigationEntry* TestNavigationController::entryWithPageID(int32_t pageID) const
+{
+ int index = entryIndexWithPageID(pageID);
+ return (index != -1) ? m_entries[index].get() : 0;
+}
+
+void TestNavigationController::didNavigateToEntry(TestNavigationEntry* entry)
+{
+ // If the entry is that of a page with PageID larger than any this Tab has
+ // seen before, then consider it a new navigation.
+ if (entry->pageID() > maxPageID()) {
+ insertEntry(entry);
+ return;
+ }
+
+ // Otherwise, we just need to update an existing entry with matching PageID.
+ // If the existing entry corresponds to the entry which is pending, then we
+ // must update the current entry index accordingly. When navigating to the
+ // same URL, a new PageID is not created.
+
+ int existingEntryIndex = entryIndexWithPageID(entry->pageID());
+ TestNavigationEntry* existingEntry = (existingEntryIndex != -1) ?
+ m_entries[existingEntryIndex].get() : 0;
+ if (!existingEntry) {
+ // No existing entry, then simply ignore this navigation!
+ } else if (existingEntry == m_pendingEntry.get()) {
+ // The given entry might provide a new URL... e.g., navigating back to a
+ // page in session history could have resulted in a new client redirect.
+ existingEntry->setURL(entry->URL());
+ existingEntry->setContentState(entry->contentState());
+ m_lastCommittedEntryIndex = m_pendingEntryIndex;
+ m_pendingEntryIndex = -1;
+ m_pendingEntry.clear();
+ } else if (m_pendingEntry && m_pendingEntry->pageID() == -1
+ && GURL(m_pendingEntry->URL()) == GURL(existingEntry->URL().spec())) {
+ // Not a new navigation
+ discardPendingEntry();
+ } else {
+ // The given entry might provide a new URL... e.g., navigating to a page
+ // might result in a client redirect, which should override the URL of the
+ // existing entry.
+ existingEntry->setURL(entry->URL());
+ existingEntry->setContentState(entry->contentState());
+
+ // The navigation could have been issued by the renderer, so be sure that
+ // we update our current index.
+ m_lastCommittedEntryIndex = existingEntryIndex;
+ }
+
+ updateMaxPageID();
+}
+
+void TestNavigationController::discardPendingEntry()
+{
+ m_pendingEntry.clear();
+ m_pendingEntryIndex = -1;
+}
+
+void TestNavigationController::insertEntry(TestNavigationEntry* entry)
+{
+ discardPendingEntry();
+
+ // Prune any entry which are in front of the current entry
+ int currentSize = static_cast<int>(m_entries.size());
+ if (currentSize > 0) {
+ while (m_lastCommittedEntryIndex < (currentSize - 1)) {
+ m_entries.removeLast();
+ currentSize--;
+ }
+ }
+
+ m_entries.append(RefPtr<TestNavigationEntry>(entry));
+ m_lastCommittedEntryIndex = static_cast<int>(m_entries.size()) - 1;
+ updateMaxPageID();
+}
+
+int TestNavigationController::entryIndexWithPageID(int32 pageID) const
+{
+ for (int i = static_cast<int>(m_entries.size()) - 1; i >= 0; --i) {
+ if (m_entries[i]->pageID() == pageID)
+ return i;
+ }
+ return -1;
+}
+
+void TestNavigationController::navigateToPendingEntry(bool reload)
+{
+ // For session history navigations only the pending_entry_index_ is set.
+ if (!m_pendingEntry) {
+ ASSERT(m_pendingEntryIndex != -1);
+ m_pendingEntry = m_entries[m_pendingEntryIndex];
+ }
+
+ if (m_host->navigate(*m_pendingEntry.get(), reload)) {
+ // Note: this is redundant if navigation completed synchronously because
+ // DidNavigateToEntry call this as well.
+ updateMaxPageID();
+ } else
+ discardPendingEntry();
+}
+
+void TestNavigationController::updateMaxPageID()
+{
+ TestNavigationEntry* entry = activeEntry();
+ if (entry)
+ m_maxPageID = max(m_maxPageID, entry->pageID());
+}
diff --git a/Tools/DumpRenderTree/chromium/TestNavigationController.h b/Tools/DumpRenderTree/chromium/TestNavigationController.h
new file mode 100644
index 000000000..f23a2ae92
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNavigationController.h
@@ -0,0 +1,211 @@
+/*
+ * 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 TestNavigationController_h
+#define TestNavigationController_h
+
+#include "WebDataSource.h"
+#include "WebHistoryItem.h"
+#include "platform/WebString.h"
+#include "platform/WebURL.h"
+#include "webkit/support/webkit_support.h"
+#include <string>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+// Associated with browser-initated navigations to hold tracking data.
+class TestShellExtraData : public WebKit::WebDataSource::ExtraData {
+public:
+ TestShellExtraData(int32_t pendingPageID)
+ : pendingPageID(pendingPageID)
+ , requestCommitted(false) { }
+
+ // Contains the page_id for this navigation or -1 if there is none yet.
+ int32_t pendingPageID;
+
+ // True if we have already processed the "DidCommitLoad" event for this
+ // request. Used by session history.
+ bool requestCommitted;
+};
+
+// Stores one back/forward navigation state for the test shell.
+class TestNavigationEntry: public RefCounted<TestNavigationEntry> {
+public:
+ static PassRefPtr<TestNavigationEntry> create();
+ static PassRefPtr<TestNavigationEntry> create(
+ int pageID,
+ const WebKit::WebURL&,
+ const WebKit::WebString& title,
+ const WebKit::WebString& targetFrame);
+
+ // Virtual to allow test_shell to extend the class.
+ virtual ~TestNavigationEntry();
+
+ // Set / Get the URI
+ void setURL(const WebKit::WebURL& url) { m_url = url; }
+ const WebKit::WebURL& URL() const { return m_url; }
+
+ // Set / Get the title
+ void setTitle(const WebKit::WebString& title) { m_title = title; }
+ const WebKit::WebString& title() const { return m_title; }
+
+ // Set / Get a state.
+ void setContentState(const WebKit::WebHistoryItem&);
+ const WebKit::WebHistoryItem& contentState() const { return m_state; }
+
+ // Get the page id corresponding to the tab's state.
+ void setPageID(int pageID) { m_pageID = pageID; }
+ int32_t pageID() const { return m_pageID; }
+
+ const WebKit::WebString& targetFrame() const { return m_targetFrame; }
+
+private:
+ TestNavigationEntry();
+ TestNavigationEntry(int pageID,
+ const WebKit::WebURL&,
+ const WebKit::WebString& title,
+ const WebKit::WebString& targetFrame);
+
+ // Describes the current page that the tab represents. This is not relevant
+ // for all tab contents types.
+ int32_t m_pageID;
+
+ WebKit::WebURL m_url;
+ WebKit::WebString m_title;
+ WebKit::WebHistoryItem m_state;
+ WebKit::WebString m_targetFrame;
+};
+
+class NavigationHost {
+public:
+ virtual bool navigate(const TestNavigationEntry&, bool reload) = 0;
+};
+
+// Test shell's NavigationController. The goal is to be as close to the Chrome
+// version as possible.
+class TestNavigationController {
+ WTF_MAKE_NONCOPYABLE(TestNavigationController);
+public:
+ TestNavigationController(NavigationHost*);
+ ~TestNavigationController();
+
+ void reset();
+
+ // Causes the controller to reload the current (or pending) entry.
+ void reload();
+
+ // Causes the controller to go to the specified offset from current. Does
+ // nothing if out of bounds.
+ void goToOffset(int);
+
+ // Causes the controller to go to the specified index.
+ void goToIndex(int);
+
+ // Causes the controller to load the specified entry.
+ // NOTE: Do not pass an entry that the controller already owns!
+ void loadEntry(TestNavigationEntry*);
+
+ // Returns the last committed entry, which may be null if there are no
+ // committed entries.
+ TestNavigationEntry* lastCommittedEntry() const;
+
+ // Returns the number of entries in the NavigationControllerBase, excluding
+ // the pending entry if there is one.
+ int entryCount() const { return static_cast<int>(m_entries.size()); }
+
+ // Returns the active entry, which is the pending entry if a navigation is in
+ // progress or the last committed entry otherwise. NOTE: This can be 0!!
+ //
+ // If you are trying to get the current state of the NavigationControllerBase,
+ // this is the method you will typically want to call.
+ TestNavigationEntry* activeEntry() const;
+
+ // Returns the index from which we would go back/forward or reload. This is
+ // the m_lastCommittedEntryIndex if m_pendingEntryIndex is -1. Otherwise,
+ // it is the m_pendingEntryIndex.
+ int currentEntryIndex() const;
+
+ // Returns the entry at the specified index. Returns 0 if out of bounds.
+ TestNavigationEntry* entryAtIndex(int) const;
+
+ // Return the entry with the corresponding type and page ID, or 0 if
+ // not found.
+ TestNavigationEntry* entryWithPageID(int32_t) const;
+
+ // Returns the index of the last committed entry.
+ int lastCommittedEntryIndex() const { return m_lastCommittedEntryIndex; }
+
+ // Used to inform us of a navigation being committed for a tab. Any entry
+ // located forward to the current entry will be deleted. The new entry
+ // becomes the current entry.
+ void didNavigateToEntry(TestNavigationEntry*);
+
+ // Used to inform us to discard its pending entry.
+ void discardPendingEntry();
+
+private:
+ // Inserts an entry after the current position, removing all entries after it.
+ // The new entry will become the active one.
+ void insertEntry(TestNavigationEntry*);
+
+ int maxPageID() const { return m_maxPageID; }
+ void navigateToPendingEntry(bool reload);
+
+ // Return the index of the entry with the corresponding type and page ID,
+ // or -1 if not found.
+ int entryIndexWithPageID(int32_t) const;
+
+ // Updates the max page ID with that of the given entry, if is larger.
+ void updateMaxPageID();
+
+ // List of NavigationEntry for this tab
+ typedef Vector<RefPtr<TestNavigationEntry> > NavigationEntryList;
+ typedef NavigationEntryList::iterator NavigationEntryListIterator;
+ NavigationEntryList m_entries;
+
+ // An entry we haven't gotten a response for yet. This will be discarded
+ // when we navigate again. It's used only so we know what the currently
+ // displayed tab is.
+ RefPtr<TestNavigationEntry> m_pendingEntry;
+
+ // currently visible entry
+ int m_lastCommittedEntryIndex;
+
+ // index of pending entry if it is in entries_, or -1 if pending_entry_ is a
+ // new entry (created by LoadURL).
+ int m_pendingEntryIndex;
+
+ NavigationHost* m_host;
+ int m_maxPageID;
+};
+
+#endif // TestNavigationController_h
+
diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h
new file mode 100644
index 000000000..9fa3fff3b
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h
@@ -0,0 +1,9 @@
+#include "bindings/npapi.h"
+
+// These are defined in WebCore/brdige/npapi.h and we need them on Linux/Win.
+#ifndef FALSE
+#define FALSE (0)
+#endif
+#ifndef TRUE
+#define TRUE (1)
+#endif
diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h
new file mode 100644
index 000000000..59ae666b9
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h
@@ -0,0 +1,8 @@
+#include "npapi.h"
+#include "bindings/npfunctions.h"
+
+// Non-standard event types can be passed to HandleEvent.
+// npapi.h that comes with WebKit.framework adds these events.
+#define getFocusEvent (osEvt + 16)
+#define loseFocusEvent (osEvt + 17)
+#define adjustCursorEvent (osEvt + 18)
diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h
new file mode 100644
index 000000000..597d4ad7c
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h
@@ -0,0 +1 @@
+#include "bindings/npruntime.h"
diff --git a/Tools/DumpRenderTree/chromium/TestShell.cpp b/Tools/DumpRenderTree/chromium/TestShell.cpp
new file mode 100644
index 000000000..f15cb444a
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShell.cpp
@@ -0,0 +1,768 @@
+/*
+ * 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 "TestShell.h"
+
+#include "DRTDevToolsAgent.h"
+#include "DRTDevToolsClient.h"
+#include "LayoutTestController.h"
+#include "platform/WebArrayBufferView.h"
+#include "WebCompositor.h"
+#include "WebDataSource.h"
+#include "WebDocument.h"
+#include "WebElement.h"
+#include "WebFrame.h"
+#include "WebHistoryItem.h"
+#include "WebIDBFactory.h"
+#include "WebTestingSupport.h"
+#include "platform/WebThread.h"
+#include "WebKit.h"
+#include "platform/WebKitPlatformSupport.h"
+#include "WebPermissions.h"
+#include "platform/WebPoint.h"
+#include "WebRuntimeFeatures.h"
+#include "WebScriptController.h"
+#include "WebSettings.h"
+#include "platform/WebSize.h"
+#include "WebSpeechInputControllerMock.h"
+#include "platform/WebString.h"
+#include "platform/WebURLRequest.h"
+#include "platform/WebURLResponse.h"
+#include "WebView.h"
+#include "WebViewHost.h"
+#include "skia/ext/platform_canvas.h"
+#include "webkit/support/webkit_support.h"
+#include "webkit/support/webkit_support_gfx.h"
+#include <algorithm>
+#include <cctype>
+#include <vector>
+#include <wtf/MD5.h>
+
+using namespace WebKit;
+using namespace std;
+
+// Content area size for newly created windows.
+static const int testWindowWidth = 800;
+static const int testWindowHeight = 600;
+
+// The W3C SVG layout tests use a different size than the other layout tests.
+static const int SVGTestWindowWidth = 480;
+static const int SVGTestWindowHeight = 360;
+
+static const char layoutTestsPattern[] = "/LayoutTests/";
+static const string::size_type layoutTestsPatternSize = sizeof(layoutTestsPattern) - 1;
+static const char fileUrlPattern[] = "file:/";
+static const char fileTestPrefix[] = "(file test):";
+static const char dataUrlPattern[] = "data:";
+static const string::size_type dataUrlPatternSize = sizeof(dataUrlPattern) - 1;
+
+// FIXME: Move this to a common place so that it can be shared with
+// WebCore::TransparencyWin::makeLayerOpaque().
+static void makeCanvasOpaque(SkCanvas* canvas)
+{
+ const SkBitmap& bitmap = canvas->getTopDevice()->accessBitmap(true);
+ ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
+
+ SkAutoLockPixels lock(bitmap);
+ 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] |= 0xFF000000; // Set alpha bits to 1.
+ }
+}
+
+TestShell::TestShell(bool testShellMode)
+ : m_testIsPending(false)
+ , m_testIsPreparing(false)
+ , m_focusedWidget(0)
+ , m_testShellMode(testShellMode)
+ , m_devTools(0)
+ , m_allowExternalPages(false)
+ , m_acceleratedCompositingForVideoEnabled(false)
+ , m_threadedCompositingEnabled(false)
+ , m_compositeToTexture(false)
+ , m_forceCompositingMode(false)
+ , m_accelerated2dCanvasEnabled(false)
+ , m_legacyAccelerated2dCanvasEnabled(false)
+ , m_acceleratedPaintingEnabled(false)
+ , m_perTilePaintingEnabled(false)
+ , m_stressOpt(false)
+ , m_stressDeopt(false)
+ , m_dumpWhenFinished(true)
+{
+ WebRuntimeFeatures::enableDataTransferItems(true);
+ WebRuntimeFeatures::enableGeolocation(true);
+ WebRuntimeFeatures::enablePointerLock(true);
+ WebRuntimeFeatures::enableIndexedDatabase(true);
+ WebRuntimeFeatures::enableFileSystem(true);
+ WebRuntimeFeatures::enableJavaScriptI18NAPI(true);
+ WebRuntimeFeatures::enableMediaStream(true);
+ WebRuntimeFeatures::enableWebAudio(true);
+ WebRuntimeFeatures::enableVideoTrack(true);
+ WebRuntimeFeatures::enableGamepad(true);
+
+ m_webPermissions = adoptPtr(new WebPermissions(this));
+ m_accessibilityController = adoptPtr(new AccessibilityController(this));
+ m_gamepadController = adoptPtr(new GamepadController(this));
+ m_layoutTestController = adoptPtr(new LayoutTestController(this));
+ m_eventSender = adoptPtr(new EventSender(this));
+ m_plainTextController = adoptPtr(new PlainTextController());
+ m_textInputController = adoptPtr(new TextInputController(this));
+#if ENABLE(NOTIFICATIONS)
+ m_notificationPresenter = adoptPtr(new NotificationPresenter(this));
+#endif
+ m_printer = m_testShellMode ? TestEventPrinter::createTestShellPrinter() : TestEventPrinter::createDRTPrinter();
+
+ WTF::initializeThreading();
+
+ if (m_threadedCompositingEnabled) {
+ m_webCompositorThread = adoptPtr(WebKit::webKitPlatformSupport()->createThread("Compositor"));
+ WebCompositor::initialize(m_webCompositorThread.get());
+ } else
+ WebCompositor::initialize(0);
+
+
+ // 30 second is the same as the value in Mac DRT.
+ // If we use a value smaller than the timeout value of
+ // (new-)run-webkit-tests, (new-)run-webkit-tests misunderstands that a
+ // timed-out DRT process was crashed.
+ m_timeout = 30 * 1000;
+
+ createMainWindow();
+}
+
+void TestShell::createMainWindow()
+{
+ m_drtDevToolsAgent = adoptPtr(new DRTDevToolsAgent);
+ m_webViewHost = adoptPtr(createNewWindow(WebURL(), m_drtDevToolsAgent.get()));
+ m_webView = m_webViewHost->webView();
+ m_drtDevToolsAgent->setWebView(m_webView);
+}
+
+TestShell::~TestShell()
+{
+ // Note: DevTools are closed together with all the other windows in the
+ // windows list.
+
+ // Destroy the WebView before its WebViewHost.
+ m_drtDevToolsAgent->setWebView(0);
+
+ WebCompositor::shutdown();
+}
+
+void TestShell::createDRTDevToolsClient(DRTDevToolsAgent* agent)
+{
+ m_drtDevToolsClient = adoptPtr(new DRTDevToolsClient(agent, m_devTools->webView()));
+}
+
+void TestShell::showDevTools()
+{
+ if (!m_devTools) {
+ WebURL url = webkit_support::GetDevToolsPathAsURL();
+ if (!url.isValid()) {
+ ASSERT(false);
+ return;
+ }
+ m_devTools = createNewWindow(url);
+ m_devTools->webView()->settings()->setMemoryInfoEnabled(true);
+ m_devTools->setLogConsoleOutput(false);
+ ASSERT(m_devTools);
+ createDRTDevToolsClient(m_drtDevToolsAgent.get());
+ }
+ m_devTools->show(WebKit::WebNavigationPolicyNewWindow);
+}
+
+void TestShell::closeDevTools()
+{
+ if (m_devTools) {
+ m_devTools->webView()->settings()->setMemoryInfoEnabled(false);
+ m_drtDevToolsAgent->reset();
+ m_drtDevToolsClient.clear();
+ closeWindow(m_devTools);
+ m_devTools = 0;
+ }
+}
+
+void TestShell::resetWebSettings(WebView& webView)
+{
+ m_prefs.reset();
+ m_prefs.acceleratedCompositingEnabled = true;
+ m_prefs.acceleratedCompositingForVideoEnabled = m_acceleratedCompositingForVideoEnabled;
+ m_prefs.compositeToTexture = m_compositeToTexture;
+ m_prefs.forceCompositingMode = m_forceCompositingMode;
+ m_prefs.accelerated2dCanvasEnabled = m_accelerated2dCanvasEnabled;
+ m_prefs.legacyAccelerated2dCanvasEnabled = m_legacyAccelerated2dCanvasEnabled;
+ m_prefs.acceleratedPaintingEnabled = m_acceleratedPaintingEnabled;
+ m_prefs.perTilePaintingEnabled = m_perTilePaintingEnabled;
+ m_prefs.applyTo(&webView);
+}
+
+void TestShell::runFileTest(const TestParams& params)
+{
+ ASSERT(params.testUrl.isValid());
+ m_testIsPreparing = true;
+ m_params = params;
+ string testUrl = m_params.testUrl.spec();
+
+ if (testUrl.find("loading/") != string::npos
+ || testUrl.find("loading\\") != string::npos)
+ m_layoutTestController->setShouldDumpFrameLoadCallbacks(true);
+
+ if (testUrl.find("compositing/") != string::npos || testUrl.find("compositing\\") != string::npos) {
+ m_prefs.acceleratedCompositingForVideoEnabled = true;
+ m_prefs.accelerated2dCanvasEnabled = true;
+ m_prefs.applyTo(m_webView);
+ }
+
+ if (testUrl.find("/dumpAsText/") != string::npos
+ || testUrl.find("\\dumpAsText\\") != string::npos) {
+ m_layoutTestController->setShouldDumpAsText(true);
+ m_layoutTestController->setShouldGeneratePixelResults(false);
+ }
+
+ if (testUrl.find("/inspector/") != string::npos
+ || testUrl.find("\\inspector\\") != string::npos)
+ showDevTools();
+
+ if (m_params.debugLayerTree)
+ m_layoutTestController->setShowDebugLayerTree(true);
+
+ if (m_dumpWhenFinished)
+ m_printer->handleTestHeader(testUrl.c_str());
+ loadURL(m_params.testUrl);
+
+ m_testIsPreparing = false;
+ waitTestFinished();
+}
+
+static inline bool isSVGTestURL(const WebURL& url)
+{
+ return url.isValid() && string(url.spec()).find("W3C-SVG-1.1") != string::npos;
+}
+
+void TestShell::resizeWindowForTest(WebViewHost* window, const WebURL& url)
+{
+ int width, height;
+ if (isSVGTestURL(url)) {
+ width = SVGTestWindowWidth;
+ height = SVGTestWindowHeight;
+ } else {
+ width = testWindowWidth;
+ height = testWindowHeight;
+ }
+ window->setWindowRect(WebRect(0, 0, width + virtualWindowBorder * 2, height + virtualWindowBorder * 2));
+}
+
+void TestShell::resetTestController()
+{
+ resetWebSettings(*webView());
+ m_webPermissions->reset();
+ m_accessibilityController->reset();
+ m_gamepadController->reset();
+ m_layoutTestController->reset();
+ m_eventSender->reset();
+ m_webViewHost->reset();
+#if ENABLE(NOTIFICATIONS)
+ m_notificationPresenter->reset();
+#endif
+ m_drtDevToolsAgent->reset();
+ if (m_drtDevToolsClient)
+ m_drtDevToolsClient->reset();
+ webView()->setPageScaleFactor(1, WebPoint(0, 0));
+ webView()->enableFixedLayoutMode(false);
+ webView()->setFixedLayoutSize(WebSize(0, 0));
+ webView()->mainFrame()->clearOpener();
+ WebTestingSupport::resetInternalsObject(webView()->mainFrame());
+}
+
+void TestShell::loadURL(const WebURL& url)
+{
+ m_webViewHost->loadURLForFrame(url, WebString());
+}
+
+void TestShell::reload()
+{
+ m_webViewHost->navigationController()->reload();
+}
+
+void TestShell::goToOffset(int offset)
+{
+ m_webViewHost->navigationController()->goToOffset(offset);
+}
+
+int TestShell::navigationEntryCount() const
+{
+ return m_webViewHost->navigationController()->entryCount();
+}
+
+void TestShell::callJSGC()
+{
+ m_webView->mainFrame()->collectGarbage();
+}
+
+void TestShell::setFocus(WebWidget* widget, bool enable)
+{
+ // Simulate the effects of InteractiveSetFocus(), which includes calling
+ // both setFocus() and setIsActive().
+ if (enable) {
+ if (m_focusedWidget != widget) {
+ if (m_focusedWidget)
+ m_focusedWidget->setFocus(false);
+ webView()->setIsActive(enable);
+ widget->setFocus(enable);
+ m_focusedWidget = widget;
+ }
+ } else {
+ if (m_focusedWidget == widget) {
+ widget->setFocus(enable);
+ webView()->setIsActive(enable);
+ m_focusedWidget = 0;
+ }
+ }
+}
+
+void TestShell::testFinished()
+{
+ if (!m_testIsPending)
+ return;
+ m_testIsPending = false;
+ if (m_dumpWhenFinished)
+ dump();
+ webkit_support::QuitMessageLoop();
+}
+
+void TestShell::testTimedOut()
+{
+ m_printer->handleTimedOut();
+ testFinished();
+}
+
+static string dumpDocumentText(WebFrame* frame)
+{
+ // We use the document element's text instead of the body text here because
+ // not all documents have a body, such as XML documents.
+ WebElement documentElement = frame->document().documentElement();
+ if (documentElement.isNull())
+ return string();
+ return documentElement.innerText().utf8();
+}
+
+static string dumpFramesAsText(WebFrame* frame, bool recursive)
+{
+ string result;
+
+ // Add header for all but the main frame. Skip empty frames.
+ if (frame->parent() && !frame->document().documentElement().isNull()) {
+ result.append("\n--------\nFrame: '");
+ result.append(frame->name().utf8().data());
+ result.append("'\n--------\n");
+ }
+
+ result.append(dumpDocumentText(frame));
+ result.append("\n");
+
+ if (recursive) {
+ for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
+ result.append(dumpFramesAsText(child, recursive));
+ }
+
+ return result;
+}
+
+static string dumpFramesAsPrintedText(WebFrame* frame, bool recursive)
+{
+ string result;
+
+ // Cannot do printed format for anything other than HTML
+ if (!frame->document().isHTMLDocument())
+ return string();
+
+ // Add header for all but the main frame. Skip empty frames.
+ if (frame->parent() && !frame->document().documentElement().isNull()) {
+ result.append("\n--------\nFrame: '");
+ result.append(frame->name().utf8().data());
+ result.append("'\n--------\n");
+ }
+
+ result.append(frame->renderTreeAsText(WebFrame::RenderAsTextPrinting).utf8());
+ result.append("\n");
+
+ if (recursive) {
+ for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
+ result.append(dumpFramesAsPrintedText(child, recursive));
+ }
+
+ return result;
+}
+
+static void dumpFrameScrollPosition(WebFrame* frame, bool recursive)
+{
+ WebSize offset = frame->scrollOffset();
+ if (offset.width > 0 || offset.height > 0) {
+ if (frame->parent())
+ printf("frame '%s' ", frame->name().utf8().data());
+ printf("scrolled to %d,%d\n", offset.width, offset.height);
+ }
+
+ if (!recursive)
+ return;
+ for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
+ dumpFrameScrollPosition(child, recursive);
+}
+
+struct ToLower {
+ char16 operator()(char16 c) { return tolower(c); }
+};
+
+// FIXME: Eliminate std::transform(), std::vector, and std::sort().
+
+// Returns True if item1 < item2.
+static bool HistoryItemCompareLess(const WebHistoryItem& item1, const WebHistoryItem& item2)
+{
+ string16 target1 = item1.target();
+ string16 target2 = item2.target();
+ std::transform(target1.begin(), target1.end(), target1.begin(), ToLower());
+ std::transform(target2.begin(), target2.end(), target2.begin(), ToLower());
+ return target1 < target2;
+}
+
+static string normalizeLayoutTestURLInternal(const string& url)
+{
+ string result = url;
+ size_t pos;
+ if (!url.find(fileUrlPattern) && ((pos = url.find(layoutTestsPattern)) != string::npos)) {
+ // adjust file URLs to match upstream results.
+ result.replace(0, pos + layoutTestsPatternSize, fileTestPrefix);
+ } else if (!url.find(dataUrlPattern)) {
+ // URL-escape data URLs to match results upstream.
+ string path = url.substr(dataUrlPatternSize);
+ result.replace(dataUrlPatternSize, url.length(), path);
+ }
+ return result;
+}
+
+static string dumpHistoryItem(const WebHistoryItem& item, int indent, bool isCurrent)
+{
+ string result;
+
+ if (isCurrent) {
+ result.append("curr->");
+ result.append(indent - 6, ' '); // 6 == "curr->".length()
+ } else
+ result.append(indent, ' ');
+
+ string url = normalizeLayoutTestURLInternal(item.urlString().utf8());
+ result.append(url);
+ if (!item.target().isEmpty()) {
+ result.append(" (in frame \"");
+ result.append(item.target().utf8());
+ result.append("\")");
+ }
+ if (item.isTargetItem())
+ result.append(" **nav target**");
+ result.append("\n");
+
+ const WebVector<WebHistoryItem>& children = item.children();
+ if (!children.isEmpty()) {
+ // Must sort to eliminate arbitrary result ordering which defeats
+ // reproducible testing.
+ // FIXME: WebVector should probably just be a std::vector!!
+ std::vector<WebHistoryItem> sortedChildren;
+ for (size_t i = 0; i < children.size(); ++i)
+ sortedChildren.push_back(children[i]);
+ std::sort(sortedChildren.begin(), sortedChildren.end(), HistoryItemCompareLess);
+ for (size_t i = 0; i < sortedChildren.size(); ++i)
+ result += dumpHistoryItem(sortedChildren[i], indent + 4, false);
+ }
+
+ return result;
+}
+
+static void dumpBackForwardList(const TestNavigationController& navigationController, string& result)
+{
+ result.append("\n============== Back Forward List ==============\n");
+ for (int index = 0; index < navigationController.entryCount(); ++index) {
+ int currentIndex = navigationController.lastCommittedEntryIndex();
+ WebHistoryItem historyItem = navigationController.entryAtIndex(index)->contentState();
+ if (historyItem.isNull()) {
+ historyItem.initialize();
+ historyItem.setURLString(navigationController.entryAtIndex(index)->URL().spec().utf16());
+ }
+ result.append(dumpHistoryItem(historyItem, 8, index == currentIndex));
+ }
+ result.append("===============================================\n");
+}
+
+string TestShell::dumpAllBackForwardLists()
+{
+ string result;
+ for (unsigned i = 0; i < m_windowList.size(); ++i)
+ dumpBackForwardList(*m_windowList[i]->navigationController(), result);
+ return result;
+}
+
+void TestShell::dump()
+{
+ WebScriptController::flushConsoleMessages();
+
+ // Dump the requested representation.
+ WebFrame* frame = m_webView->mainFrame();
+ if (!frame)
+ return;
+ bool shouldDumpAsText = m_layoutTestController->shouldDumpAsText();
+ bool shouldDumpAsAudio = m_layoutTestController->shouldDumpAsAudio();
+ bool shouldGeneratePixelResults = m_layoutTestController->shouldGeneratePixelResults();
+ bool shouldDumpAsPrinted = m_layoutTestController->isPrinting();
+ bool dumpedAnything = false;
+
+ if (shouldDumpAsAudio) {
+ m_printer->handleAudioHeader();
+
+ const WebKit::WebArrayBufferView& webArrayBufferView = m_layoutTestController->audioData();
+ printf("Content-Length: %d\n", webArrayBufferView.byteLength());
+
+ if (fwrite(webArrayBufferView.baseAddress(), 1, webArrayBufferView.byteLength(), stdout) != webArrayBufferView.byteLength())
+ FATAL("Short write to stdout, disk full?\n");
+ printf("\n");
+
+ m_printer->handleTestFooter(true);
+
+ fflush(stdout);
+ fflush(stderr);
+ return;
+ }
+
+ if (m_params.dumpTree) {
+ dumpedAnything = true;
+ m_printer->handleTextHeader();
+ // Text output: the test page can request different types of output
+ // which we handle here.
+ if (!shouldDumpAsText) {
+ // Plain text pages should be dumped as text
+ string mimeType = frame->dataSource()->response().mimeType().utf8();
+ if (mimeType == "text/plain") {
+ shouldDumpAsText = true;
+ shouldGeneratePixelResults = false;
+ }
+ }
+ if (shouldDumpAsText) {
+ bool recursive = m_layoutTestController->shouldDumpChildFramesAsText();
+ string dataUtf8 = shouldDumpAsPrinted ? dumpFramesAsPrintedText(frame, recursive) : dumpFramesAsText(frame, recursive);
+ if (fwrite(dataUtf8.c_str(), 1, dataUtf8.size(), stdout) != dataUtf8.size())
+ FATAL("Short write to stdout, disk full?\n");
+ } else {
+ WebFrame::RenderAsTextControls renderTextBehavior = WebFrame::RenderAsTextNormal;
+ if (shouldDumpAsPrinted)
+ renderTextBehavior |= WebFrame::RenderAsTextPrinting;
+ if (m_params.debugRenderTree)
+ renderTextBehavior |= WebFrame::RenderAsTextDebug;
+ printf("%s", frame->renderTreeAsText(renderTextBehavior).utf8().data());
+ bool recursive = m_layoutTestController->shouldDumpChildFrameScrollPositions();
+ dumpFrameScrollPosition(frame, recursive);
+ }
+ if (m_layoutTestController->shouldDumpBackForwardList())
+ printf("%s", dumpAllBackForwardLists().c_str());
+ }
+ if (dumpedAnything && m_params.printSeparators)
+ m_printer->handleTextFooter();
+
+ if (m_params.dumpPixels && shouldGeneratePixelResults) {
+ // Image output: we write the image data to the file given on the
+ // command line (for the dump pixels argument), and the MD5 sum to
+ // stdout.
+ dumpedAnything = true;
+ m_webView->layout();
+ if (m_layoutTestController->testRepaint()) {
+ WebSize viewSize = m_webView->size();
+ int width = viewSize.width;
+ int height = viewSize.height;
+ if (m_layoutTestController->sweepHorizontally()) {
+ for (WebRect column(0, 0, 1, height); column.x < width; column.x++)
+ m_webViewHost->paintRect(column);
+ } else {
+ for (WebRect line(0, 0, width, 1); line.y < height; line.y++)
+ m_webViewHost->paintRect(line);
+ }
+ } else if (m_layoutTestController->isPrinting())
+ m_webViewHost->paintPagesWithBoundaries();
+ else
+ m_webViewHost->paintInvalidatedRegion();
+
+ // See if we need to draw the selection bounds rect. Selection bounds
+ // rect is the rect enclosing the (possibly transformed) selection.
+ // The rect should be drawn after everything is laid out and painted.
+ if (m_layoutTestController->shouldDumpSelectionRect()) {
+ // If there is a selection rect - draw a red 1px border enclosing rect
+ WebRect wr = frame->selectionBoundsRect();
+ if (!wr.isEmpty()) {
+ // Render a red rectangle bounding selection rect
+ SkPaint paint;
+ paint.setColor(0xFFFF0000); // Fully opaque red
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ paint.setStrokeWidth(1.0f);
+ SkIRect rect; // Bounding rect
+ rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height);
+ m_webViewHost->canvas()->drawIRect(rect, paint);
+ }
+ }
+
+ dumpImage(m_webViewHost->canvas());
+ }
+ m_printer->handleImageFooter();
+ m_printer->handleTestFooter(dumpedAnything);
+ fflush(stdout);
+ fflush(stderr);
+}
+
+void TestShell::dumpImage(SkCanvas* canvas) const
+{
+ // Fix the alpha. The expected PNGs on Mac have an alpha channel, so we want
+ // to keep it. On Windows, the alpha channel is wrong since text/form control
+ // drawing may have erased it in a few places. So on Windows we force it to
+ // opaque and also don't write the alpha channel for the reference. Linux
+ // doesn't have the wrong alpha like Windows, but we match Windows.
+#if OS(MAC_OS_X)
+ bool discardTransparency = false;
+#else
+ bool discardTransparency = true;
+ makeCanvasOpaque(canvas);
+#endif
+
+ const SkBitmap& sourceBitmap = canvas->getTopDevice()->accessBitmap(false);
+ SkAutoLockPixels sourceBitmapLock(sourceBitmap);
+
+ // Compute MD5 sum.
+ MD5 digester;
+ Vector<uint8_t, 16> digestValue;
+ digester.addBytes(reinterpret_cast<const uint8_t*>(sourceBitmap.getPixels()), sourceBitmap.getSize());
+ digester.checksum(digestValue);
+ string md5hash;
+ md5hash.reserve(16 * 2);
+ for (unsigned i = 0; i < 16; ++i) {
+ char hex[3];
+ // Use "x", not "X". The string must be lowercased.
+ sprintf(hex, "%02x", digestValue[i]);
+ md5hash.append(hex);
+ }
+
+ // Only encode and dump the png if the hashes don't match. Encoding the
+ // image is really expensive.
+ if (md5hash.compare(m_params.pixelHash)) {
+ std::vector<unsigned char> png;
+ webkit_support::EncodeBGRAPNGWithChecksum(reinterpret_cast<const unsigned char*>(sourceBitmap.getPixels()), sourceBitmap.width(),
+ sourceBitmap.height(), static_cast<int>(sourceBitmap.rowBytes()), discardTransparency, md5hash, &png);
+
+ m_printer->handleImage(md5hash.c_str(), m_params.pixelHash.c_str(), &png[0], png.size(), m_params.pixelFileName.c_str());
+ } else
+ m_printer->handleImage(md5hash.c_str(), m_params.pixelHash.c_str(), 0, 0, m_params.pixelFileName.c_str());
+}
+
+void TestShell::bindJSObjectsToWindow(WebFrame* frame)
+{
+ WebTestingSupport::injectInternalsObject(frame);
+ m_accessibilityController->bindToJavascript(frame, WebString::fromUTF8("accessibilityController"));
+ m_gamepadController->bindToJavascript(frame, WebString::fromUTF8("gamepadController"));
+ m_layoutTestController->bindToJavascript(frame, WebString::fromUTF8("layoutTestController"));
+ m_eventSender->bindToJavascript(frame, WebString::fromUTF8("eventSender"));
+ m_plainTextController->bindToJavascript(frame, WebString::fromUTF8("plainText"));
+ m_textInputController->bindToJavascript(frame, WebString::fromUTF8("textInputController"));
+}
+
+WebViewHost* TestShell::createNewWindow(const WebKit::WebURL& url)
+{
+ return createNewWindow(url, 0);
+}
+
+WebViewHost* TestShell::createNewWindow(const WebKit::WebURL& url, DRTDevToolsAgent* devToolsAgent)
+{
+ WebViewHost* host = new WebViewHost(this);
+ WebView* view = WebView::create(host);
+ view->setPermissionClient(webPermissions());
+ view->setDevToolsAgentClient(devToolsAgent);
+ host->setWebWidget(view);
+ m_prefs.applyTo(view);
+ view->initializeMainFrame(host);
+ m_windowList.append(host);
+ host->loadURLForFrame(url, WebString());
+ return host;
+}
+
+void TestShell::closeWindow(WebViewHost* window)
+{
+ size_t i = m_windowList.find(window);
+ if (i == notFound) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ m_windowList.remove(i);
+ WebWidget* focusedWidget = m_focusedWidget;
+ if (window->webWidget() == m_focusedWidget)
+ focusedWidget = 0;
+
+ delete window;
+ // We set the focused widget after deleting the web view host because it
+ // can change the focus.
+ m_focusedWidget = focusedWidget;
+ if (m_focusedWidget) {
+ webView()->setIsActive(true);
+ m_focusedWidget->setFocus(true);
+ }
+}
+
+void TestShell::closeRemainingWindows()
+{
+ // Just close devTools window manually because we have custom deinitialization code for it.
+ closeDevTools();
+
+ // Iterate through the window list and close everything except the main
+ // window. We don't want to delete elements as we're iterating, so we copy
+ // to a temp vector first.
+ Vector<WebViewHost*> windowsToDelete;
+ for (unsigned i = 0; i < m_windowList.size(); ++i) {
+ if (m_windowList[i] != webViewHost())
+ windowsToDelete.append(m_windowList[i]);
+ }
+ ASSERT(windowsToDelete.size() + 1 == m_windowList.size());
+ for (unsigned i = 0; i < windowsToDelete.size(); ++i)
+ closeWindow(windowsToDelete[i]);
+ ASSERT(m_windowList.size() == 1);
+}
+
+int TestShell::windowCount()
+{
+ return m_windowList.size();
+}
+
+string TestShell::normalizeLayoutTestURL(const string& url)
+{
+ return normalizeLayoutTestURLInternal(url);
+}
diff --git a/Tools/DumpRenderTree/chromium/TestShell.h b/Tools/DumpRenderTree/chromium/TestShell.h
new file mode 100644
index 000000000..a095ef2d0
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShell.h
@@ -0,0 +1,253 @@
+/*
+ * 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 TestShell_h
+#define TestShell_h
+
+#include "AccessibilityController.h"
+#include "EventSender.h"
+#include "GamepadController.h"
+#include "LayoutTestController.h"
+#include "NotificationPresenter.h"
+#include "PlainTextController.h"
+#include "TestEventPrinter.h"
+#include "TextInputController.h"
+#include "WebPreferences.h"
+#include "WebViewHost.h"
+#include <string>
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+// TestShell is a container of global variables and has bridge functions between
+// various objects. Only one instance is created in one DRT process.
+
+namespace WebKit {
+class WebDevToolsAgentClient;
+class WebFrame;
+class WebNotificationPresenter;
+class WebThread;
+class WebView;
+class WebURL;
+}
+
+class DRTDevToolsAgent;
+class DRTDevToolsCallArgs;
+class DRTDevToolsClient;
+class WebPermissions;
+
+struct TestParams {
+ bool dumpTree;
+ bool dumpPixels;
+ bool debugRenderTree;
+ bool debugLayerTree;
+ bool printSeparators;
+ WebKit::WebURL testUrl;
+ // Resultant image file name. Required only if the test_shell mode.
+ std::string pixelFileName;
+ std::string pixelHash;
+
+ TestParams()
+ : dumpTree(true)
+ , dumpPixels(false)
+ , debugRenderTree(false)
+ , debugLayerTree(false)
+ , printSeparators(false) { }
+};
+
+class TestShell {
+public:
+ TestShell(bool testShellMode);
+ ~TestShell();
+
+ // The main WebView.
+ WebKit::WebView* webView() const { return m_webView; }
+ // Returns the host for the main WebView.
+ WebViewHost* webViewHost() const { return m_webViewHost.get(); }
+ LayoutTestController* layoutTestController() const { return m_layoutTestController.get(); }
+ EventSender* eventSender() const { return m_eventSender.get(); }
+ AccessibilityController* accessibilityController() const { return m_accessibilityController.get(); }
+ GamepadController* gamepadController() const { return m_gamepadController.get(); }
+ NotificationPresenter* notificationPresenter() const { return m_notificationPresenter.get(); }
+ TestEventPrinter* printer() const { return m_printer.get(); }
+
+ WebPreferences* preferences() { return &m_prefs; }
+ void applyPreferences() { m_prefs.applyTo(m_webView); }
+
+ WebPermissions* webPermissions() { return m_webPermissions.get(); }
+
+ void bindJSObjectsToWindow(WebKit::WebFrame*);
+ void runFileTest(const TestParams&);
+ void callJSGC();
+ void resetTestController();
+ void waitTestFinished();
+
+ // Operations to the main window.
+ void loadURL(const WebKit::WebURL&);
+ void reload();
+ void goToOffset(int offset);
+ int navigationEntryCount() const;
+
+ void setFocus(WebKit::WebWidget*, bool enable);
+ bool shouldDumpFrameLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpFrameLoadCallbacks(); }
+ bool shouldDumpUserGestureInFrameLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpUserGestureInFrameLoadCallbacks(); }
+ bool shouldDumpResourceLoadCallbacks() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpResourceLoadCallbacks(); }
+ bool shouldDumpResourceResponseMIMETypes() const { return (m_testIsPreparing || m_testIsPending) && layoutTestController()->shouldDumpResourceResponseMIMETypes(); }
+ void setIsLoading(bool flag) { m_isLoading = flag; }
+
+ // Called by the LayoutTestController to signal test completion.
+ void testFinished();
+ // Called by LayoutTestController when a test hits the timeout, but does not
+ // cause a hang. We can avoid killing TestShell in this case and still dump
+ // the test results.
+ void testTimedOut();
+
+ bool allowExternalPages() const { return m_allowExternalPages; }
+ void setAllowExternalPages(bool allowExternalPages) { m_allowExternalPages = allowExternalPages; }
+
+ void setAcceleratedCompositingForVideoEnabled(bool enabled) { m_acceleratedCompositingForVideoEnabled = enabled; }
+ void setThreadedCompositingEnabled(bool enabled) { m_threadedCompositingEnabled = enabled; }
+ void setCompositeToTexture(bool enabled) { m_compositeToTexture = enabled; }
+ void setForceCompositingMode(bool enabled) { m_forceCompositingMode = enabled; }
+ void setAccelerated2dCanvasEnabled(bool enabled) { m_accelerated2dCanvasEnabled = enabled; }
+ void setLegacyAccelerated2dCanvasEnabled(bool enabled) { m_legacyAccelerated2dCanvasEnabled = enabled; }
+ void setAcceleratedPaintingEnabled(bool enabled) { m_acceleratedPaintingEnabled = enabled; }
+ void setPerTilePaintingEnabled(bool enabled) { m_perTilePaintingEnabled = enabled; }
+#if defined(OS_WIN)
+ // Access to the finished event. Used by the static WatchDog thread.
+ HANDLE finishedEvent() { return m_finishedEvent; }
+#endif
+
+ // Get the timeout for running a test in milliseconds.
+ int layoutTestTimeout() { return m_timeout; }
+ int layoutTestTimeoutForWatchDog() { return layoutTestTimeout() + 1000; }
+ void setLayoutTestTimeout(int timeout) { m_timeout = timeout; }
+
+ // V8 JavaScript stress test options.
+ int stressOpt() { return m_stressOpt; }
+ void setStressOpt(bool stressOpt) { m_stressOpt = stressOpt; }
+ int stressDeopt() { return m_stressDeopt; }
+ void setStressDeopt(int stressDeopt) { m_stressDeopt = stressDeopt; }
+
+ // The JavaScript flags specified as a strings.
+ std::string javaScriptFlags() { return m_javaScriptFlags; }
+ void setJavaScriptFlags(std::string javaScriptFlags) { m_javaScriptFlags = javaScriptFlags; }
+
+ // Set whether to dump when the loaded page has finished processing. This is used with multiple load
+ // testing where we only want to have the output from the last load.
+ void setDumpWhenFinished(bool dumpWhenFinished) { m_dumpWhenFinished = dumpWhenFinished; }
+
+ WebViewHost* createNewWindow(const WebKit::WebURL&);
+ void closeWindow(WebViewHost*);
+ void closeRemainingWindows();
+ int windowCount();
+ static void resizeWindowForTest(WebViewHost*, const WebKit::WebURL&);
+
+ void showDevTools();
+ void closeDevTools();
+
+ DRTDevToolsAgent* drtDevToolsAgent() { return m_drtDevToolsAgent.get(); }
+ DRTDevToolsClient* drtDevToolsClient() { return m_drtDevToolsClient.get(); }
+ WebViewHost* devToolsWebView() { return m_devTools; }
+
+ static const int virtualWindowBorder = 3;
+
+ typedef Vector<WebViewHost*> WindowList;
+ WindowList windowList() const { return m_windowList; }
+
+ // Returns a string representation of an URL's spec that does not depend on
+ // the location of the layout test in the file system.
+ std::string normalizeLayoutTestURL(const std::string&);
+
+private:
+ WebViewHost* createNewWindow(const WebKit::WebURL&, DRTDevToolsAgent*);
+ void createMainWindow();
+ void createDRTDevToolsClient(DRTDevToolsAgent*);
+
+ void resetWebSettings(WebKit::WebView&);
+ void dump();
+ std::string dumpAllBackForwardLists();
+ void dumpImage(SkCanvas*) const;
+
+ bool m_testIsPending;
+ bool m_testIsPreparing;
+ bool m_isLoading;
+ WebKit::WebView* m_webView;
+ WebKit::WebWidget* m_focusedWidget;
+ bool m_testShellMode;
+ WebViewHost* m_devTools;
+
+ // Be careful of the destruction order of the following objects.
+ OwnPtr<TestEventPrinter> m_printer;
+ OwnPtr<WebPermissions> m_webPermissions;
+ OwnPtr<DRTDevToolsAgent> m_drtDevToolsAgent;
+ OwnPtr<DRTDevToolsClient> m_drtDevToolsClient;
+ OwnPtr<AccessibilityController> m_accessibilityController;
+ OwnPtr<GamepadController> m_gamepadController;
+ OwnPtr<EventSender> m_eventSender;
+ OwnPtr<LayoutTestController> m_layoutTestController;
+ OwnPtr<PlainTextController> m_plainTextController;
+ OwnPtr<TextInputController> m_textInputController;
+ OwnPtr<NotificationPresenter> m_notificationPresenter;
+ OwnPtr<WebViewHost> m_webViewHost;
+ OwnPtr<WebKit::WebThread> m_webCompositorThread;
+
+ TestParams m_params;
+ int m_timeout; // timeout value in millisecond
+ bool m_allowExternalPages;
+ bool m_acceleratedCompositingForVideoEnabled;
+ bool m_threadedCompositingEnabled;
+ bool m_compositeToTexture;
+ bool m_forceCompositingMode;
+ bool m_accelerated2dCanvasEnabled;
+ bool m_legacyAccelerated2dCanvasEnabled;
+ bool m_acceleratedPaintingEnabled;
+ bool m_perTilePaintingEnabled;
+ WebPreferences m_prefs;
+ bool m_stressOpt;
+ bool m_stressDeopt;
+ std::string m_javaScriptFlags;
+ bool m_dumpWhenFinished;
+
+
+ // List of all windows in this process.
+ // The main window should be put into windowList[0].
+ WindowList m_windowList;
+
+#if defined(OS_WIN)
+ // Used by the watchdog to know when it's finished.
+ HANDLE m_finishedEvent;
+#endif
+};
+
+void platformInit(int*, char***);
+void openStartupDialog();
+bool checkLayoutTestSystemDependencies();
+
+#endif // TestShell_h
diff --git a/Tools/DumpRenderTree/chromium/TestShellGtk.cpp b/Tools/DumpRenderTree/chromium/TestShellGtk.cpp
new file mode 100644
index 000000000..4228f2afd
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellGtk.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "TestShell.h"
+
+#include "webkit/support/webkit_support.h"
+#include <fontconfig/fontconfig.h>
+#include <gtk/gtk.h>
+#include <signal.h>
+
+
+void openStartupDialog()
+{
+ GtkWidget* dialog = gtk_message_dialog_new(
+ 0, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Attach to me?");
+ gtk_window_set_title(GTK_WINDOW(dialog), "DumpRenderTree");
+ gtk_dialog_run(GTK_DIALOG(dialog)); // Runs a nested message loop.
+ gtk_widget_destroy(dialog);
+}
+
+bool checkLayoutTestSystemDependencies()
+{
+ return true;
+}
diff --git a/Tools/DumpRenderTree/chromium/TestShellLinux.cpp b/Tools/DumpRenderTree/chromium/TestShellLinux.cpp
new file mode 100644
index 000000000..82db69a2f
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellLinux.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2011 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 "TestShell.h"
+
+#include "SkTypeface.h"
+#include "WebView.h"
+#include "webkit/support/webkit_support.h"
+
+#if !OS(ANDROID)
+#include <fontconfig/fontconfig.h>
+#endif
+
+#if USE(GTK)
+#include <gtk/gtk.h>
+#endif
+#include <signal.h>
+#include <unistd.h>
+
+static void AlarmHandler(int)
+{
+ // If the alarm alarmed, kill the process since we have a really bad hang.
+ puts("\n#TEST_TIMED_OUT\n");
+ puts("#EOF\n");
+ fflush(stdout);
+ exit(0);
+}
+
+void TestShell::waitTestFinished()
+{
+ ASSERT(!m_testIsPending);
+ m_testIsPending = true;
+
+ // Install an alarm signal handler that will kill us if we time out.
+ struct sigaction alarmAction;
+ alarmAction.sa_handler = AlarmHandler;
+ sigemptyset(&alarmAction.sa_mask);
+ alarmAction.sa_flags = 0;
+
+ struct sigaction oldAction;
+ sigaction(SIGALRM, &alarmAction, &oldAction);
+ alarm(layoutTestTimeoutForWatchDog() / 1000);
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (m_testIsPending)
+ webkit_support::RunMessageLoop();
+
+ // Remove the alarm.
+ alarm(0);
+ sigaction(SIGALRM, &oldAction, 0);
+}
+
+#if !OS(ANDROID)
+static void setupFontconfig()
+{
+ // We wish to make the layout tests reproducable with respect to fonts. Skia
+ // uses fontconfig to resolve font family names from WebKit into actual font
+ // files found on the current system. This means that fonts vary based on the
+ // system and also on the fontconfig configuration.
+ //
+ // To avoid this we initialise fontconfig here and install a configuration
+ // which only knows about a few, select, fonts.
+
+ // We have fontconfig parse a config file from our resources file. This
+ // sets a number of aliases ("sans"->"Arial" etc), but doesn't include any
+ // font directories.
+ FcInit();
+
+ char drtPath[PATH_MAX + 1];
+ int drtPathSize = readlink("/proc/self/exe", drtPath, PATH_MAX);
+ if (drtPathSize < 0 || drtPathSize > PATH_MAX) {
+ fputs("Unable to resolve /proc/self/exe.", stderr);
+ exit(1);
+ }
+ drtPath[drtPathSize] = 0;
+ std::string drtDirPath(drtPath);
+ size_t lastPathPos = drtDirPath.rfind("/");
+ ASSERT(lastPathPos != std::string::npos);
+ drtDirPath.erase(lastPathPos + 1);
+
+ FcConfig* fontcfg = FcConfigCreate();
+ std::string fontconfigPath = drtDirPath + "fonts.conf";
+ if (!FcConfigParseAndLoad(fontcfg, reinterpret_cast<const FcChar8*>(fontconfigPath.c_str()), true)) {
+ fputs("Failed to parse fontconfig config file\n", stderr);
+ exit(1);
+ }
+
+ // This is the list of fonts that fontconfig will know about. It
+ // will try its best to match based only on the fonts here in. The
+ // paths are where these fonts are found on our Ubuntu boxes.
+ static const char *const fonts[] = {
+ "/usr/share/fonts/truetype/kochi/kochi-gothic.ttf",
+ "/usr/share/fonts/truetype/kochi/kochi-mincho.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Arial_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Arial_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Arial_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Courier_New.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Courier_New_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Georgia_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Georgia_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Impact.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Trebuchet_MS_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Verdana.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Verdana_Bold.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Verdana_Bold_Italic.ttf",
+ "/usr/share/fonts/truetype/msttcorefonts/Verdana_Italic.ttf",
+ "/usr/share/fonts/truetype/thai/Garuda.ttf",
+ // The DejaVuSans font is used by the css2.1 tests.
+ "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf",
+ "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_hi.ttf",
+ "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_ta.ttf",
+ "/usr/share/fonts/truetype/ttf-indic-fonts-core/MuktiNarrow.ttf",
+ };
+ for (size_t i = 0; i < arraysize(fonts); ++i) {
+ if (access(fonts[i], R_OK)) {
+ fprintf(stderr, "You are missing %s. Try re-running build/install-build-deps.sh. Also see "
+ "http://code.google.com/p/chromium/wiki/LayoutTestsLinux",
+ fonts[i]);
+ exit(1);
+ }
+ if (!FcConfigAppFontAddFile(fontcfg, (FcChar8 *) fonts[i])) {
+ fprintf(stderr, "Failed to load font %s\n", fonts[i]);
+ exit(1);
+ }
+ }
+
+ // We special case these fonts because they're only needed in a
+ // few layout tests.
+ static const char* const optionalFonts[] = {
+ "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_pa.ttf",
+ };
+ for (size_t i = 0; i < arraysize(optionalFonts); ++i) {
+ const char* font = optionalFonts[i];
+
+ // This font changed paths across Ubuntu releases, so try checking in both locations.
+ if (!strcmp(font, "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_pa.ttf")
+ && access(font, R_OK) < 0)
+ font = "/usr/share/fonts/truetype/ttf-punjabi-fonts/lohit_pa.ttf";
+
+ if (access(font, R_OK) < 0) {
+ fprintf(stderr, "You are missing %s. Without this, some layout tests may fail. "
+ "See http://code.google.com/p/chromium/wiki/LayoutTestsLinux "
+ "for more.\n", font);
+ } else if (!FcConfigAppFontAddFile(fontcfg, (FcChar8 *) font)) {
+ fprintf(stderr, "Failed to load font %s\n", font);
+ exit(1);
+ }
+ }
+
+ // Also load the layout-test-specific "Ahem" font.
+ std::string ahemPath = drtDirPath + "AHEM____.TTF";
+ if (!FcConfigAppFontAddFile(fontcfg, reinterpret_cast<const FcChar8*>(ahemPath.c_str()))) {
+ fprintf(stderr, "Failed to load font %s\n", ahemPath.c_str());
+ exit(1);
+ }
+
+ if (!FcConfigSetCurrent(fontcfg)) {
+ fputs("Failed to set the default font configuration\n", stderr);
+ exit(1);
+ }
+}
+#endif // !OS(ANDROID)
+
+void platformInit(int* argc, char*** argv)
+{
+ // FIXME: It's better call gtk_init() only when we run plugin tests.
+ // See http://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/633ea167cde196ca#
+#if USE(GTK)
+ gtk_init(argc, argv);
+#endif
+
+#if !OS(ANDROID)
+ setupFontconfig();
+#endif
+}
+
diff --git a/Tools/DumpRenderTree/chromium/TestShellMac.mm b/Tools/DumpRenderTree/chromium/TestShellMac.mm
new file mode 100644
index 000000000..d79a8c835
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellMac.mm
@@ -0,0 +1,149 @@
+/*
+ * 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 "TestShell.h"
+#include "WebThemeEngineDRTMac.h"
+#include "webkit/support/webkit_support.h"
+#import <AppKit/AppKit.h>
+
+static WebThemeEngineDRTMac themeEngine;
+
+// A class to be the target/selector of the "watchdog" thread that ensures
+// pages timeout if they take too long and tells the test harness via stdout.
+@interface WatchDogTarget : NSObject {
+@private
+ NSTimeInterval _timeout;
+}
+// |timeout| is in seconds
+- (id)initWithTimeout:(NSTimeInterval)timeout;
+// serves as the "run" method of a NSThread.
+- (void)run:(id)sender;
+@end
+
+@implementation WatchDogTarget
+
+- (id)initWithTimeout:(NSTimeInterval)timeout
+{
+ if ((self = [super init]))
+ _timeout = timeout;
+ return self;
+}
+
+- (void)run:(id)ignore
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ // check for debugger, just bail if so. We don't want the timeouts hitting
+ // when we're trying to track down an issue.
+ if (webkit_support::BeingDebugged())
+ return;
+
+ NSThread* currentThread = [NSThread currentThread];
+
+ // Wait to be cancelled. If we are that means the test finished. If it hasn't,
+ // then we need to tell the layout script we timed out and start again.
+ NSDate* limitDate = [NSDate dateWithTimeIntervalSinceNow:_timeout];
+ while ([(NSDate*)[NSDate date] compare:limitDate] == NSOrderedAscending &&
+ ![currentThread isCancelled]) {
+ // sleep for a small increment then check again
+ NSDate* incrementDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
+ [NSThread sleepUntilDate:incrementDate];
+ }
+ if (![currentThread isCancelled]) {
+ // Print a warning to be caught by the layout-test script.
+ // Note: the layout test driver may or may not recognize
+ // this as a timeout.
+ puts("#TEST_TIMED_OUT\n");
+ puts("#EOF\n");
+ fflush(stdout);
+ exit(0);
+ }
+
+ [pool release];
+}
+
+@end
+
+void TestShell::waitTestFinished()
+{
+ ASSERT(!m_testIsPending);
+
+ m_testIsPending = true;
+
+ // Create a watchdog thread which just sets a timer and
+ // kills the process if it times out. This catches really
+ // bad hangs where the shell isn't coming back to the
+ // message loop. If the watchdog is what catches a
+ // timeout, it can't do anything except terminate the test
+ // shell, which is unfortunate.
+ // Windows multiplies by 2.5, but that causes us to run for far, far too
+ // long. We use the passed value and let the scripts flag override
+ // the value as needed.
+ NSTimeInterval timeoutSeconds = layoutTestTimeoutForWatchDog() / 1000;
+ WatchDogTarget* watchdog = [[[WatchDogTarget alloc]
+ initWithTimeout:timeoutSeconds] autorelease];
+ NSThread* thread = [[NSThread alloc] initWithTarget:watchdog
+ selector:@selector(run:)
+ object:nil];
+ [thread start];
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (m_testIsPending)
+ webkit_support::RunMessageLoop();
+
+ // Tell the watchdog that we're finished. No point waiting to re-join, it'll
+ // die on its own.
+ [thread cancel];
+ [thread release];
+}
+
+void platformInit(int*, char***)
+{
+ webkit_support::SetThemeEngine(&themeEngine);
+}
+
+void openStartupDialog()
+{
+ // FIXME: This code doesn't work. Need NSApplication event loop?
+ NSAlert* alert = [[[NSAlert alloc] init] autorelease];
+ alert.messageText = @"Attach to me?";
+ alert.informativeText = @"This would probably be a good time to attach your debugger.";
+ [alert addButtonWithTitle:@"OK"];
+ [alert runModal];
+}
+
+bool checkLayoutTestSystemDependencies()
+{
+ return true;
+}
+
diff --git a/Tools/DumpRenderTree/chromium/TestShellStub.cpp b/Tools/DumpRenderTree/chromium/TestShellStub.cpp
new file mode 100644
index 000000000..6c34f84b3
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellStub.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 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 "TestShell.h"
+
+bool checkLayoutTestSystemDependencies()
+{
+ return true;
+}
+
+void openStartupDialog()
+{
+ // FIXME: Not implemented.
+}
+
diff --git a/Tools/DumpRenderTree/chromium/TestShellWin.cpp b/Tools/DumpRenderTree/chromium/TestShellWin.cpp
new file mode 100644
index 000000000..850e5de81
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellWin.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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 "TestShell.h"
+
+#include "WebThemeEngineDRTWin.h"
+#include "webkit/support/webkit_support.h"
+#include <fcntl.h>
+#include <io.h>
+#include <list>
+#include <process.h>
+#include <shlwapi.h>
+#include <string>
+#include <sys/stat.h>
+#include <windows.h>
+
+#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \
+ offsetof(structName, member) + \
+ (sizeof static_cast<structName*>(0)->member)
+#define NONCLIENTMETRICS_SIZE_PRE_VISTA \
+ SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)
+
+// Theme engine
+static WebThemeEngineDRTWin themeEngine;
+
+// Thread main to run for the thread which just tests for timeout.
+unsigned int __stdcall watchDogThread(void* arg)
+{
+ // If we're debugging a layout test, don't timeout.
+ if (::IsDebuggerPresent())
+ return 0;
+
+ TestShell* shell = static_cast<TestShell*>(arg);
+ // FIXME: Do we need user-specified time settings as with the original
+ // Chromium implementation?
+ DWORD timeout = static_cast<DWORD>(shell->layoutTestTimeoutForWatchDog());
+ DWORD rv = WaitForSingleObject(shell->finishedEvent(), timeout);
+ if (rv == WAIT_TIMEOUT) {
+ // Print a warning to be caught by the layout-test script.
+ // Note: the layout test driver may or may not recognize
+ // this as a timeout.
+ puts("\n#TEST_TIMED_OUT\n");
+ puts("#EOF\n");
+ fflush(stdout);
+ TerminateProcess(GetCurrentProcess(), 0);
+ }
+ // Finished normally.
+ return 0;
+}
+
+void TestShell::waitTestFinished()
+{
+ DCHECK(!m_testIsPending) << "cannot be used recursively";
+
+ m_testIsPending = true;
+
+ // Create a watchdog thread which just sets a timer and
+ // kills the process if it times out. This catches really
+ // bad hangs where the shell isn't coming back to the
+ // message loop. If the watchdog is what catches a
+ // timeout, it can't do anything except terminate the test
+ // shell, which is unfortunate.
+ m_finishedEvent = CreateEvent(0, TRUE, FALSE, 0);
+ DCHECK(m_finishedEvent);
+
+ HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(
+ 0,
+ 0,
+ &watchDogThread,
+ this,
+ 0,
+ 0));
+ DCHECK(threadHandle);
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (m_testIsPending)
+ webkit_support::RunMessageLoop();
+
+ // Tell the watchdog that we are finished.
+ SetEvent(m_finishedEvent);
+
+ // Wait to join the watchdog thread. (up to 1s, then quit)
+ WaitForSingleObject(threadHandle, 1000);
+}
+
+void platformInit(int*, char***)
+{
+ // Set stdout/stderr binary mode.
+ _setmode(_fileno(stdout), _O_BINARY);
+ _setmode(_fileno(stderr), _O_BINARY);
+
+ // Set theme engine.
+ webkit_support::SetThemeEngine(&themeEngine);
+
+ // Load Ahem font.
+ // AHEM____.TTF is copied to the directory of DumpRenderTree.exe by WebKit.gyp.
+ WCHAR path[_MAX_PATH];
+ if (!::GetModuleFileName(0, path, _MAX_PATH)) {
+ fprintf(stderr, "Can't get the module path.\n");
+ exit(1);
+ }
+ ::PathRemoveFileSpec(path);
+ wcscat_s(path, _MAX_PATH, L"/AHEM____.TTF");
+ struct _stat ahemStat;
+ if (_wstat(path, &ahemStat) == -1) {
+ fprintf(stderr, "Can't access: '%S'\n", path);
+ exit(1);
+ }
+
+ FILE* fp = _wfopen(path, L"rb");
+ if (!fp) {
+ _wperror(path);
+ exit(1);
+ }
+ size_t size = ahemStat.st_size;
+ char* fontBuffer = new char[size];
+ if (fread(fontBuffer, 1, size, fp) != size) {
+ fprintf(stderr, "Can't read the font: '%S'\n", path);
+ fclose(fp);
+ exit(1);
+ }
+ fclose(fp);
+ DWORD numFonts = 1;
+ HANDLE fontHandle = ::AddFontMemResourceEx(fontBuffer, size, 0, &numFonts);
+ delete[] fontBuffer; // OS owns a copy of the buffer.
+ if (!fontHandle) {
+ fprintf(stderr, "Failed to register Ahem font: '%S'\n", path);
+ exit(1);
+ }
+ // We don't need to release the font explicitly.
+}
+
+void openStartupDialog()
+{
+ ::MessageBox(0, L"Attach to me?", L"DumpRenderTree", MB_OK);
+}
+
+bool checkLayoutTestSystemDependencies()
+{
+ // This metric will be 17 when font size is "Normal".
+ // The size of drop-down menus depends on it.
+ int verticalScrollSize = ::GetSystemMetrics(SM_CXVSCROLL);
+ int requiredVScrollSize = 17;
+ std::list<std::string> errors;
+ if (verticalScrollSize != requiredVScrollSize)
+ errors.push_back("Must use normal size fonts (96 dpi).");
+
+ // ClearType must be disabled, because the rendering is unpredictable.
+ BOOL fontSmoothingEnabled;
+ ::SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0);
+ int fontSmoothingType;
+ ::SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &fontSmoothingType, 0);
+ if (fontSmoothingEnabled && (fontSmoothingType == FE_FONTSMOOTHINGCLEARTYPE))
+ errors.push_back("ClearType must be disabled.");
+
+ // Check that we're using the default system fonts.
+ OSVERSIONINFO versionInfo = {0};
+ versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+ ::GetVersionEx(&versionInfo);
+ const bool isVistaOrLater = (versionInfo.dwMajorVersion >= 6);
+ NONCLIENTMETRICS metrics = {0};
+ metrics.cbSize = isVistaOrLater ? (sizeof NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
+ const bool success = !!::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
+ ASSERT(success);
+ LOGFONTW* systemFonts[] =
+ {&metrics.lfStatusFont, &metrics.lfMenuFont, &metrics.lfSmCaptionFont};
+ const wchar_t* const requiredFont = isVistaOrLater ? L"Segoe UI" : L"Tahoma";
+ const int requiredFontSize = isVistaOrLater ? -12 : -11;
+ for (size_t i = 0; i < arraysize(systemFonts); ++i) {
+ if (systemFonts[i]->lfHeight != requiredFontSize || wcscmp(requiredFont, systemFonts[i]->lfFaceName)) {
+ errors.push_back(isVistaOrLater ? "Must use either the Aero or Basic theme." : "Must use the default XP theme (Luna).");
+ break;
+ }
+ }
+
+ if (!errors.empty()) {
+ fprintf(stderr, "%s",
+ "##################################################################\n"
+ "## Layout test system dependencies check failed.\n"
+ "##\n");
+ for (std::list<std::string>::iterator it = errors.begin(); it != errors.end(); ++it)
+ fprintf(stderr, "## %s\n", it->c_str());
+ fprintf(stderr, "%s",
+ "##\n"
+ "##################################################################\n");
+ }
+ return errors.empty();
+}
diff --git a/Tools/DumpRenderTree/chromium/TestWebPlugin.cpp b/Tools/DumpRenderTree/chromium/TestWebPlugin.cpp
new file mode 100644
index 000000000..ac2336664
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestWebPlugin.cpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "TestWebPlugin.h"
+
+#include "WebFrame.h"
+#include "platform/WebGraphicsContext3D.h"
+#include "WebKit.h"
+#include "platform/WebKitPlatformSupport.h"
+#include "WebPluginContainer.h"
+#include "WebPluginParams.h"
+#include <wtf/Assertions.h>
+#include <wtf/text/CString.h>
+
+using namespace WebKit;
+
+// GLenum values copied from gl2.h.
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_ONE 1
+#define GL_TRIANGLES 0x0004
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_BLEND 0x0BE2
+#define GL_FLOAT 0x1406
+#define GL_COLOR_BUFFER_BIT 0x4000
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_STATIC_DRAW 0x88E4
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+
+static void premultiplyAlpha(const unsigned colorIn[3], float alpha, float colorOut[4])
+{
+ for (int i = 0; i < 3; ++i)
+ colorOut[i] = (colorIn[i] / 255.0f) * alpha;
+
+ colorOut[3] = alpha;
+}
+
+TestWebPlugin::TestWebPlugin(WebKit::WebFrame* frame,
+ const WebKit::WebPluginParams& params)
+ : m_frame(frame)
+ , m_container(0)
+ , m_context(0)
+{
+ static const WebString kAttributePrimitive = WebString::fromUTF8("primitive");
+ static const WebString kAttributeBackgroundColor = WebString::fromUTF8("background-color");
+ static const WebString kAttributePrimitiveColor = WebString::fromUTF8("primitive-color");
+ static const WebString kAttributeOpacity = WebString::fromUTF8("opacity");
+
+ ASSERT(params.attributeNames.size() == params.attributeValues.size());
+ size_t size = params.attributeNames.size();
+ for (size_t i = 0; i < size; ++i) {
+ const WebString& attributeName = params.attributeNames[i];
+ const WebString& attributeValue = params.attributeValues[i];
+
+ if (attributeName == kAttributePrimitive)
+ m_scene.primitive = parsePrimitive(attributeValue);
+ else if (attributeName == kAttributeBackgroundColor)
+ parseColor(attributeValue, m_scene.backgroundColor);
+ else if (attributeName == kAttributePrimitiveColor)
+ parseColor(attributeValue, m_scene.primitiveColor);
+ else if (attributeName == kAttributeOpacity)
+ m_scene.opacity = parseOpacity(attributeValue);
+ }
+}
+
+TestWebPlugin::~TestWebPlugin()
+{
+}
+
+const WebString& TestWebPlugin::mimeType()
+{
+ static const WebString kMimeType = WebString::fromUTF8("application/x-webkit-test-webplugin");
+ return kMimeType;
+}
+
+bool TestWebPlugin::initialize(WebPluginContainer* container)
+{
+ m_context = webKitPlatformSupport()->createGraphicsContext3D();
+ if (!m_context)
+ return false;
+
+ WebGraphicsContext3D::Attributes attrs;
+ if (!m_context->initialize(attrs, m_frame->view(), false))
+ return false;
+
+ if (!m_context->makeContextCurrent())
+ return false;
+
+ if (!initScene())
+ return false;
+
+ m_container = container;
+ m_container->setBackingTextureId(m_context->getPlatformTextureId());
+ return true;
+}
+
+void TestWebPlugin::destroy()
+{
+ destroyScene();
+
+ delete m_context;
+ m_context = 0;
+
+ m_container = 0;
+ m_frame = 0;
+}
+
+void TestWebPlugin::updateGeometry(const WebRect& frameRect,
+ const WebRect& clipRect,
+ const WebVector<WebRect>& cutOutsRects,
+ bool isVisible)
+{
+ if (clipRect == m_rect)
+ return;
+ m_rect = clipRect;
+
+ m_context->reshape(m_rect.width, m_rect.height);
+ drawScene();
+ m_context->prepareTexture();
+
+ m_container->commitBackingTexture();
+}
+
+TestWebPlugin::Primitive TestWebPlugin::parsePrimitive(const WebString& string)
+{
+ static const WebString kPrimitiveNone = WebString::fromUTF8("none");
+ static const WebString kPrimitiveTriangle = WebString::fromUTF8("triangle");
+
+ Primitive primitive = PrimitiveNone;
+ if (string == kPrimitiveNone)
+ primitive = PrimitiveNone;
+ else if (string == kPrimitiveTriangle)
+ primitive = PrimitiveTriangle;
+ else
+ ASSERT_NOT_REACHED();
+ return primitive;
+}
+
+// FIXME: This method should already exist. Use it.
+// For now just parse primary colors.
+void TestWebPlugin::parseColor(const WebString& string, unsigned color[3])
+{
+ color[0] = color[1] = color[2] = 0;
+ if (string == "black")
+ return;
+
+ if (string == "red")
+ color[0] = 255;
+ else if (string == "green")
+ color[1] = 255;
+ else if (string == "blue")
+ color[2] = 255;
+ else
+ ASSERT_NOT_REACHED();
+}
+
+float TestWebPlugin::parseOpacity(const WebString& string)
+{
+ return static_cast<float>(atof(string.utf8().data()));
+}
+
+bool TestWebPlugin::initScene()
+{
+ float color[4];
+ premultiplyAlpha(m_scene.backgroundColor, m_scene.opacity, color);
+ m_context->clearColor(color[0], color[1], color[2], color[3]);
+
+ m_context->enable(GL_BLEND);
+ m_context->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ return m_scene.primitive != PrimitiveNone ? initProgram() && initPrimitive() : true;
+}
+
+void TestWebPlugin::drawScene()
+{
+ m_context->viewport(0, 0, m_rect.width, m_rect.height);
+ m_context->clear(GL_COLOR_BUFFER_BIT);
+
+ if (m_scene.primitive != PrimitiveNone)
+ drawPrimitive();
+}
+
+void TestWebPlugin::destroyScene()
+{
+ if (m_scene.program) {
+ m_context->deleteProgram(m_scene.program);
+ m_scene.program = 0;
+ }
+ if (m_scene.vbo) {
+ m_context->deleteBuffer(m_scene.vbo);
+ m_scene.vbo = 0;
+ }
+}
+
+bool TestWebPlugin::initProgram()
+{
+ const CString vertexSource(
+ "attribute vec4 position; \n"
+ "void main() { \n"
+ " gl_Position = position; \n"
+ "} \n"
+ );
+
+ const CString fragmentSource(
+ "precision mediump float; \n"
+ "uniform vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color; \n"
+ "} \n"
+ );
+
+ m_scene.program = loadProgram(vertexSource, fragmentSource);
+ if (!m_scene.program)
+ return false;
+
+ m_scene.colorLocation = m_context->getUniformLocation(m_scene.program, "color");
+ m_scene.positionLocation = m_context->getAttribLocation(m_scene.program, "position");
+ return true;
+}
+
+bool TestWebPlugin::initPrimitive()
+{
+ ASSERT(m_scene.primitive == PrimitiveTriangle);
+
+ m_scene.vbo = m_context->createBuffer();
+ if (!m_scene.vbo)
+ return false;
+
+ const float vertices[] = { 0.0f, 0.8f, 0.0f,
+ -0.8f, -0.8f, 0.0f,
+ 0.8f, -0.8f, 0.0f };
+ m_context->bindBuffer(GL_ARRAY_BUFFER, m_scene.vbo);
+ m_context->bufferData(GL_ARRAY_BUFFER, sizeof(vertices), 0, GL_STATIC_DRAW);
+ m_context->bufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
+ return true;
+}
+
+void TestWebPlugin::drawPrimitive()
+{
+ ASSERT(m_scene.primitive == PrimitiveTriangle);
+ ASSERT(m_scene.vbo);
+ ASSERT(m_scene.program);
+
+ m_context->useProgram(m_scene.program);
+
+ // Bind primitive color.
+ float color[4];
+ premultiplyAlpha(m_scene.primitiveColor, m_scene.opacity, color);
+ m_context->uniform4f(m_scene.colorLocation, color[0], color[1], color[2], color[3]);
+
+ // Bind primitive vertices.
+ m_context->bindBuffer(GL_ARRAY_BUFFER, m_scene.vbo);
+ m_context->enableVertexAttribArray(m_scene.positionLocation);
+ m_context->vertexAttribPointer(m_scene.positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
+ m_context->drawArrays(GL_TRIANGLES, 0, 3);
+}
+
+unsigned TestWebPlugin::loadShader(unsigned type, const CString& source)
+{
+ unsigned shader = m_context->createShader(type);
+ if (shader) {
+ m_context->shaderSource(shader, source.data());
+ m_context->compileShader(shader);
+
+ int compiled = 0;
+ m_context->getShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ m_context->deleteShader(shader);
+ shader = 0;
+ }
+ }
+ return shader;
+}
+
+unsigned TestWebPlugin::loadProgram(const CString& vertexSource,
+ const CString& fragmentSource)
+{
+ unsigned vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
+ unsigned fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
+ unsigned program = m_context->createProgram();
+ if (vertexShader && fragmentShader && program) {
+ m_context->attachShader(program, vertexShader);
+ m_context->attachShader(program, fragmentShader);
+ m_context->linkProgram(program);
+
+ int linked = 0;
+ m_context->getProgramiv(program, GL_LINK_STATUS, &linked);
+ if (!linked) {
+ m_context->deleteProgram(program);
+ program = 0;
+ }
+ }
+ if (vertexShader)
+ m_context->deleteShader(vertexShader);
+ if (fragmentShader)
+ m_context->deleteShader(fragmentShader);
+
+ return program;
+}
+
diff --git a/Tools/DumpRenderTree/chromium/TestWebPlugin.h b/Tools/DumpRenderTree/chromium/TestWebPlugin.h
new file mode 100644
index 000000000..cef472884
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestWebPlugin.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 TestWebPlugin_h
+#define TestWebPlugin_h
+
+#include "WebPlugin.h"
+#include "platform/WebRect.h"
+
+namespace WebKit {
+class WebGraphicsContext3D;
+}
+
+// A fake implemention of WebKit::WebPlugin for testing purposes.
+//
+// It uses WebGraphicsContext3D to paint a scene consisiting of a primitive
+// over a background. The primitive and background can be customized using
+// the following plugin parameters:
+// primitive: none (default), triangle.
+// background-color: black (default), red, green, blue.
+// primitive-color: black (default), red, green, blue.
+// opacity: [0.0 - 1.0]. Default is 1.0.
+class TestWebPlugin : public WebKit::WebPlugin {
+public:
+ TestWebPlugin(WebKit::WebFrame*, const WebKit::WebPluginParams&);
+ virtual ~TestWebPlugin();
+
+ static const WebKit::WebString& mimeType();
+
+ // WebPlugin methods:
+ virtual bool initialize(WebKit::WebPluginContainer*);
+ virtual void destroy();
+ virtual NPObject* scriptableObject() { return 0; }
+ virtual void paint(WebKit::WebCanvas*, const WebKit::WebRect&) { }
+ virtual void updateGeometry(const WebKit::WebRect& frameRect,
+ const WebKit::WebRect& clipRect,
+ const WebKit::WebVector<WebKit::WebRect>& cutOutsRects,
+ bool isVisible);
+ virtual void updateFocus(bool) { }
+ virtual void updateVisibility(bool) { }
+ virtual bool acceptsInputEvents() { return false; }
+ virtual bool handleInputEvent(const WebKit::WebInputEvent&, WebKit::WebCursorInfo&) { return false; }
+ virtual void didReceiveResponse(const WebKit::WebURLResponse&) { }
+ virtual void didReceiveData(const char* data, int dataLength) { }
+ virtual void didFinishLoading() { }
+ virtual void didFailLoading(const WebKit::WebURLError&) { }
+ virtual void didFinishLoadingFrameRequest(const WebKit::WebURL&, void* notifyData) { }
+ virtual void didFailLoadingFrameRequest(const WebKit::WebURL&, void* notifyData, const WebKit::WebURLError&) { }
+
+private:
+ enum Primitive {
+ PrimitiveNone,
+ PrimitiveTriangle
+ };
+
+ struct Scene {
+ Primitive primitive;
+ unsigned backgroundColor[3];
+ unsigned primitiveColor[3];
+ float opacity;
+
+ unsigned vbo;
+ unsigned program;
+ int colorLocation;
+ int positionLocation;
+
+ Scene()
+ : primitive(PrimitiveNone)
+ , opacity(1.0f) // Fully opaque.
+ , vbo(0)
+ , program(0)
+ , colorLocation(-1)
+ , positionLocation(-1)
+ {
+ backgroundColor[0] = backgroundColor[1] = backgroundColor[2] = 0;
+ primitiveColor[0] = primitiveColor[1] = primitiveColor[2] = 0;
+ }
+ };
+
+ // Functions for parsing plugin parameters.
+ Primitive parsePrimitive(const WebKit::WebString&);
+ void parseColor(const WebKit::WebString&, unsigned color[3]);
+ float parseOpacity(const WebKit::WebString&);
+
+ // Functions for loading and drawing scene.
+ bool initScene();
+ void drawScene();
+ void destroyScene();
+ bool initProgram();
+ bool initPrimitive();
+ void drawPrimitive();
+ unsigned loadShader(unsigned type, const WTF::CString& source);
+ unsigned loadProgram(const WTF::CString& vertexSource,
+ const WTF::CString& fragmentSource);
+
+ WebKit::WebFrame* m_frame;
+ WebKit::WebPluginContainer* m_container;
+
+ WebKit::WebRect m_rect;
+ WebKit::WebGraphicsContext3D* m_context;
+ Scene m_scene;
+};
+
+#endif // TestPepperPlugin_h
diff --git a/Tools/DumpRenderTree/chromium/TestWebWorker.h b/Tools/DumpRenderTree/chromium/TestWebWorker.h
new file mode 100644
index 000000000..ad82a87e9
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestWebWorker.h
@@ -0,0 +1,93 @@
+/*
+ * 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 TestWebWorker_h
+#define TestWebWorker_h
+
+#include "WebMessagePortChannel.h"
+#include "WebSharedWorkerClient.h"
+#include "WebWorker.h"
+#include <wtf/RefCounted.h>
+
+namespace WebKit {
+class WebNotificationPresenter;
+class WebString;
+class WebURL;
+}
+
+class TestWebWorker : public WebKit::WebWorker,
+ public WebKit::WebSharedWorkerClient,
+ public WTF::RefCounted<TestWebWorker> {
+public:
+ TestWebWorker()
+ {
+ // This class expects refcounting semantics like those found in
+ // Chromium's base::RefCounted, so it's OK to call ref() directly.
+ relaxAdoptionRequirement();
+ ref();
+ // The initial counter value should be 2. One for a worker object,
+ // another for a worker context object. We need to call ref() just once
+ // because the default counter value of RefCounted is 1.
+ }
+
+ // WebWorker methods:
+ virtual void startWorkerContext(const WebKit::WebURL&, const WebKit::WebString&, const WebKit::WebString&) { }
+ virtual void terminateWorkerContext() { }
+ virtual void postMessageToWorkerContext(const WebKit::WebString&, const WebKit::WebMessagePortChannelArray&) { }
+ virtual void workerObjectDestroyed()
+ {
+ // Releases the reference held for worker object.
+ deref();
+ }
+ virtual void clientDestroyed() { }
+
+ // WebWorkerClient methods:
+ virtual void postMessageToWorkerObject(const WebKit::WebString&, const WebKit::WebMessagePortChannelArray&) { }
+ virtual void postExceptionToWorkerObject(const WebKit::WebString&, int, const WebKit::WebString&) { }
+ virtual void postConsoleMessageToWorkerObject(int, int, int, int, const WebKit::WebString&, int, const WebKit::WebString&) { }
+ virtual void confirmMessageFromWorkerObject(bool) { }
+ virtual void reportPendingActivity(bool) { }
+ virtual void workerContextClosed() { }
+ virtual void workerContextDestroyed()
+ {
+ // Releases the reference held for worker context object.
+ deref();
+ }
+ virtual WebKit::WebWorker* createWorker(WebKit::WebSharedWorkerClient*) { return 0; }
+ virtual WebKit::WebNotificationPresenter* notificationPresenter() { return 0; }
+ virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost(WebKit::WebApplicationCacheHostClient*) { return 0; }
+ virtual bool allowDatabase(WebKit::WebFrame*, const WebKit::WebString&, const WebKit::WebString&, unsigned long) { return true; }
+
+private:
+ ~TestWebWorker() { }
+ friend class WTF::RefCounted<TestWebWorker>;
+};
+
+#endif // TestWebWorker_h
diff --git a/Tools/DumpRenderTree/chromium/TextInputController.cpp b/Tools/DumpRenderTree/chromium/TextInputController.cpp
new file mode 100644
index 000000000..a3637067a
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TextInputController.cpp
@@ -0,0 +1,249 @@
+/*
+ * 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 "TextInputController.h"
+
+#include "TestShell.h"
+#include "WebBindings.h"
+#include "WebCompositionUnderline.h"
+#include "WebFrame.h"
+#include "WebRange.h"
+#include "platform/WebString.h"
+#include "platform/WebVector.h"
+#include "WebView.h"
+#include <string>
+#include <wtf/StringExtras.h>
+
+using namespace WebKit;
+
+TestShell* TextInputController::testShell = 0;
+
+TextInputController::TextInputController(TestShell* shell)
+{
+ // Set static testShell variable. Be careful not to assign testShell to new
+ // windows which are temporary.
+ if (!testShell)
+ testShell = shell;
+
+ bindMethod("attributedSubstringFromRange", &TextInputController::attributedSubstringFromRange);
+ bindMethod("characterIndexForPoint", &TextInputController::characterIndexForPoint);
+ bindMethod("conversationIdentifier", &TextInputController::conversationIdentifier);
+ bindMethod("doCommand", &TextInputController::doCommand);
+ bindMethod("firstRectForCharacterRange", &TextInputController::firstRectForCharacterRange);
+ bindMethod("hasMarkedText", &TextInputController::hasMarkedText);
+ bindMethod("insertText", &TextInputController::insertText);
+ bindMethod("makeAttributedString", &TextInputController::makeAttributedString);
+ bindMethod("markedRange", &TextInputController::markedRange);
+ bindMethod("selectedRange", &TextInputController::selectedRange);
+ bindMethod("setMarkedText", &TextInputController::setMarkedText);
+ bindMethod("substringFromRange", &TextInputController::substringFromRange);
+ bindMethod("unmarkText", &TextInputController::unmarkText);
+ bindMethod("validAttributesForMarkedText", &TextInputController::validAttributesForMarkedText);
+ bindMethod("setComposition", &TextInputController::setComposition);
+}
+
+WebFrame* TextInputController::getMainFrame()
+{
+ return testShell->webView()->mainFrame();
+}
+
+void TextInputController::insertText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+
+ testShell->webView()->confirmComposition(WebString::fromUTF8(arguments[0].toString()));
+}
+
+void TextInputController::doCommand(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ if (arguments.size() >= 1 && arguments[0].isString())
+ mainFrame->executeCommand(WebString::fromUTF8(arguments[0].toString()));
+}
+
+void TextInputController::setMarkedText(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ if (arguments.size() >= 3 && arguments[0].isString()
+ && arguments[1].isNumber() && arguments[2].isNumber()) {
+ WebVector<WebCompositionUnderline> underlines;
+ testShell->webView()->setComposition(WebString::fromUTF8(arguments[0].toString()),
+ underlines,
+ arguments[1].toInt32(),
+ arguments[1].toInt32() + arguments[2].toInt32());
+ }
+}
+
+void TextInputController::unmarkText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ testShell->webView()->confirmComposition();
+}
+
+void TextInputController::hasMarkedText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ result->set(mainFrame->hasMarkedText());
+}
+
+void TextInputController::conversationIdentifier(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::substringFromRange(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::attributedSubstringFromRange(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::markedRange(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ WebRange range = mainFrame->markedRange();
+ Vector<int> intArray(2);
+ intArray[0] = range.startOffset();
+ intArray[1] = range.endOffset();
+ result->set(WebBindings::makeIntArray(intArray));
+}
+
+void TextInputController::selectedRange(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ WebRange range = mainFrame->selectionRange();
+ Vector<int> intArray(2);
+ intArray[0] = range.startOffset();
+ intArray[1] = range.endOffset();
+ result->set(WebBindings::makeIntArray(intArray));
+}
+
+void TextInputController::firstRectForCharacterRange(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* frame = testShell->webView()->focusedFrame();
+ if (!frame)
+ return;
+
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ WebRect rect;
+ if (!frame->firstRectForCharacterRange(arguments[0].toInt32(), arguments[1].toInt32(), rect))
+ return;
+
+ Vector<int> intArray(4);
+ intArray[0] = rect.x;
+ intArray[1] = rect.y;
+ intArray[2] = rect.width;
+ intArray[3] = rect.height;
+ result->set(WebBindings::makeIntArray(intArray));
+}
+
+void TextInputController::characterIndexForPoint(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::validAttributesForMarkedText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ result->set("NSUnderline,NSUnderlineColor,NSMarkedClauseSegment,"
+ "NSTextInputReplacementRangeAttributeName");
+}
+
+void TextInputController::makeAttributedString(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+void TextInputController::setComposition(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+
+ WebView* view = getMainFrame() ? getMainFrame()->view() : 0;
+ if (!view)
+ return;
+
+ if (arguments.size() < 1)
+ return;
+
+ // Sends a keydown event with key code = 0xE5 to emulate input method behavior.
+ WebKeyboardEvent keyDown;
+ keyDown.type = WebInputEvent::RawKeyDown;
+ keyDown.modifiers = 0;
+ keyDown.windowsKeyCode = 0xE5; // VKEY_PROCESSKEY
+ keyDown.setKeyIdentifierFromWindowsKeyCode();
+ view->handleInputEvent(keyDown);
+
+ WebVector<WebCompositionUnderline> underlines;
+ WebString text(WebString::fromUTF8(arguments[0].toString()));
+ view->setComposition(text, underlines, 0, text.length());
+}
diff --git a/Tools/DumpRenderTree/chromium/TextInputController.h b/Tools/DumpRenderTree/chromium/TextInputController.h
new file mode 100644
index 000000000..3a3907fda
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TextInputController.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+// TextInputController is bound to window.textInputController in Javascript
+// when DRT is running. Layout tests use it to exercise various corners of
+// text input.
+
+#ifndef TextInputController_h
+#define TextInputController_h
+
+#include "CppBoundClass.h"
+
+class TestShell;
+
+namespace WebKit {
+class WebFrame;
+}
+
+class TextInputController : public CppBoundClass {
+public:
+ TextInputController(TestShell*);
+
+ void insertText(const CppArgumentList&, CppVariant*);
+ void doCommand(const CppArgumentList&, CppVariant*);
+ void setMarkedText(const CppArgumentList&, CppVariant*);
+ void unmarkText(const CppArgumentList&, CppVariant*);
+ void hasMarkedText(const CppArgumentList&, CppVariant*);
+ void conversationIdentifier(const CppArgumentList&, CppVariant*);
+ void substringFromRange(const CppArgumentList&, CppVariant*);
+ void attributedSubstringFromRange(const CppArgumentList&, CppVariant*);
+ void markedRange(const CppArgumentList&, CppVariant*);
+ void selectedRange(const CppArgumentList&, CppVariant*);
+ void firstRectForCharacterRange(const CppArgumentList&, CppVariant*);
+ void characterIndexForPoint(const CppArgumentList&, CppVariant*);
+ void validAttributesForMarkedText(const CppArgumentList&, CppVariant*);
+ void makeAttributedString(const CppArgumentList&, CppVariant*);
+ void setComposition(const CppArgumentList&, CppVariant*);
+
+private:
+ // Returns the test shell's main WebFrame.
+ static WebKit::WebFrame* getMainFrame();
+
+ // Non-owning pointer. The TextInputController is owned by the TestShell.
+ static TestShell* testShell;
+};
+
+#endif // TextInputController_h
diff --git a/Tools/DumpRenderTree/chromium/WebPermissions.cpp b/Tools/DumpRenderTree/chromium/WebPermissions.cpp
new file mode 100644
index 000000000..ee90a7b2c
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebPermissions.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 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 "WebPermissions.h"
+
+#include "LayoutTestController.h"
+#include "TestShell.h"
+#include "platform/WebCString.h"
+#include "platform/WebURL.h"
+
+WebPermissions::WebPermissions(TestShell* shell)
+ : m_shell(shell)
+{
+ reset();
+}
+
+WebPermissions::~WebPermissions()
+{
+}
+
+bool WebPermissions::allowImage(WebKit::WebFrame*, bool enabledPerSettings, const WebKit::WebURL& imageURL)
+{
+ bool allowed = enabledPerSettings && m_imagesAllowed;
+ if (layoutTestController()->shouldDumpPermissionClientCallbacks())
+ fprintf(stdout, "PERMISSION CLIENT: allowImage(%s): %s\n", m_shell->normalizeLayoutTestURL(imageURL.spec()).c_str(), allowed ? "true" : "false");
+ return allowed;
+}
+
+bool WebPermissions::allowScriptFromSource(WebKit::WebFrame*, bool enabledPerSettings, const WebKit::WebURL& scriptURL)
+{
+ bool allowed = enabledPerSettings && m_scriptsAllowed;
+ if (layoutTestController()->shouldDumpPermissionClientCallbacks())
+ fprintf(stdout, "PERMISSION CLIENT: allowScriptFromSource(%s): %s\n", m_shell->normalizeLayoutTestURL(scriptURL.spec()).c_str(), allowed ? "true" : "false");
+ return allowed;
+}
+
+bool WebPermissions::allowStorage(WebKit::WebFrame*, bool)
+{
+ return m_storageAllowed;
+}
+
+bool WebPermissions::allowPlugins(WebKit::WebFrame*, bool enabledPerSettings)
+{
+ return enabledPerSettings && m_pluginsAllowed;
+}
+
+bool WebPermissions::allowDisplayingInsecureContent(WebKit::WebFrame*, bool enabledPerSettings,
+ const WebKit::WebSecurityOrigin&, const WebKit::WebURL&)
+{
+ return enabledPerSettings || m_displayingInsecureContentAllowed;
+}
+
+bool WebPermissions::allowRunningInsecureContent(WebKit::WebFrame*, bool enabledPerSettings,
+ const WebKit::WebSecurityOrigin&, const WebKit::WebURL&)
+{
+ return enabledPerSettings || m_runningInsecureContentAllowed;
+}
+
+void WebPermissions::setImagesAllowed(bool imagesAllowed)
+{
+ m_imagesAllowed = imagesAllowed;
+}
+
+void WebPermissions::setScriptsAllowed(bool scriptsAllowed)
+{
+ m_scriptsAllowed = scriptsAllowed;
+}
+
+void WebPermissions::setStorageAllowed(bool storageAllowed)
+{
+ m_storageAllowed = storageAllowed;
+}
+
+void WebPermissions::setPluginsAllowed(bool pluginsAllowed)
+{
+ m_pluginsAllowed = pluginsAllowed;
+}
+
+void WebPermissions::setDisplayingInsecureContentAllowed(bool allowed)
+{
+ m_displayingInsecureContentAllowed = allowed;
+}
+
+void WebPermissions::setRunningInsecureContentAllowed(bool allowed)
+{
+ m_runningInsecureContentAllowed = allowed;
+}
+
+void WebPermissions::reset()
+{
+ m_imagesAllowed = true;
+ m_scriptsAllowed = true;
+ m_storageAllowed = true;
+ m_pluginsAllowed = true;
+ m_displayingInsecureContentAllowed = false;
+ m_runningInsecureContentAllowed = false;
+}
+
+// Private functions ----------------------------------------------------------
+
+LayoutTestController* WebPermissions::layoutTestController() const
+{
+ return m_shell->layoutTestController();
+}
diff --git a/Tools/DumpRenderTree/chromium/WebPermissions.h b/Tools/DumpRenderTree/chromium/WebPermissions.h
new file mode 100644
index 000000000..184046a0a
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebPermissions.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 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 WebPermissions_h
+#define WebPermissions_h
+
+#include "WebPermissionClient.h"
+
+class LayoutTestController;
+class TestShell;
+
+class WebPermissions : public WebKit::WebPermissionClient {
+public:
+ WebPermissions(TestShell*);
+ virtual ~WebPermissions();
+
+ // Override WebPermissionClient methods.
+ virtual bool allowImage(WebKit::WebFrame*, bool enabledPerSettings, const WebKit::WebURL& imageURL);
+ virtual bool allowScriptFromSource(WebKit::WebFrame*, bool enabledPerSettings, const WebKit::WebURL& scriptURL);
+ virtual bool allowStorage(WebKit::WebFrame*, bool local);
+ virtual bool allowPlugins(WebKit::WebFrame*, bool enabledPerSettings);
+ virtual bool allowDisplayingInsecureContent(WebKit::WebFrame*, bool enabledPerSettings,
+ const WebKit::WebSecurityOrigin&, const WebKit::WebURL&);
+ virtual bool allowRunningInsecureContent(WebKit::WebFrame*, bool enabledPerSettings,
+ const WebKit::WebSecurityOrigin&, const WebKit::WebURL&);
+
+ // Hooks to set the different policies.
+ void setImagesAllowed(bool);
+ void setScriptsAllowed(bool);
+ void setStorageAllowed(bool);
+ void setPluginsAllowed(bool);
+ void setDisplayingInsecureContentAllowed(bool);
+ void setRunningInsecureContentAllowed(bool);
+
+ // Resets the policy to allow everything, except for running insecure content.
+ void reset();
+
+private:
+ LayoutTestController* layoutTestController() const;
+
+ // Non-owning pointer. The WebPermissions instance is owned by this TestShell instance.
+ TestShell* m_shell;
+
+ bool m_imagesAllowed;
+ bool m_scriptsAllowed;
+ bool m_storageAllowed;
+ bool m_pluginsAllowed;
+ bool m_displayingInsecureContentAllowed;
+ bool m_runningInsecureContentAllowed;
+};
+
+#endif
diff --git a/Tools/DumpRenderTree/chromium/WebPreferences.cpp b/Tools/DumpRenderTree/chromium/WebPreferences.cpp
new file mode 100644
index 000000000..01e4fcc4e
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebPreferences.cpp
@@ -0,0 +1,243 @@
+/*
+ * 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 "WebPreferences.h"
+
+#include "WebView.h"
+
+using namespace WebKit;
+
+void WebPreferences::reset()
+{
+#if OS(MAC_OS_X)
+ cursiveFontFamily = WebString::fromUTF8("Apple Chancery");
+ fantasyFontFamily = WebString::fromUTF8("Papyrus");
+ WebString serif = WebString::fromUTF8("Times");
+#else
+ // These two fonts are picked from the intersection of
+ // Win XP font list and Vista font list :
+ // http://www.microsoft.com/typography/fonts/winxp.htm
+ // http://blogs.msdn.com/michkap/archive/2006/04/04/567881.aspx
+ // Some of them are installed only with CJK and complex script
+ // support enabled on Windows XP and are out of consideration here.
+ // (although we enabled both on our buildbots.)
+ // They (especially Impact for fantasy) are not typical cursive
+ // and fantasy fonts, but it should not matter for layout tests
+ // as long as they're available.
+ cursiveFontFamily = WebString::fromUTF8("Comic Sans MS");
+ fantasyFontFamily = WebString::fromUTF8("Impact");
+ // NOTE: case matters here, this must be 'times new roman', else
+ // some layout tests fail.
+ WebString serif = WebString::fromUTF8("times new roman");
+#endif
+ serifFontFamily = serif;
+ standardFontFamily = serif;
+ fixedFontFamily = WebString::fromUTF8("Courier");
+ sansSerifFontFamily = WebString::fromUTF8("Helvetica");
+
+ defaultFontSize = 16;
+ defaultFixedFontSize = 13;
+ minimumFontSize = 0;
+ minimumLogicalFontSize = 9;
+ // Do not disable acceleration for 2d canvas based on size.
+ // This makes having test expectations consistent.
+ minimumAccelerated2dCanvasSize = 0;
+
+ DOMPasteAllowed = true;
+ XSSAuditorEnabled = false;
+ allowDisplayOfInsecureContent = true;
+ allowFileAccessFromFileURLs = true;
+ allowRunningOfInsecureContent = true;
+ authorAndUserStylesEnabled = true;
+ defaultTextEncodingName = WebString::fromUTF8("ISO-8859-1");
+ developerExtrasEnabled = true;
+ experimentalWebGLEnabled = false;
+ javaEnabled = false;
+ javaScriptCanAccessClipboard = true;
+ javaScriptCanOpenWindowsAutomatically = true;
+ javaScriptEnabled = true;
+ loadsImagesAutomatically = true;
+ localStorageEnabled = true;
+ offlineWebApplicationCacheEnabled = true;
+ pluginsEnabled = true;
+ shrinksStandaloneImagesToFit = false;
+ textAreasAreResizable = false;
+ userStyleSheetLocation = WebURL();
+ usesPageCache = false;
+ pageCacheSupportsPlugins = false;
+ webSecurityEnabled = true;
+ caretBrowsingEnabled = false;
+
+ // Allow those layout tests running as local files, i.e. under
+ // LayoutTests/http/tests/local, to access http server.
+ allowUniversalAccessFromFileURLs = true;
+
+#if OS(DARWIN)
+ editingBehavior = WebSettings::EditingBehaviorMac;
+#else
+ editingBehavior = WebSettings::EditingBehaviorWin;
+#endif
+
+ tabsToLinks = false;
+ hyperlinkAuditingEnabled = false;
+ acceleratedCompositingForVideoEnabled = false;
+ acceleratedCompositingEnabled = false;
+ compositeToTexture = false;
+ accelerated2dCanvasEnabled = false;
+ legacyAccelerated2dCanvasEnabled = false;
+ acceleratedPaintingEnabled = false;
+ forceCompositingMode = false;
+ hixie76WebSocketProtocolEnabled = true;
+ perTilePaintingEnabled = false;
+}
+
+static void setStandardFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script)
+{
+ settings->setStandardFontFamily(font, script);
+}
+
+static void setFixedFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script)
+{
+ settings->setFixedFontFamily(font, script);
+}
+
+static void setSerifFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script)
+{
+ settings->setSerifFontFamily(font, script);
+}
+
+static void setSansSerifFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script)
+{
+ settings->setSansSerifFontFamily(font, script);
+}
+
+static void setCursiveFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script)
+{
+ settings->setCursiveFontFamily(font, script);
+}
+
+static void setFantasyFontFamilyWrapper(WebSettings* settings, const WebKit::WebString& font, UScriptCode script)
+{
+ settings->setFantasyFontFamily(font, script);
+}
+
+typedef void (*SetFontFamilyWrapper)(WebSettings*, const WebString&, UScriptCode);
+
+static void applyFontMap(WebSettings* settings, const WebPreferences::ScriptFontFamilyMap& map, SetFontFamilyWrapper setter)
+{
+ for (WebPreferences::ScriptFontFamilyMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
+ const WebString& font = iter->second;
+ if (!font.isNull() && !font.isEmpty())
+ (*setter)(settings, font, static_cast<UScriptCode>(iter->first));
+ }
+}
+
+void WebPreferences::applyTo(WebView* webView)
+{
+ WebSettings* settings = webView->settings();
+ settings->setStandardFontFamily(standardFontFamily);
+ settings->setFixedFontFamily(fixedFontFamily);
+ settings->setSerifFontFamily(serifFontFamily);
+ settings->setSansSerifFontFamily(sansSerifFontFamily);
+ settings->setCursiveFontFamily(cursiveFontFamily);
+ settings->setFantasyFontFamily(fantasyFontFamily);
+
+ applyFontMap(settings, standardFontMap, setStandardFontFamilyWrapper);
+ applyFontMap(settings, fixedFontMap, setFixedFontFamilyWrapper);
+ applyFontMap(settings, serifFontMap, setSerifFontFamilyWrapper);
+ applyFontMap(settings, sansSerifFontMap, setSansSerifFontFamilyWrapper);
+ applyFontMap(settings, cursiveFontMap, setCursiveFontFamilyWrapper);
+ applyFontMap(settings, fantasyFontMap, setFantasyFontFamilyWrapper);
+
+ settings->setDefaultFontSize(defaultFontSize);
+ settings->setDefaultFixedFontSize(defaultFixedFontSize);
+ settings->setMinimumFontSize(minimumFontSize);
+ settings->setMinimumLogicalFontSize(minimumLogicalFontSize);
+ settings->setMinimumAccelerated2dCanvasSize(minimumAccelerated2dCanvasSize);
+
+ settings->setDOMPasteAllowed(DOMPasteAllowed);
+ settings->setXSSAuditorEnabled(XSSAuditorEnabled);
+ settings->setAllowDisplayOfInsecureContent(allowDisplayOfInsecureContent);
+ settings->setAllowFileAccessFromFileURLs(allowFileAccessFromFileURLs);
+ settings->setAllowRunningOfInsecureContent(allowRunningOfInsecureContent);
+ settings->setAuthorAndUserStylesEnabled(authorAndUserStylesEnabled);
+ settings->setDefaultTextEncodingName(defaultTextEncodingName);
+ settings->setDeveloperExtrasEnabled(developerExtrasEnabled);
+ settings->setExperimentalWebGLEnabled(experimentalWebGLEnabled);
+ settings->setJavaEnabled(javaEnabled);
+ settings->setJavaScriptCanAccessClipboard(javaScriptCanAccessClipboard);
+ settings->setJavaScriptCanOpenWindowsAutomatically(javaScriptCanOpenWindowsAutomatically);
+ settings->setJavaScriptEnabled(javaScriptEnabled);
+ settings->setLoadsImagesAutomatically(loadsImagesAutomatically);
+ settings->setLocalStorageEnabled(localStorageEnabled);
+ settings->setOfflineWebApplicationCacheEnabled(offlineWebApplicationCacheEnabled);
+ settings->setPluginsEnabled(pluginsEnabled);
+ settings->setShrinksStandaloneImagesToFit(shrinksStandaloneImagesToFit);
+ settings->setTextAreasAreResizable(textAreasAreResizable);
+ settings->setUserStyleSheetLocation(userStyleSheetLocation);
+ settings->setUsesPageCache(usesPageCache);
+ settings->setPageCacheSupportsPlugins(pageCacheSupportsPlugins);
+ settings->setWebSecurityEnabled(webSecurityEnabled);
+ settings->setAllowUniversalAccessFromFileURLs(allowUniversalAccessFromFileURLs);
+ settings->setEditingBehavior(editingBehavior);
+ settings->setHyperlinkAuditingEnabled(hyperlinkAuditingEnabled);
+ // LayoutTests were written with Safari Mac in mind which does not allow
+ // tabbing to links by default.
+ webView->setTabsToLinks(tabsToLinks);
+ settings->setCaretBrowsingEnabled(caretBrowsingEnabled);
+ settings->setAcceleratedCompositingEnabled(acceleratedCompositingEnabled);
+ settings->setAcceleratedCompositingForVideoEnabled(acceleratedCompositingForVideoEnabled);
+ settings->setCompositeToTextureEnabled(compositeToTexture);
+ settings->setForceCompositingMode(forceCompositingMode);
+ settings->setAccelerated2dCanvasEnabled(accelerated2dCanvasEnabled);
+ settings->setLegacyAccelerated2dCanvasEnabled(legacyAccelerated2dCanvasEnabled);
+ settings->setAcceleratedPaintingEnabled(acceleratedPaintingEnabled);
+ settings->setHixie76WebSocketProtocolEnabled(hixie76WebSocketProtocolEnabled);
+ settings->setPerTilePaintingEnabled(perTilePaintingEnabled);
+
+ // Fixed values.
+ settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();
+ settings->setDownloadableBinaryFontsEnabled(true);
+ settings->setAllowScriptsToCloseWindows(false);
+ settings->setNeedsSiteSpecificQuirks(true);
+ settings->setEditableLinkBehaviorNeverLive();
+ settings->setEnableScrollAnimator(false);
+ settings->setFontRenderingModeNormal();
+ settings->setMockScrollbarsEnabled(false);
+ settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();
+ settings->setUsesEncodingDetector(false);
+ settings->setImagesEnabled(true);
+ settings->setInteractiveFormValidationEnabled(true);
+ // Enable fullscreen so the fullscreen layout tests can run.
+ settings->setFullScreenEnabled(true);
+ settings->setValidationMessageTimerMagnification(-1);
+ settings->setVisualWordMovementEnabled(false);
+}
diff --git a/Tools/DumpRenderTree/chromium/WebPreferences.h b/Tools/DumpRenderTree/chromium/WebPreferences.h
new file mode 100644
index 000000000..2e2135ab7
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebPreferences.h
@@ -0,0 +1,119 @@
+/*
+ * 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 WebPreferences_h
+#define WebPreferences_h
+
+#include "WebSettings.h"
+#include "platform/WebString.h"
+#include "platform/WebURL.h"
+#include <wtf/HashMap.h>
+
+namespace WebKit {
+class WebView;
+}
+
+struct WebPreferences {
+ WebKit::WebString standardFontFamily;
+ WebKit::WebString fixedFontFamily;
+ WebKit::WebString serifFontFamily;
+ WebKit::WebString sansSerifFontFamily;
+ WebKit::WebString cursiveFontFamily;
+ WebKit::WebString fantasyFontFamily;
+
+ // UScriptCode uses -1 and 0 for UScriptInvalidCode and UScriptCommon.
+ // We need to use -2 and -3 for empty value and deleted value.
+ // (See WebCore::ScriptFontFamilyMap)
+ struct UScriptCodeHashTraits : WTF::GenericHashTraits<int> {
+ static const bool emptyValueIsZero = false;
+ static int emptyValue() { return -2; }
+ static void constructDeletedValue(int& slot) { slot = -3; }
+ static bool isDeletedValue(int value) { return value == -3; }
+ };
+
+ // Map of UScriptCode to font such as USCRIPT_ARABIC to "My Arabic Font".
+ typedef HashMap<int, WebKit::WebString, DefaultHash<int>::Hash, UScriptCodeHashTraits> ScriptFontFamilyMap;
+ ScriptFontFamilyMap standardFontMap;
+ ScriptFontFamilyMap fixedFontMap;
+ ScriptFontFamilyMap serifFontMap;
+ ScriptFontFamilyMap sansSerifFontMap;
+ ScriptFontFamilyMap cursiveFontMap;
+ ScriptFontFamilyMap fantasyFontMap;
+
+ int defaultFontSize;
+ int defaultFixedFontSize;
+ int minimumFontSize;
+ int minimumLogicalFontSize;
+ int minimumAccelerated2dCanvasSize;
+
+ bool DOMPasteAllowed;
+ bool XSSAuditorEnabled;
+ bool allowDisplayOfInsecureContent;
+ bool allowFileAccessFromFileURLs;
+ bool allowRunningOfInsecureContent;
+ bool authorAndUserStylesEnabled;
+ WebKit::WebString defaultTextEncodingName;
+ bool developerExtrasEnabled;
+ bool experimentalWebGLEnabled;
+ bool javaEnabled;
+ bool javaScriptCanAccessClipboard;
+ bool javaScriptCanOpenWindowsAutomatically;
+ bool javaScriptEnabled;
+ bool loadsImagesAutomatically;
+ bool localStorageEnabled;
+ bool offlineWebApplicationCacheEnabled;
+ bool pluginsEnabled;
+ bool shrinksStandaloneImagesToFit;
+ bool textAreasAreResizable;
+ WebKit::WebURL userStyleSheetLocation;
+ bool usesPageCache;
+ bool pageCacheSupportsPlugins;
+ bool webSecurityEnabled;
+ bool allowUniversalAccessFromFileURLs;
+ WebKit::WebSettings::EditingBehavior editingBehavior;
+ bool tabsToLinks;
+ bool hyperlinkAuditingEnabled;
+ bool caretBrowsingEnabled;
+ bool acceleratedCompositingForVideoEnabled;
+ bool acceleratedCompositingEnabled;
+ bool compositeToTexture;
+ bool forceCompositingMode;
+ bool accelerated2dCanvasEnabled;
+ bool legacyAccelerated2dCanvasEnabled;
+ bool acceleratedPaintingEnabled;
+ bool hixie76WebSocketProtocolEnabled;
+ bool perTilePaintingEnabled;
+
+ WebPreferences() { reset(); }
+ void reset();
+ void applyTo(WebKit::WebView*);
+};
+
+#endif // WebPreferences_h
diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp
new file mode 100755
index 000000000..13b798284
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp
@@ -0,0 +1,527 @@
+/*
+ * 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.
+ */
+
+// This file implements a simple generic version of the WebThemeEngine,
+// which is used to draw all the native controls on a web page. We use this
+// file when running in layout test mode in order to remove any
+// platform-specific rendering differences due to themes, colors, etc.
+//
+
+#include "config.h"
+#include "WebThemeControlDRTWin.h"
+
+#include "skia/ext/skia_utils_win.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+#include <wtf/Assertions.h>
+
+using namespace std;
+
+static const SkColor edgeColor = SK_ColorBLACK;
+static const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6);
+static const SkColor fgColor = SK_ColorBLACK;
+static const SkColor bgColors[] = {
+ SK_ColorBLACK, // Unknown
+ SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled
+ SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly
+ SkColorSetRGB(0x89, 0xc4, 0xff), // Normal
+ SkColorSetRGB(0x43, 0xf9, 0xff), // Hot
+ SkColorSetRGB(0x20, 0xf6, 0xcc), // Focused
+ SkColorSetRGB(0x00, 0xf3, 0xac), // Hover
+ SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed
+ SkColorSetRGB(0xcc, 0xcc, 0xcc) // Indeterminate
+};
+
+static SkIRect validate(const SkIRect& rect, WebThemeControlDRTWin::Type ctype)
+{
+ switch (ctype) {
+ case WebThemeControlDRTWin::UncheckedBoxType:
+ case WebThemeControlDRTWin::CheckedBoxType:
+ case WebThemeControlDRTWin::UncheckedRadioType:
+ case WebThemeControlDRTWin::CheckedRadioType: {
+ SkIRect retval = rect;
+
+ // The maximum width and height is 13.
+ // Center the square in the passed rectangle.
+ const int maxControlSize = 13;
+ int controlSize = min(rect.width(), rect.height());
+ controlSize = min(controlSize, maxControlSize);
+
+ retval.fLeft = rect.fLeft + (rect.width() / 2) - (controlSize / 2);
+ retval.fRight = retval.fLeft + controlSize - 1;
+ retval.fTop = rect.fTop + (rect.height() / 2) - (controlSize / 2);
+ retval.fBottom = retval.fTop + controlSize - 1;
+
+ return retval;
+ }
+
+ default:
+ return rect;
+ }
+}
+
+// WebThemeControlDRTWin
+
+WebThemeControlDRTWin::WebThemeControlDRTWin(SkCanvas* canvas,
+ const SkIRect& irect,
+ Type ctype,
+ State cstate)
+ : m_canvas(canvas)
+ , m_irect(validate(irect, ctype))
+ , m_type(ctype)
+ , m_state(cstate)
+ , m_left(m_irect.fLeft)
+ , m_right(m_irect.fRight)
+ , m_top(m_irect.fTop)
+ , m_bottom(m_irect.fBottom)
+ , m_height(m_irect.height())
+ , m_width(m_irect.width())
+ , m_edgeColor(edgeColor)
+ , m_bgColor(bgColors[cstate])
+ , m_fgColor(fgColor)
+{
+}
+
+WebThemeControlDRTWin::~WebThemeControlDRTWin()
+{
+}
+
+void WebThemeControlDRTWin::box(const SkIRect& rect, SkColor fillColor)
+{
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(fillColor);
+ m_canvas->drawIRect(rect, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawIRect(rect, paint);
+}
+
+void WebThemeControlDRTWin::line(int x0, int y0, int x1, int y1, SkColor color)
+{
+ SkPaint paint;
+ paint.setColor(color);
+ m_canvas->drawLine(SkIntToScalar(x0), SkIntToScalar(y0),
+ SkIntToScalar(x1), SkIntToScalar(y1),
+ paint);
+}
+
+void WebThemeControlDRTWin::triangle(int x0, int y0,
+ int x1, int y1,
+ int x2, int y2,
+ SkColor color)
+{
+ SkPath path;
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ path.incReserve(4);
+ path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0));
+ path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1));
+ path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2));
+ path.close();
+ m_canvas->drawPath(path, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawPath(path, paint);
+}
+
+void WebThemeControlDRTWin::roundRect(SkColor color)
+{
+ SkRect rect;
+ SkScalar radius = SkIntToScalar(5);
+ SkPaint paint;
+
+ rect.set(m_irect);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawRoundRect(rect, radius, radius, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawRoundRect(rect, radius, radius, paint);
+}
+
+void WebThemeControlDRTWin::oval(SkColor color)
+{
+ SkRect rect;
+ SkPaint paint;
+
+ rect.set(m_irect);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawOval(rect, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawOval(rect, paint);
+}
+
+void WebThemeControlDRTWin::circle(SkScalar radius, SkColor color)
+{
+ SkScalar cy = SkIntToScalar(m_top + m_height / 2);
+ SkScalar cx = SkIntToScalar(m_left + m_width / 2);
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawCircle(cx, cy, radius, paint);
+
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawCircle(cx, cy, radius, paint);
+}
+
+void WebThemeControlDRTWin::nestedBoxes(int indentLeft,
+ int indentTop,
+ int indentRight,
+ int indentBottom,
+ SkColor outerColor,
+ SkColor innerColor)
+{
+ SkIRect lirect;
+ box(m_irect, outerColor);
+ lirect.set(m_irect.fLeft + indentLeft,
+ m_irect.fTop + indentTop,
+ m_irect.fRight - indentRight,
+ m_irect.fBottom - indentBottom);
+ box(lirect, innerColor);
+}
+
+void WebThemeControlDRTWin::markState()
+{
+ // The horizontal lines in a read only control are spaced by this amount.
+ const int readOnlyLineOffset = 5;
+
+ // The length of a triangle side for the corner marks.
+ const int triangleSize = 5;
+
+ switch (m_state) {
+ case UnknownState:
+ case DisabledState:
+ case NormalState:
+ // Don't visually mark these states (color is enough).
+ break;
+ case ReadOnlyState:
+ // Drawing lines across the control.
+ for (int i = m_top + readOnlyLineOffset; i < m_bottom; i += readOnlyLineOffset)
+ line(m_left + 1, i, m_right - 1, i, readOnlyColor);
+ break;
+
+ case HotState:
+ // Draw a triangle in the upper left corner of the control.
+ triangle(m_left, m_top,
+ m_left + triangleSize, m_top,
+ m_left, m_top + triangleSize, m_edgeColor);
+ break;
+
+ case HoverState:
+ // Draw a triangle in the upper right corner of the control.
+ triangle(m_right, m_top,
+ m_right, m_top + triangleSize,
+ m_right - triangleSize, m_top, m_edgeColor);
+ break;
+
+ case FocusedState:
+ // Draw a triangle in the bottom right corner of the control.
+ triangle(m_right, m_bottom,
+ m_right - triangleSize, m_bottom,
+ m_right, m_bottom - triangleSize, m_edgeColor);
+ break;
+
+ case PressedState:
+ // Draw a triangle in the bottom left corner of the control.
+ triangle(m_left, m_bottom,
+ m_left, m_bottom - triangleSize,
+ m_left + triangleSize, m_bottom, m_edgeColor);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ CRASH();
+ break;
+ }
+}
+
+void WebThemeControlDRTWin::draw()
+{
+ int halfWidth = m_width / 2;
+ int halfHeight = m_height / 2;
+ int quarterWidth = m_width / 4;
+ int quarterHeight = m_height / 4;
+
+ // Indent amounts for the check in a checkbox or radio button.
+ const int checkIndent = 3;
+
+ // Indent amounts for short and long sides of the scrollbar notches.
+ const int notchLongOffset = 1;
+ const int notchShortOffset = 4;
+ const int noOffset = 0;
+
+ // Indent amounts for the short and long sides of a scroll thumb box.
+ const int thumbLongIndent = 0;
+ const int thumbShortIndent = 2;
+
+ // Indents for the crosshatch on a scroll grip.
+ const int gripLongIndent = 3;
+ const int gripShortIndent = 5;
+
+ // Indents for the the slider track.
+ const int sliderIndent = 2;
+
+ switch (m_type) {
+ case UnknownType:
+ ASSERT_NOT_REACHED();
+ CRASH();
+ break;
+
+ case TextFieldType:
+ // We render this by hand outside of this function.
+ ASSERT_NOT_REACHED();
+ CRASH();
+ break;
+
+ case PushButtonType:
+ // push buttons render as a rounded rectangle
+ roundRect(m_bgColor);
+ break;
+
+ case UncheckedBoxType:
+ // Unchecked boxes are simply plain boxes.
+ box(m_irect, m_bgColor);
+ break;
+
+ case CheckedBoxType:
+ nestedBoxes(checkIndent, checkIndent, checkIndent, checkIndent, m_bgColor, m_fgColor);
+ break;
+
+ case IndeterminateCheckboxType:
+ // Indeterminate checkbox is a box containing '-'.
+ nestedBoxes(checkIndent, halfHeight, checkIndent, halfHeight, m_bgColor, m_fgColor);
+ break;
+
+ case UncheckedRadioType:
+ circle(SkIntToScalar(halfHeight), m_bgColor);
+ break;
+
+ case CheckedRadioType:
+ circle(SkIntToScalar(halfHeight), m_bgColor);
+ circle(SkIntToScalar(halfHeight - checkIndent), m_fgColor);
+ break;
+
+ case HorizontalScrollTrackBackType: {
+ // Draw a box with a notch at the left.
+ int longOffset = halfHeight - notchLongOffset;
+ int shortOffset = m_width - notchShortOffset;
+ nestedBoxes(noOffset, longOffset, shortOffset, longOffset, m_bgColor, m_edgeColor);
+ break;
+ }
+
+ case HorizontalScrollTrackForwardType: {
+ // Draw a box with a notch at the right.
+ int longOffset = halfHeight - notchLongOffset;
+ int shortOffset = m_width - notchShortOffset;
+ nestedBoxes(shortOffset, longOffset, noOffset, longOffset, m_bgColor, m_fgColor);
+ break;
+ }
+
+ case VerticalScrollTrackBackType: {
+ // Draw a box with a notch at the top.
+ int longOffset = halfWidth - notchLongOffset;
+ int shortOffset = m_height - notchShortOffset;
+ nestedBoxes(longOffset, noOffset, longOffset, shortOffset, m_bgColor, m_fgColor);
+ break;
+ }
+
+ case VerticalScrollTrackForwardType: {
+ // Draw a box with a notch at the bottom.
+ int longOffset = halfWidth - notchLongOffset;
+ int shortOffset = m_height - notchShortOffset;
+ nestedBoxes(longOffset, shortOffset, longOffset, noOffset, m_bgColor, m_fgColor);
+ break;
+ }
+
+ case HorizontalScrollThumbType:
+ // Draw a narrower box on top of the outside box.
+ nestedBoxes(thumbLongIndent, thumbShortIndent, thumbLongIndent, thumbShortIndent, m_bgColor, m_bgColor);
+ break;
+
+ case VerticalScrollThumbType:
+ // Draw a shorter box on top of the outside box.
+ nestedBoxes(thumbShortIndent, thumbLongIndent, thumbShortIndent, thumbLongIndent, m_bgColor, m_bgColor);
+ break;
+
+ case HorizontalSliderThumbType:
+ case VerticalSliderThumbType:
+ // Slider thumbs are ovals.
+ oval(m_bgColor);
+ break;
+
+ case HorizontalScrollGripType: {
+ // Draw a horizontal crosshatch for the grip.
+ int longOffset = halfWidth - gripLongIndent;
+ line(m_left + gripLongIndent, m_top + halfHeight,
+ m_right - gripLongIndent, m_top + halfHeight, m_fgColor);
+ line(m_left + longOffset, m_top + gripShortIndent,
+ m_left + longOffset, m_bottom - gripShortIndent, m_fgColor);
+ line(m_right - longOffset, m_top + gripShortIndent,
+ m_right - longOffset, m_bottom - gripShortIndent, m_fgColor);
+ break;
+ }
+
+ case VerticalScrollGripType: {
+ // Draw a vertical crosshatch for the grip.
+ int longOffset = halfHeight - gripLongIndent;
+ line(m_left + halfWidth, m_top + gripLongIndent,
+ m_left + halfWidth, m_bottom - gripLongIndent, m_fgColor);
+ line(m_left + gripShortIndent, m_top + longOffset,
+ m_right - gripShortIndent, m_top + longOffset, m_fgColor);
+ line(m_left + gripShortIndent, m_bottom - longOffset,
+ m_right - gripShortIndent, m_bottom - longOffset, m_fgColor);
+ break;
+ }
+
+ case LeftArrowType:
+ // Draw a left arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_right - quarterWidth, m_top + quarterHeight,
+ m_right - quarterWidth, m_bottom - quarterHeight,
+ m_left + quarterWidth, m_top + halfHeight, m_fgColor);
+ break;
+
+ case RightArrowType:
+ // Draw a left arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_top + quarterHeight,
+ m_right - quarterWidth, m_top + halfHeight,
+ m_left + quarterWidth, m_bottom - quarterHeight, m_fgColor);
+ break;
+
+ case UpArrowType:
+ // Draw an up arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_bottom - quarterHeight,
+ m_left + halfWidth, m_top + quarterHeight,
+ m_right - quarterWidth, m_bottom - quarterHeight, m_fgColor);
+ break;
+
+ case DownArrowType:
+ // Draw a down arrow inside a box.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_top + quarterHeight,
+ m_right - quarterWidth, m_top + quarterHeight,
+ m_left + halfWidth, m_bottom - quarterHeight, m_fgColor);
+ break;
+
+ case HorizontalSliderTrackType: {
+ // Draw a narrow rect for the track plus box hatches on the ends.
+ SkIRect lirect;
+ lirect = m_irect;
+ lirect.inset(noOffset, halfHeight - sliderIndent);
+ box(lirect, m_bgColor);
+ line(m_left, m_top, m_left, m_bottom, m_edgeColor);
+ line(m_right, m_top, m_right, m_bottom, m_edgeColor);
+ break;
+ }
+
+ case VerticalSliderTrackType: {
+ // Draw a narrow rect for the track plus box hatches on the ends.
+ SkIRect lirect;
+ lirect = m_irect;
+ lirect.inset(halfWidth - sliderIndent, noOffset);
+ box(lirect, m_bgColor);
+ line(m_left, m_top, m_right, m_top, m_edgeColor);
+ line(m_left, m_bottom, m_right, m_bottom, m_edgeColor);
+ break;
+ }
+
+ case DropDownButtonType:
+ // Draw a box with a big down arrow on top.
+ box(m_irect, m_bgColor);
+ triangle(m_left + quarterWidth, m_top,
+ m_right - quarterWidth, m_top,
+ m_left + halfWidth, m_bottom, m_fgColor);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ CRASH();
+ break;
+ }
+
+ markState();
+}
+
+// Because rendering a text field is dependent on input
+// parameters the other controls don't have, we render it directly
+// rather than trying to overcomplicate draw() further.
+void WebThemeControlDRTWin::drawTextField(bool drawEdges, bool fillContentArea, SkColor color)
+{
+ SkPaint paint;
+
+ if (fillContentArea) {
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawIRect(m_irect, paint);
+ }
+ if (drawEdges) {
+ paint.setColor(m_edgeColor);
+ paint.setStyle(SkPaint::kStroke_Style);
+ m_canvas->drawIRect(m_irect, paint);
+ }
+
+ markState();
+}
+
+void WebThemeControlDRTWin::drawProgressBar(const SkIRect& fillRect)
+{
+ SkPaint paint;
+
+ paint.setColor(m_bgColor);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawIRect(m_irect, paint);
+
+ // Emulate clipping
+ SkIRect tofill;
+ tofill.intersect(m_irect, fillRect);
+ paint.setColor(m_fgColor);
+ paint.setStyle(SkPaint::kFill_Style);
+ m_canvas->drawIRect(tofill, paint);
+
+ markState();
+}
+
diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h
new file mode 100644
index 000000000..ef731ab39
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+// WebThemeControlDRTWin implements the generic rendering of controls
+// needed by WebThemeEngineDRTWin. See the comments in that class
+// header file for why this class is needed and used.
+//
+// This class implements a generic set of widgets using Skia. The widgets
+// are optimized for testability, not a pleasing appearance.
+//
+
+#ifndef WebThemeControlDRTWin_h
+#define WebThemeControlDRTWin_h
+
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include <wtf/Noncopyable.h>
+
+// Skia forward declarations
+class SkCanvas;
+
+class WebThemeControlDRTWin {
+ WTF_MAKE_NONCOPYABLE(WebThemeControlDRTWin);
+public:
+ // This list of states mostly mirrors the list in WebCore/platform/ThemeTypes.h
+ // but is maintained separately since that isn't public and also to minimize
+ // dependencies.
+ // Note that the WebKit ThemeTypes seem to imply that a control can be
+ // in multiple states simultaneously but WebThemeEngine only allows for
+ // a single state at a time.
+ //
+ // Some definitions for the various states:
+ // Disabled - indicates that a control can't be modified or selected
+ // (corresponds to HTML 'disabled' attribute)
+ // ReadOnly - indicates that a control can't be modified but can be
+ // selected
+ // Normal - the normal state of control on the page when it isn't
+ // focused or otherwise active
+ // Hot - when the mouse is hovering over a part of the control,
+ // all the other parts are considered "hot"
+ // Hover - when the mouse is directly over a control (the CSS
+ // :hover pseudo-class)
+ // Focused - when the control has the keyboard focus
+ // Pressed - when the control is being triggered (by a mousedown or
+ // a key event).
+ // Indeterminate - when set to indeterminate (only for progress bar)
+ enum State {
+ UnknownState = 0,
+ DisabledState,
+ ReadOnlyState,
+ NormalState,
+ HotState,
+ HoverState,
+ FocusedState,
+ PressedState,
+ IndeterminateState
+ };
+
+ // This list of types mostly mirrors the list in
+ // WebCore/platform/ThemeTypes.h but is maintained
+ // separately since that isn't public and also to minimize dependencies.
+ //
+ // Note that what the user might think of as a single control can be
+ // made up of multiple parts. For example, a single scroll bar contains
+ // six clickable parts - two arrows, the "thumb" indicating the current
+ // position on the bar, the other two parts of the bar (before and after
+ // the thumb) and the "gripper" on the thumb itself.
+ //
+ enum Type {
+ UnknownType = 0,
+ TextFieldType,
+ PushButtonType,
+ UncheckedBoxType,
+ CheckedBoxType,
+ IndeterminateCheckboxType,
+ UncheckedRadioType,
+ CheckedRadioType,
+ HorizontalScrollTrackBackType,
+ HorizontalScrollTrackForwardType,
+ HorizontalScrollThumbType,
+ HorizontalScrollGripType,
+ VerticalScrollTrackBackType,
+ VerticalScrollTrackForwardType,
+ VerticalScrollThumbType,
+ VerticalScrollGripType,
+ LeftArrowType,
+ RightArrowType,
+ UpArrowType,
+ DownArrowType,
+ HorizontalSliderTrackType,
+ HorizontalSliderThumbType,
+ VerticalSliderTrackType,
+ VerticalSliderThumbType,
+ DropDownButtonType,
+ ProgressBarType
+ };
+
+ // Constructs a control of the given size, type and state to draw
+ // on to the given canvas.
+ WebThemeControlDRTWin(SkCanvas*, const SkIRect&, Type, State);
+ ~WebThemeControlDRTWin();
+
+ // Draws the control.
+ void draw();
+
+ // Use this for TextField controls instead, because the logic
+ // for drawing them is dependent on what WebKit tells us to do.
+ // If drawEdges is true, draw an edge around the control. If
+ // fillContentArea is true, fill the content area with the given color.
+ void drawTextField(bool drawEdges, bool fillContentArea, SkColor);
+
+ // Use this for drawing ProgressBar controls instead, since we
+ // need to know the rect to fill inside the bar.
+ void drawProgressBar(const SkIRect& fillRect);
+
+private:
+ // Draws a box of size specified by irect, filled with the given color.
+ // The box will have a border drawn in the default edge color.
+ void box(const SkIRect& irect, SkColor);
+
+
+ // Draws a triangle of size specified by the three pairs of coordinates,
+ // filled with the given color. The box will have an edge drawn in the
+ // default edge color.
+ void triangle(int x0, int y0, int x1, int y1, int x2, int y2, SkColor);
+
+ // Draws a rectangle the size of the control with rounded corners, filled
+ // with the specified color (and with a border in the default edge color).
+ void roundRect(SkColor);
+
+ // Draws an oval the size of the control, filled with the specified color
+ // and with a border in the default edge color.
+ void oval(SkColor);
+
+ // Draws a circle centered in the control with the specified radius,
+ // filled with the specified color, and with a border draw in the
+ // default edge color.
+ void circle(SkScalar radius, SkColor);
+
+ // Draws a box the size of the control, filled with the outerColor and
+ // with a border in the default edge color, and then draws another box
+ // indented on all four sides by the specified amounts, filled with the
+ // inner color and with a border in the default edge color.
+ void nestedBoxes(int indentLeft,
+ int indentTop,
+ int indentRight,
+ int indentBottom,
+ SkColor outerColor,
+ SkColor innerColor);
+
+ // Draws a line between the two points in the given color.
+ void line(int x0, int y0, int x1, int y1, SkColor);
+
+ // Draws a distinctive mark on the control for each state, so that the
+ // state of the control can be determined without needing to know which
+ // color is which.
+ void markState();
+
+ SkCanvas* m_canvas;
+ const SkIRect m_irect;
+ const Type m_type;
+ const State m_state;
+ const SkColor m_edgeColor;
+ const SkColor m_bgColor;
+ const SkColor m_fgColor;
+
+ // The following are convenience accessors for m_irect.
+ const int m_left;
+ const int m_right;
+ const int m_top;
+ const int m_bottom;
+ const int m_width;
+ const int m_height;
+};
+
+#endif // WebThemeControlDRTWin_h
diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.h b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.h
new file mode 100644
index 000000000..2398be3ae
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Google Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This implements the WebThemeEngine API in such a way that we match the Mac
+// port rendering more than usual Chromium path, thus allowing us to share
+// more pixel baselines.
+
+#ifndef WebThemeEngineDRTMac_h
+#define WebThemeEngineDRTMac_h
+
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/mac/WebThemeEngine.h"
+
+class WebThemeEngineDRTMac : public WebKit::WebThemeEngine {
+public:
+ virtual void paintScrollbarThumb(
+ WebKit::WebCanvas*,
+ WebKit::WebThemeEngine::State,
+ WebKit::WebThemeEngine::Size,
+ const WebKit::WebRect&,
+ const WebKit::WebThemeEngine::ScrollbarInfo&);
+
+private:
+ virtual void paintHIThemeScrollbarThumb(
+ WebKit::WebCanvas*,
+ WebKit::WebThemeEngine::State,
+ WebKit::WebThemeEngine::Size,
+ const WebKit::WebRect&,
+ const WebKit::WebThemeEngine::ScrollbarInfo&);
+ virtual void paintNSScrollerScrollbarThumb(
+ WebKit::WebCanvas*,
+ WebKit::WebThemeEngine::State,
+ WebKit::WebThemeEngine::Size,
+ const WebKit::WebRect&,
+ const WebKit::WebThemeEngine::ScrollbarInfo&);
+};
+
+#endif // WebThemeEngineDRTMac_h
diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.mm b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.mm
new file mode 100644
index 000000000..9a1c30857
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTMac.mm
@@ -0,0 +1,202 @@
+/*
+ * 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 "WebThemeEngineDRTMac.h"
+
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCanvas.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
+#import <AppKit/NSAffineTransform.h>
+#import <AppKit/NSGraphicsContext.h>
+#import <AppKit/NSScroller.h>
+#import <AppKit/NSWindow.h>
+#include <Carbon/Carbon.h>
+
+#if WEBKIT_USING_SKIA
+#include "skia/ext/skia_utils_mac.h"
+#endif
+
+using WebKit::WebCanvas;
+using WebKit::WebRect;
+using WebKit::WebThemeEngine;
+
+// We can't directly tell the NSScroller to draw itself as active or inactive,
+// instead we have to make it a child of an (in)active window. This class lets
+// us fake that parent window.
+@interface FakeActiveWindow : NSWindow {
+@private
+ BOOL hasActiveControls;
+}
++ (NSWindow*)alwaysActiveWindow;
++ (NSWindow*)alwaysInactiveWindow;
+- (id)initWithActiveControls:(BOOL)_hasActiveControls;
+- (BOOL)_hasActiveControls;
+@end
+
+@implementation FakeActiveWindow
+
+static NSWindow* alwaysActiveWindow = nil;
+static NSWindow* alwaysInactiveWindow = nil;
+
++ (NSWindow*)alwaysActiveWindow
+{
+ if (alwaysActiveWindow == nil)
+ alwaysActiveWindow = [[self alloc] initWithActiveControls:YES];
+ return alwaysActiveWindow;
+}
+
++ (NSWindow*)alwaysInactiveWindow
+{
+ if (alwaysInactiveWindow == nil)
+ alwaysInactiveWindow = [[self alloc] initWithActiveControls:NO];
+ return alwaysInactiveWindow;
+}
+
+- (id)initWithActiveControls:(BOOL)_hasActiveControls
+{
+ self = [super init];
+ hasActiveControls = _hasActiveControls;
+ return self;
+}
+
+- (BOOL)_hasActiveControls
+{
+ return hasActiveControls;
+}
+
+@end
+
+void WebThemeEngineDRTMac::paintScrollbarThumb(
+ WebCanvas* canvas,
+ WebThemeEngine::State state,
+ WebThemeEngine::Size size,
+ const WebRect& rect,
+ const WebThemeEngine::ScrollbarInfo& scrollbarInfo)
+{
+ // To match the Mac port, we still use HITheme for inner scrollbars.
+ if (scrollbarInfo.parent == WebThemeEngine::ScrollbarParentRenderLayer)
+ paintHIThemeScrollbarThumb(canvas, state, size, rect, scrollbarInfo);
+ else
+ paintNSScrollerScrollbarThumb(canvas, state, size, rect, scrollbarInfo);
+}
+
+static ThemeTrackEnableState stateToHIEnableState(WebThemeEngine::State state)
+{
+ switch (state) {
+ case WebThemeEngine::StateDisabled:
+ return kThemeTrackDisabled;
+ case WebThemeEngine::StateInactive:
+ return kThemeTrackInactive;
+ default:
+ return kThemeTrackActive;
+ }
+}
+
+// Duplicated from webkit/glue/webthemeengine_impl_mac.cc in the downstream
+// Chromium WebThemeEngine implementation.
+void WebThemeEngineDRTMac::paintHIThemeScrollbarThumb(
+ WebCanvas* canvas,
+ WebThemeEngine::State state,
+ WebThemeEngine::Size size,
+ const WebRect& rect,
+ const WebThemeEngine::ScrollbarInfo& scrollbarInfo)
+{
+ HIThemeTrackDrawInfo trackInfo;
+ trackInfo.version = 0;
+ trackInfo.kind = size == WebThemeEngine::SizeRegular ? kThemeMediumScrollBar : kThemeSmallScrollBar;
+ trackInfo.bounds = CGRectMake(rect.x, rect.y, rect.width, rect.height);
+ trackInfo.min = 0;
+ trackInfo.max = scrollbarInfo.maxValue;
+ trackInfo.value = scrollbarInfo.currentValue;
+ trackInfo.trackInfo.scrollbar.viewsize = scrollbarInfo.visibleSize;
+ trackInfo.attributes = 0;
+ if (scrollbarInfo.orientation == WebThemeEngine::ScrollbarOrientationHorizontal)
+ trackInfo.attributes |= kThemeTrackHorizontal;
+
+ trackInfo.enableState = stateToHIEnableState(state);
+
+ trackInfo.trackInfo.scrollbar.pressState =
+ state == WebThemeEngine::StatePressed ? kThemeThumbPressed : 0;
+ trackInfo.attributes |= (kThemeTrackShowThumb | kThemeTrackHideTrack);
+#if WEBKIT_USING_SKIA
+ gfx::SkiaBitLocker bitLocker(canvas);
+ CGContextRef cgContext = bitLocker.cgContext();
+#else
+ CGContextRef cgContext = canvas;
+#endif
+ HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal);
+}
+
+void WebThemeEngineDRTMac::paintNSScrollerScrollbarThumb(
+ WebCanvas* canvas,
+ WebThemeEngine::State state,
+ WebThemeEngine::Size size,
+ const WebRect& rect,
+ const WebThemeEngine::ScrollbarInfo& scrollbarInfo)
+{
+ [NSGraphicsContext saveGraphicsState];
+ NSScroller* scroller = [[NSScroller alloc] initWithFrame:NSMakeRect(rect.x, rect.y, rect.width, rect.height)];
+ [scroller setEnabled:state != WebThemeEngine::StateDisabled];
+ if (state == WebThemeEngine::StateInactive)
+ [[[FakeActiveWindow alwaysInactiveWindow] contentView] addSubview:scroller];
+ else
+ [[[FakeActiveWindow alwaysActiveWindow] contentView] addSubview:scroller];
+
+ [scroller setControlSize:size == WebThemeEngine::SizeRegular ? NSRegularControlSize : NSSmallControlSize];
+
+ double value = double(scrollbarInfo.currentValue) / double(scrollbarInfo.maxValue);
+ [scroller setDoubleValue: value];
+
+ float knobProportion = float(scrollbarInfo.visibleSize) / float(scrollbarInfo.totalSize);
+ [scroller setKnobProportion: knobProportion];
+
+#if WEBKIT_USING_SKIA
+ gfx::SkiaBitLocker bitLocker(canvas);
+ CGContextRef cgContext = bitLocker.cgContext();
+#else
+ CGContextRef cgContext = canvas;
+#endif
+ NSGraphicsContext* nsGraphicsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES];
+ [NSGraphicsContext setCurrentContext:nsGraphicsContext];
+
+ // Despite passing in frameRect() to the scroller, it always draws at (0, 0).
+ // Force it to draw in the right location by translating the whole graphics
+ // context.
+ CGContextSaveGState(cgContext);
+ NSAffineTransform *transform = [NSAffineTransform transform];
+ [transform translateXBy:rect.x yBy:rect.y];
+ [transform concat];
+
+ [scroller drawKnob];
+ CGContextRestoreGState(cgContext);
+
+ [scroller release];
+
+ [NSGraphicsContext restoreGraphicsState];
+}
diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp
new file mode 100755
index 000000000..789b1c816
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp
@@ -0,0 +1,787 @@
+/*
+ * 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 "WebThemeEngineDRTWin.h"
+
+#include "platform/WebRect.h"
+#include "WebThemeControlDRTWin.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+// Although all this code is generic, we include these headers
+// to pull in the Windows #defines for the parts and states of
+// the controls.
+#include <vsstyle.h>
+#include <windows.h>
+
+#include <wtf/Assertions.h>
+
+using namespace WebKit;
+
+// We define this for clarity, although there really should be a DFCS_NORMAL in winuser.h.
+static const int dfcsNormal = 0x0000;
+
+static SkIRect webRectToSkIRect(const WebRect& webRect)
+{
+ SkIRect irect;
+ irect.set(webRect.x, webRect.y, webRect.x + webRect.width, webRect.y + webRect.height);
+ return irect;
+}
+
+static void drawControl(WebCanvas* canvas,
+ const WebRect& rect,
+ WebThemeControlDRTWin::Type ctype,
+ WebThemeControlDRTWin::State cstate)
+{
+ WebThemeControlDRTWin control(canvas, webRectToSkIRect(rect), ctype, cstate);
+ control.draw();
+}
+
+static void drawTextField(WebCanvas* canvas,
+ const WebRect& rect,
+ WebThemeControlDRTWin::Type ctype,
+ WebThemeControlDRTWin::State cstate,
+ bool drawEdges,
+ bool fillContentArea,
+ WebColor color)
+{
+ WebThemeControlDRTWin control(canvas, webRectToSkIRect(rect), ctype, cstate);
+ control.drawTextField(drawEdges, fillContentArea, color);
+}
+
+static void drawProgressBar(WebCanvas* canvas,
+ WebThemeControlDRTWin::Type ctype,
+ WebThemeControlDRTWin::State cstate,
+ const WebRect& barRect,
+ const WebRect& fillRect)
+{
+ WebThemeControlDRTWin control(canvas, webRectToSkIRect(barRect), ctype, cstate);
+ control.drawProgressBar(webRectToSkIRect(fillRect));
+}
+
+// WebThemeEngineDRTWin
+
+void WebThemeEngineDRTWin::paintButton(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ if (part == BP_CHECKBOX) {
+ switch (state) {
+ case CBS_UNCHECKEDNORMAL:
+ ASSERT(classicState == dfcsNormal);
+ ctype = WebThemeControlDRTWin::UncheckedBoxType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case CBS_UNCHECKEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::UncheckedBoxType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case CBS_UNCHECKEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::UncheckedBoxType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case CBS_UNCHECKEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::UncheckedBoxType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case CBS_CHECKEDNORMAL:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED));
+ ctype = WebThemeControlDRTWin::CheckedBoxType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case CBS_CHECKEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::CheckedBoxType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case CBS_CHECKEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::CheckedBoxType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case CBS_CHECKEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::CheckedBoxType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case CBS_MIXEDNORMAL:
+ // Classic theme can't represent mixed state checkbox. We assume
+ // it's equivalent to unchecked.
+ ASSERT(classicState == DFCS_BUTTONCHECK);
+ ctype = WebThemeControlDRTWin::IndeterminateCheckboxType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case CBS_MIXEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::IndeterminateCheckboxType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case CBS_MIXEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::IndeterminateCheckboxType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case CBS_MIXEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONCHECK | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::IndeterminateCheckboxType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (BP_RADIOBUTTON == part) {
+ switch (state) {
+ case RBS_UNCHECKEDNORMAL:
+ ASSERT(classicState == DFCS_BUTTONRADIO);
+ ctype = WebThemeControlDRTWin::UncheckedRadioType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case RBS_UNCHECKEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::UncheckedRadioType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case RBS_UNCHECKEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::UncheckedRadioType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case RBS_UNCHECKEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::UncheckedRadioType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case RBS_CHECKEDNORMAL:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED));
+ ctype = WebThemeControlDRTWin::CheckedRadioType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case RBS_CHECKEDHOT:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::CheckedRadioType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case RBS_CHECKEDPRESSED:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::CheckedRadioType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case RBS_CHECKEDDISABLED:
+ ASSERT(classicState == (DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::CheckedRadioType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (BP_PUSHBUTTON == part) {
+ switch (state) {
+ case PBS_NORMAL:
+ ASSERT(classicState == DFCS_BUTTONPUSH);
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case PBS_HOT:
+ ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case PBS_PRESSED:
+ ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_PUSHED));
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case PBS_DISABLED:
+ ASSERT(classicState == (DFCS_BUTTONPUSH | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case PBS_DEFAULTED:
+ ASSERT(classicState == DFCS_BUTTONPUSH);
+ ctype = WebThemeControlDRTWin::PushButtonType;
+ cstate = WebThemeControlDRTWin::FocusedState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else
+ ASSERT_NOT_REACHED();
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+
+void WebThemeEngineDRTWin::paintMenuList(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ if (CP_DROPDOWNBUTTON == part) {
+ ctype = WebThemeControlDRTWin::DropDownButtonType;
+ switch (state) {
+ case CBXS_NORMAL:
+ ASSERT(classicState == DFCS_MENUARROW);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case CBXS_HOT:
+ ASSERT(classicState == (DFCS_MENUARROW | DFCS_HOT));
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case CBXS_PRESSED:
+ ASSERT(classicState == (DFCS_MENUARROW | DFCS_PUSHED));
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case CBXS_DISABLED:
+ ASSERT(classicState == (DFCS_MENUARROW | DFCS_INACTIVE));
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ CRASH();
+ break;
+ }
+ } else
+ CRASH();
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintScrollbarArrow(WebCanvas* canvas,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ switch (state) {
+ case ABS_UPNORMAL:
+ ASSERT(classicState == DFCS_SCROLLUP);
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ABS_DOWNNORMAL:
+ ASSERT(classicState == DFCS_SCROLLDOWN);
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ABS_LEFTNORMAL:
+ ASSERT(classicState == DFCS_SCROLLLEFT);
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ABS_RIGHTNORMAL:
+ ASSERT(classicState == DFCS_SCROLLRIGHT);
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ABS_UPHOT:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ABS_DOWNHOT:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ABS_LEFTHOT:
+ ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ABS_RIGHTHOT:
+ ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_HOT));
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ABS_UPHOVER:
+ ASSERT(classicState == DFCS_SCROLLUP);
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case ABS_DOWNHOVER:
+ ASSERT(classicState == DFCS_SCROLLDOWN);
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case ABS_LEFTHOVER:
+ ASSERT(classicState == DFCS_SCROLLLEFT);
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case ABS_RIGHTHOVER:
+ ASSERT(classicState == DFCS_SCROLLRIGHT);
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case ABS_UPPRESSED:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ABS_DOWNPRESSED:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ABS_LEFTPRESSED:
+ ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ABS_RIGHTPRESSED:
+ ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_PUSHED | DFCS_FLAT));
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ABS_UPDISABLED:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case ABS_DOWNDISABLED:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case ABS_LEFTDISABLED:
+ ASSERT(classicState == (DFCS_SCROLLLEFT | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::LeftArrowType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case ABS_RIGHTDISABLED:
+ ASSERT(classicState == (DFCS_SCROLLRIGHT | DFCS_INACTIVE));
+ ctype = WebThemeControlDRTWin::RightArrowType;
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintScrollbarThumb(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ switch (part) {
+ case SBP_THUMBBTNHORZ:
+ ctype = WebThemeControlDRTWin::HorizontalScrollThumbType;
+ break;
+
+ case SBP_THUMBBTNVERT:
+ ctype = WebThemeControlDRTWin::VerticalScrollThumbType;
+ break;
+
+ case SBP_GRIPPERHORZ:
+ ctype = WebThemeControlDRTWin::HorizontalScrollGripType;
+ break;
+
+ case SBP_GRIPPERVERT:
+ ctype = WebThemeControlDRTWin::VerticalScrollGripType;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ switch (state) {
+ case SCRBS_NORMAL:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case SCRBS_HOT:
+ ASSERT(classicState == DFCS_HOT);
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case SCRBS_HOVER:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case SCRBS_PRESSED:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case SCRBS_DISABLED:
+ ASSERT_NOT_REACHED(); // This should never happen in practice.
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintScrollbarTrack(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect,
+ const WebRect& alignRect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ switch (part) {
+ case SBP_UPPERTRACKHORZ:
+ ctype = WebThemeControlDRTWin::HorizontalScrollTrackBackType;
+ break;
+
+ case SBP_LOWERTRACKHORZ:
+ ctype = WebThemeControlDRTWin::HorizontalScrollTrackForwardType;
+ break;
+
+ case SBP_UPPERTRACKVERT:
+ ctype = WebThemeControlDRTWin::VerticalScrollTrackBackType;
+ break;
+
+ case SBP_LOWERTRACKVERT:
+ ctype = WebThemeControlDRTWin::VerticalScrollTrackForwardType;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ switch (state) {
+ case SCRBS_NORMAL:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case SCRBS_HOT:
+ ASSERT_NOT_REACHED(); // This should never happen in practice.
+ break;
+
+ case SCRBS_HOVER:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+
+ case SCRBS_PRESSED:
+ ASSERT_NOT_REACHED(); // This should never happen in practice.
+ break;
+
+ case SCRBS_DISABLED:
+ ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ default:
+ CRASH();
+ break;
+ }
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintSpinButton(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ if (part == SPNP_UP) {
+ ctype = WebThemeControlDRTWin::UpArrowType;
+ switch (state) {
+ case UPS_NORMAL:
+ ASSERT(classicState == DFCS_SCROLLUP);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+ case UPS_DISABLED:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_INACTIVE));
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+ case UPS_PRESSED:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_PUSHED));
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+ case UPS_HOT:
+ ASSERT(classicState == (DFCS_SCROLLUP | DFCS_HOT));
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ } else if (part == SPNP_DOWN) {
+ ctype = WebThemeControlDRTWin::DownArrowType;
+ switch (state) {
+ case DNS_NORMAL:
+ ASSERT(classicState == DFCS_SCROLLDOWN);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+ case DNS_DISABLED:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_INACTIVE));
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+ case DNS_PRESSED:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_PUSHED));
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+ case DNS_HOT:
+ ASSERT(classicState == (DFCS_SCROLLDOWN | DFCS_HOT));
+ cstate = WebThemeControlDRTWin::HoverState;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ } else
+ ASSERT_NOT_REACHED();
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+void WebThemeEngineDRTWin::paintTextField(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect,
+ WebColor color,
+ bool fillContentArea,
+ bool drawEdges)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ ASSERT(EP_EDITTEXT == part);
+ ctype = WebThemeControlDRTWin::TextFieldType;
+
+ switch (state) {
+ case ETS_NORMAL:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case ETS_HOT:
+ ASSERT(classicState == DFCS_HOT);
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case ETS_DISABLED:
+ ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case ETS_SELECTED:
+ ASSERT(classicState == DFCS_PUSHED);
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ case ETS_FOCUSED:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::FocusedState;
+ break;
+
+ case ETS_READONLY:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::ReadOnlyState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ drawTextField(canvas, rect, ctype, cstate, drawEdges, fillContentArea, color);
+}
+
+void WebThemeEngineDRTWin::paintTrackbar(WebCanvas* canvas,
+ int part,
+ int state,
+ int classicState,
+ const WebRect& rect)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::UnknownType;
+ WebThemeControlDRTWin::State cstate = WebThemeControlDRTWin::UnknownState;
+
+ if (TKP_THUMBBOTTOM == part) {
+ ctype = WebThemeControlDRTWin::HorizontalSliderThumbType;
+ switch (state) {
+ case TUS_NORMAL:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case TUS_HOT:
+ ASSERT(classicState == DFCS_HOT);
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case TUS_DISABLED:
+ ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case TUS_PRESSED:
+ ASSERT(classicState == DFCS_PUSHED);
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (TKP_THUMBVERT == part) {
+ ctype = WebThemeControlDRTWin::VerticalSliderThumbType;
+ switch (state) {
+ case TUS_NORMAL:
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ break;
+
+ case TUS_HOT:
+ ASSERT(classicState == DFCS_HOT);
+ cstate = WebThemeControlDRTWin::HotState;
+ break;
+
+ case TUS_DISABLED:
+ ASSERT(classicState == DFCS_INACTIVE);
+ cstate = WebThemeControlDRTWin::DisabledState;
+ break;
+
+ case TUS_PRESSED:
+ ASSERT(classicState == DFCS_PUSHED);
+ cstate = WebThemeControlDRTWin::PressedState;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ } else if (TKP_TRACK == part) {
+ ctype = WebThemeControlDRTWin::HorizontalSliderTrackType;
+ ASSERT(state == TRS_NORMAL);
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ } else if (TKP_TRACKVERT == part) {
+ ctype = WebThemeControlDRTWin::VerticalSliderTrackType;
+ ASSERT(state == TRVS_NORMAL);
+ ASSERT(classicState == dfcsNormal);
+ cstate = WebThemeControlDRTWin::NormalState;
+ } else
+ ASSERT_NOT_REACHED();
+
+ drawControl(canvas, rect, ctype, cstate);
+}
+
+
+void WebThemeEngineDRTWin::paintProgressBar(WebKit::WebCanvas* canvas,
+ const WebKit::WebRect& barRect,
+ const WebKit::WebRect& valueRect,
+ bool determinate,
+ double)
+{
+ WebThemeControlDRTWin::Type ctype = WebThemeControlDRTWin::ProgressBarType;
+ WebThemeControlDRTWin::State cstate = determinate ? WebThemeControlDRTWin::NormalState
+ : WebThemeControlDRTWin::IndeterminateState;
+ drawProgressBar(canvas, ctype, cstate, barRect, valueRect);
+}
+
diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h
new file mode 100644
index 000000000..daa911166
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+// This implements the WebThemeEngine API used by the Windows version of
+// Chromium to render native form controls like checkboxes, radio buttons,
+// and scroll bars.
+// The normal implementation (native_theme) renders the controls using either
+// the UXTheme theming engine present in XP, Vista, and Win 7, or the "classic"
+// theme used if that theme is selected in the Desktop settings.
+// Unfortunately, both of these themes render controls differently on the
+// different versions of Windows.
+//
+// In order to ensure maximum consistency of baselines across the different
+// Windows versions, we provide a simple implementation for DRT here
+// instead. These controls are actually platform-independent (they're rendered
+// using Skia) and could be used on Linux and the Mac as well, should we
+// choose to do so at some point.
+//
+
+#ifndef WebThemeEngineDRTWin_h
+#define WebThemeEngineDRTWin_h
+
+#include "platform/win/WebThemeEngine.h"
+#include <wtf/Noncopyable.h>
+
+class WebThemeEngineDRTWin : public WebKit::WebThemeEngine {
+ WTF_MAKE_NONCOPYABLE(WebThemeEngineDRTWin);
+public:
+ WebThemeEngineDRTWin() { }
+
+ // WebThemeEngine methods:
+ virtual void paintButton(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintMenuList(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintScrollbarArrow(
+ WebKit::WebCanvas*, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintScrollbarThumb(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintScrollbarTrack(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&, const WebKit::WebRect& alignRect);
+
+ virtual void paintSpinButton(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintTextField(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&, WebKit::WebColor, bool fillContentArea,
+ bool drawEdges);
+
+ virtual void paintTrackbar(
+ WebKit::WebCanvas*, int part, int state, int classicState,
+ const WebKit::WebRect&);
+
+ virtual void paintProgressBar(
+ WebKit::WebCanvas*, const WebKit::WebRect& barRect,
+ const WebKit::WebRect& valueRect,
+ bool determinate, double time);
+};
+
+#endif // WebThemeEngineDRTWin_h
diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.cpp b/Tools/DumpRenderTree/chromium/WebViewHost.cpp
new file mode 100644
index 000000000..1b0687dd0
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebViewHost.cpp
@@ -0,0 +1,1687 @@
+/*
+ * Copyright (C) 2010, 2011 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 "WebViewHost.h"
+
+#include "LayoutTestController.h"
+#include "TestNavigationController.h"
+#include "TestShell.h"
+#include "TestWebPlugin.h"
+#include "TestWebWorker.h"
+#include "platform/WebCString.h"
+#include "WebConsoleMessage.h"
+#include "WebContextMenuData.h"
+#include "WebDOMMessageEvent.h"
+#include "WebDataSource.h"
+#include "WebDeviceOrientationClientMock.h"
+#include "platform/WebDragData.h"
+#include "WebElement.h"
+#include "WebFrame.h"
+#include "WebGeolocationClientMock.h"
+#include "WebHistoryItem.h"
+#include "WebKit.h"
+#include "WebNode.h"
+#include "WebPluginParams.h"
+#include "WebPopupMenu.h"
+#include "WebPopupType.h"
+#include "WebRange.h"
+#include "platform/WebRect.h"
+#include "WebScreenInfo.h"
+#include "platform/WebSize.h"
+#include "WebSpeechInputControllerMock.h"
+#include "WebStorageNamespace.h"
+#include "WebTextCheckingCompletion.h"
+#include "WebTextCheckingResult.h"
+#include "platform/WebThread.h"
+#include "platform/WebURLRequest.h"
+#include "platform/WebURLResponse.h"
+#include "WebView.h"
+#include "WebWindowFeatures.h"
+#include "skia/ext/platform_canvas.h"
+#include "webkit/support/webkit_support.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+using namespace WebCore;
+using namespace WebKit;
+using namespace std;
+
+static const int screenWidth = 1920;
+static const int screenHeight = 1080;
+static const int screenUnavailableBorder = 8;
+
+// WebNavigationType debugging strings taken from PolicyDelegate.mm.
+static const char* linkClickedString = "link clicked";
+static const char* formSubmittedString = "form submitted";
+static const char* backForwardString = "back/forward";
+static const char* reloadString = "reload";
+static const char* formResubmittedString = "form resubmitted";
+static const char* otherString = "other";
+static const char* illegalString = "illegal value";
+
+static int nextPageID = 1;
+
+// Used to write a platform neutral file:/// URL by only taking the filename
+// (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
+static string urlSuitableForTestResult(const string& url)
+{
+ if (url.empty() || string::npos == url.find("file://"))
+ return url;
+
+ size_t pos = url.rfind('/');
+ if (pos == string::npos) {
+#if OS(WINDOWS)
+ pos = url.rfind('\\');
+ if (pos == string::npos)
+ pos = 0;
+#else
+ pos = 0;
+#endif
+ }
+ string filename = url.substr(pos + 1);
+ if (filename.empty())
+ return "file:"; // A WebKit test has this in its expected output.
+ return filename;
+}
+
+// Used to write a platform neutral file:/// URL by taking the
+// filename and its directory. (e.g., converts
+// "file:///tmp/foo/bar.txt" to just "bar.txt").
+static string descriptionSuitableForTestResult(const string& url)
+{
+ if (url.empty() || string::npos == url.find("file://"))
+ return url;
+
+ size_t pos = url.rfind('/');
+ if (pos == string::npos || !pos)
+ return "ERROR:" + url;
+ pos = url.rfind('/', pos - 1);
+ if (pos == string::npos)
+ return "ERROR:" + url;
+
+ return url.substr(pos + 1);
+}
+
+// Adds a file called "DRTFakeFile" to dragData (CF_HDROP). Use to fake
+// dragging a file.
+static void addDRTFakeFileToDataObject(WebDragData* dragData)
+{
+ dragData->appendToFilenames(WebString::fromUTF8("DRTFakeFile"));
+}
+
+// Get a debugging string from a WebNavigationType.
+static const char* webNavigationTypeToString(WebNavigationType type)
+{
+ switch (type) {
+ case WebKit::WebNavigationTypeLinkClicked:
+ return linkClickedString;
+ case WebKit::WebNavigationTypeFormSubmitted:
+ return formSubmittedString;
+ case WebKit::WebNavigationTypeBackForward:
+ return backForwardString;
+ case WebKit::WebNavigationTypeReload:
+ return reloadString;
+ case WebKit::WebNavigationTypeFormResubmitted:
+ return formResubmittedString;
+ case WebKit::WebNavigationTypeOther:
+ return otherString;
+ }
+ return illegalString;
+}
+
+static string URLDescription(const GURL& url)
+{
+ if (url.SchemeIs("file"))
+ return url.ExtractFileName();
+ return url.possibly_invalid_spec();
+}
+
+static void printResponseDescription(const WebURLResponse& response)
+{
+ if (response.isNull()) {
+ fputs("(null)", stdout);
+ return;
+ }
+ string url = response.url().spec();
+ printf("<NSURLResponse %s, http status code %d>",
+ descriptionSuitableForTestResult(url).c_str(),
+ response.httpStatusCode());
+}
+
+static void printNodeDescription(const WebNode& node, int exception)
+{
+ if (exception) {
+ fputs("ERROR", stdout);
+ return;
+ }
+ if (node.isNull()) {
+ fputs("(null)", stdout);
+ return;
+ }
+ fputs(node.nodeName().utf8().data(), stdout);
+ const WebNode& parent = node.parentNode();
+ if (!parent.isNull()) {
+ fputs(" > ", stdout);
+ printNodeDescription(parent, 0);
+ }
+}
+
+static void printRangeDescription(const WebRange& range)
+{
+ if (range.isNull()) {
+ fputs("(null)", stdout);
+ return;
+ }
+ printf("range from %d of ", range.startOffset());
+ int exception = 0;
+ WebNode startNode = range.startContainer(exception);
+ printNodeDescription(startNode, exception);
+ printf(" to %d of ", range.endOffset());
+ WebNode endNode = range.endContainer(exception);
+ printNodeDescription(endNode, exception);
+}
+
+static string editingActionDescription(WebEditingAction action)
+{
+ switch (action) {
+ case WebKit::WebEditingActionTyped:
+ return "WebViewInsertActionTyped";
+ case WebKit::WebEditingActionPasted:
+ return "WebViewInsertActionPasted";
+ case WebKit::WebEditingActionDropped:
+ return "WebViewInsertActionDropped";
+ }
+ return "(UNKNOWN ACTION)";
+}
+
+static string textAffinityDescription(WebTextAffinity affinity)
+{
+ switch (affinity) {
+ case WebKit::WebTextAffinityUpstream:
+ return "NSSelectionAffinityUpstream";
+ case WebKit::WebTextAffinityDownstream:
+ return "NSSelectionAffinityDownstream";
+ }
+ return "(UNKNOWN AFFINITY)";
+}
+
+// WebViewClient -------------------------------------------------------------
+
+WebView* WebViewHost::createView(WebFrame*, const WebURLRequest& request, const WebWindowFeatures&, const WebString&)
+{
+ if (!layoutTestController()->canOpenWindows())
+ return 0;
+ if (layoutTestController()->shouldDumpCreateView())
+ fprintf(stdout, "createView(%s)\n", URLDescription(request.url()).c_str());
+ return m_shell->createNewWindow(WebURL())->webView();
+}
+
+WebWidget* WebViewHost::createPopupMenu(WebPopupType type)
+{
+ switch (type) {
+ case WebKit::WebPopupTypeNone:
+ break;
+ case WebKit::WebPopupTypeSelect:
+ case WebKit::WebPopupTypeSuggestion:
+ m_popupmenus.append(WebPopupMenu::create(0));
+ return m_popupmenus.last();
+ }
+ return 0;
+}
+
+WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&)
+{
+ // Do not use this method. It's been replaced by createExternalPopupMenu.
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+WebStorageNamespace* WebViewHost::createSessionStorageNamespace(unsigned quota)
+{
+ return WebKit::WebStorageNamespace::createSessionStorageNamespace(quota);
+}
+
+void WebViewHost::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
+{
+ // This matches win DumpRenderTree's UIDelegate.cpp.
+ if (!m_logConsoleOutput)
+ return;
+ string newMessage;
+ if (!message.text.isEmpty()) {
+ newMessage = message.text.utf8();
+ size_t fileProtocol = newMessage.find("file://");
+ if (fileProtocol != string::npos) {
+ newMessage = newMessage.substr(0, fileProtocol)
+ + urlSuitableForTestResult(newMessage.substr(fileProtocol));
+ }
+ }
+ printf("CONSOLE MESSAGE: line %d: %s\n", sourceLine, newMessage.data());
+}
+
+void WebViewHost::didStartLoading()
+{
+ m_shell->setIsLoading(true);
+}
+
+void WebViewHost::didStopLoading()
+{
+ if (layoutTestController()->shouldDumpProgressFinishedCallback())
+ fputs("postProgressFinishedNotification\n", stdout);
+ m_shell->setIsLoading(false);
+}
+
+// The output from these methods in layout test mode should match that
+// expected by the layout tests. See EditingDelegate.m in DumpRenderTree.
+
+bool WebViewHost::shouldBeginEditing(const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldBeginEditingInDOMRange:", stdout);
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldEndEditing(const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldEndEditingInDOMRange:", stdout);
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldInsertNode:", stdout);
+ printNodeDescription(node, 0);
+ fputs(" replacingDOMRange:", stdout);
+ printRangeDescription(range);
+ printf(" givenAction:%s\n", editingActionDescription(action).c_str());
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:", text.utf8().data());
+ printRangeDescription(range);
+ printf(" givenAction:%s\n", editingActionDescription(action).c_str());
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldChangeSelectedRange(
+ const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldChangeSelectedDOMRange:", stdout);
+ printRangeDescription(fromRange);
+ fputs(" toDOMRange:", stdout);
+ printRangeDescription(toRange);
+ printf(" affinity:%s stillSelecting:%s\n",
+ textAffinityDescription(affinity).c_str(),
+ (stillSelecting ? "TRUE" : "FALSE"));
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldDeleteRange(const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ fputs("EDITING DELEGATE: shouldDeleteDOMRange:", stdout);
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::shouldApplyStyle(const WebString& style, const WebRange& range)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks()) {
+ printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:", style.utf8().data());
+ printRangeDescription(range);
+ fputs("\n", stdout);
+ }
+ return layoutTestController()->acceptsEditing();
+}
+
+bool WebViewHost::isSmartInsertDeleteEnabled()
+{
+ return m_smartInsertDeleteEnabled;
+}
+
+bool WebViewHost::isSelectTrailingWhitespaceEnabled()
+{
+ return m_selectTrailingWhitespaceEnabled;
+}
+
+void WebViewHost::didBeginEditing()
+{
+ if (!layoutTestController()->shouldDumpEditingCallbacks())
+ return;
+ fputs("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n", stdout);
+}
+
+void WebViewHost::didChangeSelection(bool isEmptySelection)
+{
+ if (layoutTestController()->shouldDumpEditingCallbacks())
+ fputs("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n", stdout);
+ // No need to update clipboard with the selected text in DRT.
+}
+
+void WebViewHost::didChangeContents()
+{
+ if (!layoutTestController()->shouldDumpEditingCallbacks())
+ return;
+ fputs("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n", stdout);
+}
+
+void WebViewHost::didEndEditing()
+{
+ if (!layoutTestController()->shouldDumpEditingCallbacks())
+ return;
+ fputs("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n", stdout);
+}
+
+bool WebViewHost::handleCurrentKeyboardEvent()
+{
+ if (m_editCommandName.empty())
+ return false;
+ WebFrame* frame = webView()->focusedFrame();
+ if (!frame)
+ return false;
+
+ return frame->executeCommand(WebString::fromUTF8(m_editCommandName), WebString::fromUTF8(m_editCommandValue));
+}
+
+void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength, WebVector<WebString>* optionalSuggestions)
+{
+ // Check the spelling of the given text.
+ m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength);
+}
+
+void WebViewHost::requestCheckingOfText(const WebString& text, WebTextCheckingCompletion* completion)
+{
+ if (text.isEmpty()) {
+ if (completion)
+ completion->didFinishCheckingText(Vector<WebTextCheckingResult>());
+ return;
+ }
+
+ m_lastRequestedTextCheckingCompletion = completion;
+ m_lastRequestedTextCheckString = text;
+ postDelayedTask(new HostMethodTask(this, &WebViewHost::finishLastTextCheck), 0);
+}
+
+void WebViewHost::finishLastTextCheck()
+{
+ Vector<WebTextCheckingResult> results;
+ // FIXME: Do the grammar check.
+ int offset = 0;
+ String text(m_lastRequestedTextCheckString.data(), m_lastRequestedTextCheckString.length());
+ while (text.length()) {
+ int misspelledPosition = 0;
+ int misspelledLength = 0;
+ m_spellcheck.spellCheckWord(WebString(text.characters(), text.length()), &misspelledPosition, &misspelledLength);
+ if (!misspelledLength)
+ break;
+ results.append(WebTextCheckingResult(WebTextCheckingResult::ErrorSpelling, offset + misspelledPosition, misspelledLength));
+ text = text.substring(misspelledPosition + misspelledLength);
+ offset += misspelledPosition + misspelledLength;
+ }
+
+ m_lastRequestedTextCheckingCompletion->didFinishCheckingText(results);
+ m_lastRequestedTextCheckingCompletion = 0;
+}
+
+
+WebString WebViewHost::autoCorrectWord(const WebString&)
+{
+ // Returns an empty string as Mac WebKit ('WebKitSupport/WebEditorClient.mm')
+ // does. (If this function returns a non-empty string, WebKit replaces the
+ // given misspelled string with the result one. This process executes some
+ // editor commands and causes layout-test failures.)
+ return WebString();
+}
+
+void WebViewHost::runModalAlertDialog(WebFrame*, const WebString& message)
+{
+ printf("ALERT: %s\n", message.utf8().data());
+}
+
+bool WebViewHost::runModalConfirmDialog(WebFrame*, const WebString& message)
+{
+ printf("CONFIRM: %s\n", message.utf8().data());
+ return true;
+}
+
+bool WebViewHost::runModalPromptDialog(WebFrame* frame, const WebString& message,
+ const WebString& defaultValue, WebString*)
+{
+ printf("PROMPT: %s, default text: %s\n", message.utf8().data(), defaultValue.utf8().data());
+ return true;
+}
+
+bool WebViewHost::runModalBeforeUnloadDialog(WebFrame*, const WebString& message)
+{
+ printf("CONFIRM NAVIGATION: %s\n", message.utf8().data());
+ return !layoutTestController()->shouldStayOnPageAfterHandlingBeforeUnload();
+}
+
+void WebViewHost::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData)
+{
+ m_lastContextMenuData = adoptPtr(new WebContextMenuData(contextMenuData));
+}
+
+void WebViewHost::clearContextMenuData()
+{
+ m_lastContextMenuData.clear();
+}
+
+WebContextMenuData* WebViewHost::lastContextMenuData() const
+{
+ return m_lastContextMenuData.get();
+}
+
+void WebViewHost::setStatusText(const WebString& text)
+{
+ if (!layoutTestController()->shouldDumpStatusCallbacks())
+ return;
+ // When running tests, write to stdout.
+ printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text.utf8().data());
+}
+
+void WebViewHost::startDragging(const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&)
+{
+ WebDragData mutableDragData = data;
+ if (layoutTestController()->shouldAddFileToPasteboard()) {
+ // Add a file called DRTFakeFile to the drag&drop clipboard.
+ addDRTFakeFileToDataObject(&mutableDragData);
+ }
+
+ // When running a test, we need to fake a drag drop operation otherwise
+ // Windows waits for real mouse events to know when the drag is over.
+ m_shell->eventSender()->doDragDrop(mutableDragData, mask);
+}
+
+void WebViewHost::didUpdateLayout()
+{
+#if OS(MAC_OS_X)
+ static bool queryingPreferredSize = false;
+ if (queryingPreferredSize)
+ return;
+
+ queryingPreferredSize = true;
+ // Query preferred width to emulate the same functionality in Chromium:
+ // see RenderView::CheckPreferredSize (src/content/renderer/render_view.cc)
+ // and TabContentsViewMac::RenderViewCreated (src/chrome/browser/tab_contents/tab_contents_view_mac.mm)
+ webView()->mainFrame()->contentsPreferredWidth();
+ webView()->mainFrame()->documentElementScrollHeight();
+ queryingPreferredSize = false;
+#endif
+}
+
+void WebViewHost::navigateBackForwardSoon(int offset)
+{
+ navigationController()->goToOffset(offset);
+}
+
+int WebViewHost::historyBackListCount()
+{
+ return navigationController()->lastCommittedEntryIndex();
+}
+
+int WebViewHost::historyForwardListCount()
+{
+ int currentIndex =navigationController()->lastCommittedEntryIndex();
+ return navigationController()->entryCount() - currentIndex - 1;
+}
+
+void WebViewHost::postAccessibilityNotification(const WebAccessibilityObject& obj, WebAccessibilityNotification notification)
+{
+ if (notification == WebAccessibilityNotificationFocusedUIElementChanged)
+ m_shell->accessibilityController()->setFocusedElement(obj);
+
+ const char* notificationName;
+ switch (notification) {
+ case WebAccessibilityNotificationActiveDescendantChanged:
+ notificationName = "ActiveDescendantChanged";
+ break;
+ case WebAccessibilityNotificationAutocorrectionOccured:
+ notificationName = "AutocorrectionOccured";
+ break;
+ case WebAccessibilityNotificationCheckedStateChanged:
+ notificationName = "CheckedStateChanged";
+ break;
+ case WebAccessibilityNotificationChildrenChanged:
+ notificationName = "ChildrenChanged";
+ break;
+ case WebAccessibilityNotificationFocusedUIElementChanged:
+ notificationName = "FocusedUIElementChanged";
+ break;
+ case WebAccessibilityNotificationLayoutComplete:
+ notificationName = "LayoutComplete";
+ break;
+ case WebAccessibilityNotificationLoadComplete:
+ notificationName = "LoadComplete";
+ break;
+ case WebAccessibilityNotificationSelectedChildrenChanged:
+ notificationName = "SelectedChildrenChanged";
+ break;
+ case WebAccessibilityNotificationSelectedTextChanged:
+ notificationName = "SelectedTextChanged";
+ break;
+ case WebAccessibilityNotificationValueChanged:
+ notificationName = "ValueChanged";
+ break;
+ case WebAccessibilityNotificationScrolledToAnchor:
+ notificationName = "ScrolledToAnchor";
+ break;
+ case WebAccessibilityNotificationLiveRegionChanged:
+ notificationName = "LiveRegionChanged";
+ break;
+ case WebAccessibilityNotificationMenuListItemSelected:
+ notificationName = "MenuListItemSelected";
+ break;
+ case WebAccessibilityNotificationMenuListValueChanged:
+ notificationName = "MenuListValueChanged";
+ break;
+ case WebAccessibilityNotificationRowCountChanged:
+ notificationName = "RowCountChanged";
+ break;
+ case WebAccessibilityNotificationRowCollapsed:
+ notificationName = "RowCollapsed";
+ break;
+ case WebAccessibilityNotificationRowExpanded:
+ notificationName = "RowExpanded";
+ break;
+ case WebAccessibilityNotificationInvalidStatusChanged:
+ notificationName = "InvalidStatusChanged";
+ break;
+ default:
+ notificationName = "UnknownNotification";
+ break;
+ }
+
+ m_shell->accessibilityController()->notificationReceived(obj, notificationName);
+
+ if (m_shell->accessibilityController()->shouldLogAccessibilityEvents()) {
+ printf("AccessibilityNotification - %s", notificationName);
+
+ WebKit::WebNode node = obj.node();
+ if (!node.isNull() && node.isElementNode()) {
+ WebKit::WebElement element = node.to<WebKit::WebElement>();
+ if (element.hasAttribute("id"))
+ printf(" - id:%s", element.getAttribute("id").utf8().data());
+ }
+
+ printf("\n");
+ }
+}
+
+WebNotificationPresenter* WebViewHost::notificationPresenter()
+{
+ return m_shell->notificationPresenter();
+}
+
+WebKit::WebGeolocationClient* WebViewHost::geolocationClient()
+{
+ return geolocationClientMock();
+}
+
+WebKit::WebGeolocationClientMock* WebViewHost::geolocationClientMock()
+{
+ if (!m_geolocationClientMock)
+ m_geolocationClientMock = adoptPtr(WebGeolocationClientMock::create());
+ return m_geolocationClientMock.get();
+}
+
+WebSpeechInputController* WebViewHost::speechInputController(WebKit::WebSpeechInputListener* listener)
+{
+ if (!m_speechInputControllerMock)
+ m_speechInputControllerMock = adoptPtr(WebSpeechInputControllerMock::create(listener));
+ return m_speechInputControllerMock.get();
+}
+
+WebDeviceOrientationClientMock* WebViewHost::deviceOrientationClientMock()
+{
+ if (!m_deviceOrientationClientMock.get())
+ m_deviceOrientationClientMock = adoptPtr(WebDeviceOrientationClientMock::create());
+ return m_deviceOrientationClientMock.get();
+}
+
+MockSpellCheck* WebViewHost::mockSpellCheck()
+{
+ return &m_spellcheck;
+}
+
+WebDeviceOrientationClient* WebViewHost::deviceOrientationClient()
+{
+ return deviceOrientationClientMock();
+}
+
+// WebWidgetClient -----------------------------------------------------------
+
+void WebViewHost::didInvalidateRect(const WebRect& rect)
+{
+ updatePaintRect(rect);
+}
+
+void WebViewHost::didScrollRect(int, int, const WebRect& clipRect)
+{
+ // This is used for optimizing painting when the renderer is scrolled. We're
+ // currently not doing any optimizations so just invalidate the region.
+ didInvalidateRect(clipRect);
+}
+
+void WebViewHost::scheduleComposite()
+{
+ WebSize widgetSize = webWidget()->size();
+ WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
+ didInvalidateRect(clientRect);
+}
+
+#if ENABLE(REQUEST_ANIMATION_FRAME)
+void WebViewHost::scheduleAnimation()
+{
+ postDelayedTask(new HostMethodTask(this, &WebViewHost::scheduleComposite), 0);
+}
+#endif
+
+void WebViewHost::didFocus()
+{
+ m_shell->setFocus(webWidget(), true);
+}
+
+void WebViewHost::didBlur()
+{
+ m_shell->setFocus(webWidget(), false);
+}
+
+WebScreenInfo WebViewHost::screenInfo()
+{
+ // We don't need to set actual values.
+ WebScreenInfo info;
+ info.depth = 24;
+ info.depthPerComponent = 8;
+ info.isMonochrome = false;
+ info.rect = WebRect(0, 0, screenWidth, screenHeight);
+ // Use values different from info.rect for testing.
+ info.availableRect = WebRect(screenUnavailableBorder, screenUnavailableBorder,
+ screenWidth - screenUnavailableBorder * 2,
+ screenHeight - screenUnavailableBorder * 2);
+ return info;
+}
+
+void WebViewHost::show(WebNavigationPolicy)
+{
+ m_hasWindow = true;
+ WebSize size = webWidget()->size();
+ updatePaintRect(WebRect(0, 0, size.width, size.height));
+}
+
+
+
+void WebViewHost::closeWidget()
+{
+ m_hasWindow = false;
+ m_shell->closeWindow(this);
+ // No more code here, we should be deleted at this point.
+}
+
+void WebViewHost::closeWidgetSoon()
+{
+ postDelayedTask(new HostMethodTask(this, &WebViewHost::closeWidget), 0);
+}
+
+void WebViewHost::didChangeCursor(const WebCursorInfo& cursorInfo)
+{
+ if (!hasWindow())
+ return;
+ m_currentCursor = cursorInfo;
+}
+
+WebRect WebViewHost::windowRect()
+{
+ return m_windowRect;
+}
+
+void WebViewHost::setWindowRect(const WebRect& rect)
+{
+ m_windowRect = rect;
+ const int border2 = TestShell::virtualWindowBorder * 2;
+ if (m_windowRect.width <= border2)
+ m_windowRect.width = 1 + border2;
+ if (m_windowRect.height <= border2)
+ m_windowRect.height = 1 + border2;
+ int width = m_windowRect.width - border2;
+ int height = m_windowRect.height - border2;
+ discardBackingStore();
+ webWidget()->resize(WebSize(width, height));
+ updatePaintRect(WebRect(0, 0, width, height));
+}
+
+WebRect WebViewHost::rootWindowRect()
+{
+ return windowRect();
+}
+
+WebRect WebViewHost::windowResizerRect()
+{
+ // Not necessary.
+ return WebRect();
+}
+
+void WebViewHost::runModal()
+{
+ bool oldState = webkit_support::MessageLoopNestableTasksAllowed();
+ webkit_support::MessageLoopSetNestableTasksAllowed(true);
+ m_inModalLoop = true;
+ webkit_support::RunMessageLoop();
+ webkit_support::MessageLoopSetNestableTasksAllowed(oldState);
+}
+
+bool WebViewHost::enterFullScreen()
+{
+ postDelayedTask(new HostMethodTask(this, &WebViewHost::enterFullScreenNow), 0);
+ return true;
+}
+
+void WebViewHost::exitFullScreen()
+{
+ postDelayedTask(new HostMethodTask(this, &WebViewHost::exitFullScreenNow), 0);
+}
+
+// WebFrameClient ------------------------------------------------------------
+
+WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params)
+{
+ if (params.mimeType == TestWebPlugin::mimeType())
+ return new TestWebPlugin(frame, params);
+
+ return webkit_support::CreateWebPlugin(frame, params);
+}
+
+WebWorker* WebViewHost::createWorker(WebFrame*, WebSharedWorkerClient*)
+{
+ return new TestWebWorker();
+}
+
+WebMediaPlayer* WebViewHost::createMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client)
+{
+ return webkit_support::CreateMediaPlayer(frame, client);
+}
+
+WebApplicationCacheHost* WebViewHost::createApplicationCacheHost(WebFrame* frame, WebApplicationCacheHostClient* client)
+{
+ return webkit_support::CreateApplicationCacheHost(frame, client);
+}
+
+void WebViewHost::loadURLExternally(WebFrame* frame, const WebURLRequest& request, WebNavigationPolicy policy)
+{
+ loadURLExternally(frame, request, policy, WebString());
+}
+
+void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy, const WebString& downloadName)
+{
+ ASSERT(policy != WebKit::WebNavigationPolicyCurrentTab);
+ WebViewHost* another = m_shell->createNewWindow(request.url());
+ if (another)
+ another->show(policy);
+}
+
+WebNavigationPolicy WebViewHost::decidePolicyForNavigation(
+ WebFrame*, const WebURLRequest& request,
+ WebNavigationType type, const WebNode& originatingNode,
+ WebNavigationPolicy defaultPolicy, bool isRedirect)
+{
+ WebNavigationPolicy result;
+ if (!m_policyDelegateEnabled)
+ return defaultPolicy;
+
+ printf("Policy delegate: attempt to load %s with navigation type '%s'",
+ URLDescription(request.url()).c_str(), webNavigationTypeToString(type));
+ if (!originatingNode.isNull()) {
+ fputs(" originating from ", stdout);
+ printNodeDescription(originatingNode, 0);
+ }
+ fputs("\n", stdout);
+ if (m_policyDelegateIsPermissive)
+ result = WebKit::WebNavigationPolicyCurrentTab;
+ else
+ result = WebKit::WebNavigationPolicyIgnore;
+
+ if (m_policyDelegateShouldNotifyDone)
+ layoutTestController()->policyDelegateDone();
+ return result;
+}
+
+bool WebViewHost::canHandleRequest(WebFrame*, const WebURLRequest& request)
+{
+ GURL url = request.url();
+ // Just reject the scheme used in
+ // LayoutTests/http/tests/misc/redirect-to-external-url.html
+ return !url.SchemeIs("spaceballs");
+}
+
+WebURLError WebViewHost::cannotHandleRequestError(WebFrame*, const WebURLRequest& request)
+{
+ WebURLError error;
+ // A WebKit layout test expects the following values.
+ // unableToImplementPolicyWithError() below prints them.
+ error.domain = WebString::fromUTF8("WebKitErrorDomain");
+ error.reason = 101;
+ error.unreachableURL = request.url();
+ return error;
+}
+
+WebURLError WebViewHost::cancelledError(WebFrame*, const WebURLRequest& request)
+{
+ return webkit_support::CreateCancelledError(request);
+}
+
+void WebViewHost::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error)
+{
+ printf("Policy delegate: unable to implement policy with error domain '%s', "
+ "error code %d, in frame '%s'\n",
+ error.domain.utf8().data(), error.reason, frame->name().utf8().data());
+}
+
+void WebViewHost::willPerformClientRedirect(WebFrame* frame, const WebURL& from, const WebURL& to,
+ double interval, double fire_time)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ printf(" - willPerformClientRedirectToURL: %s \n", to.spec().data());
+ }
+
+ if (m_shell->shouldDumpUserGestureInFrameLoadCallbacks())
+ printFrameUserGestureStatus(frame, " - in willPerformClientRedirect\n");
+}
+
+void WebViewHost::didCancelClientRedirect(WebFrame* frame)
+{
+ if (!m_shell->shouldDumpFrameLoadCallbacks())
+ return;
+ printFrameDescription(frame);
+ fputs(" - didCancelClientRedirectForFrame\n", stdout);
+}
+
+void WebViewHost::didCreateDataSource(WebFrame*, WebDataSource* ds)
+{
+ ds->setExtraData(m_pendingExtraData.leakPtr());
+ if (!layoutTestController()->deferMainResourceDataLoad())
+ ds->setDeferMainResourceDataLoad(false);
+}
+
+void WebViewHost::didStartProvisionalLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didStartProvisionalLoadForFrame\n", stdout);
+ }
+
+ if (m_shell->shouldDumpUserGestureInFrameLoadCallbacks())
+ printFrameUserGestureStatus(frame, " - in didStartProvisionalLoadForFrame\n");
+
+ if (!m_topLoadingFrame)
+ m_topLoadingFrame = frame;
+
+ if (layoutTestController()->stopProvisionalFrameLoads()) {
+ printFrameDescription(frame);
+ fputs(" - stopping load in didStartProvisionalLoadForFrame callback\n", stdout);
+ frame->stopLoading();
+ }
+ updateAddressBar(frame->view());
+}
+
+void WebViewHost::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didReceiveServerRedirectForProvisionalLoadForFrame\n", stdout);
+ }
+ updateAddressBar(frame->view());
+}
+
+void WebViewHost::didFailProvisionalLoad(WebFrame* frame, const WebURLError& error)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFailProvisionalLoadWithError\n", stdout);
+ }
+
+ locationChangeDone(frame);
+
+ // Don't display an error page if we're running layout tests, because
+ // DumpRenderTree doesn't.
+}
+
+void WebViewHost::didCommitProvisionalLoad(WebFrame* frame, bool isNewNavigation)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didCommitLoadForFrame\n", stdout);
+ }
+ updateForCommittedLoad(frame, isNewNavigation);
+}
+
+void WebViewHost::didClearWindowObject(WebFrame* frame)
+{
+ m_shell->bindJSObjectsToWindow(frame);
+}
+
+void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction)
+{
+ WebCString title8 = title.utf8();
+
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ printf(" - didReceiveTitle: %s\n", title8.data());
+ }
+
+ if (layoutTestController()->shouldDumpTitleChanges())
+ printf("TITLE CHANGED: %s\n", title8.data());
+
+ setPageTitle(title);
+ layoutTestController()->setTitleTextDirection(direction);
+}
+
+void WebViewHost::didFinishDocumentLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFinishDocumentLoadForFrame\n", stdout);
+ } else {
+ unsigned pendingUnloadEvents = frame->unloadListenerCount();
+ if (pendingUnloadEvents) {
+ printFrameDescription(frame);
+ printf(" - has %u onunload handler(s)\n", pendingUnloadEvents);
+ }
+ }
+}
+
+void WebViewHost::didHandleOnloadEvents(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didHandleOnloadEventsForFrame\n", stdout);
+ }
+}
+
+void WebViewHost::didFailLoad(WebFrame* frame, const WebURLError& error)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFailLoadWithError\n", stdout);
+ }
+ locationChangeDone(frame);
+}
+
+void WebViewHost::didFinishLoad(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didFinishLoadForFrame\n", stdout);
+ }
+ updateAddressBar(frame->view());
+ locationChangeDone(frame);
+}
+
+void WebViewHost::didNavigateWithinPage(WebFrame* frame, bool isNewNavigation)
+{
+ frame->dataSource()->setExtraData(m_pendingExtraData.leakPtr());
+
+ updateForCommittedLoad(frame, isNewNavigation);
+}
+
+void WebViewHost::didChangeLocationWithinPage(WebFrame* frame)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didChangeLocationWithinPageForFrame\n", stdout);
+ }
+}
+
+void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request)
+{
+ if (!m_shell->shouldDumpResourceLoadCallbacks())
+ return;
+ ASSERT(!m_resourceIdentifierMap.contains(identifier));
+ m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec()));
+}
+
+void WebViewHost::removeIdentifierForRequest(unsigned identifier)
+{
+ m_resourceIdentifierMap.remove(identifier);
+}
+
+void WebViewHost::willSendRequest(WebFrame*, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirectResponse)
+{
+ // Need to use GURL for host() and SchemeIs()
+ GURL url = request.url();
+ string requestURL = url.possibly_invalid_spec();
+
+ if (layoutTestController()->shouldDumpResourceLoadCallbacks()) {
+ GURL mainDocumentURL = request.firstPartyForCookies();
+ printResourceDescription(identifier);
+ printf(" - willSendRequest <NSURLRequest URL %s, main document URL %s,"
+ " http method %s> redirectResponse ",
+ descriptionSuitableForTestResult(requestURL).c_str(),
+ URLDescription(mainDocumentURL).c_str(),
+ request.httpMethod().utf8().data());
+ printResponseDescription(redirectResponse);
+ fputs("\n", stdout);
+ }
+
+ if (!redirectResponse.isNull() && m_blocksRedirects) {
+ fputs("Returning null for this redirect\n", stdout);
+ // To block the request, we set its URL to an empty one.
+ request.setURL(WebURL());
+ return;
+ }
+
+ if (m_requestReturnNull) {
+ // To block the request, we set its URL to an empty one.
+ request.setURL(WebURL());
+ return;
+ }
+
+ string host = url.host();
+ // 255.255.255.255 is used in some tests that expect to get back an error.
+ if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))
+ && host != "127.0.0.1"
+ && host != "255.255.255.255"
+ && host != "localhost"
+ && !m_shell->allowExternalPages()) {
+ printf("Blocked access to external URL %s\n", requestURL.c_str());
+
+ // To block the request, we set its URL to an empty one.
+ request.setURL(WebURL());
+ return;
+ }
+
+ HashSet<String>::const_iterator end = m_clearHeaders.end();
+ for (HashSet<String>::const_iterator header = m_clearHeaders.begin(); header != end; ++header)
+ request.clearHTTPHeaderField(WebString(header->characters(), header->length()));
+
+ // Set the new substituted URL.
+ request.setURL(webkit_support::RewriteLayoutTestsURL(request.url().spec()));
+}
+
+void WebViewHost::didReceiveResponse(WebFrame*, unsigned identifier, const WebURLResponse& response)
+{
+ if (m_shell->shouldDumpResourceLoadCallbacks()) {
+ printResourceDescription(identifier);
+ fputs(" - didReceiveResponse ", stdout);
+ printResponseDescription(response);
+ fputs("\n", stdout);
+ }
+ if (m_shell->shouldDumpResourceResponseMIMETypes()) {
+ GURL url = response.url();
+ WebString mimeType = response.mimeType();
+ printf("%s has MIME type %s\n",
+ url.ExtractFileName().c_str(),
+ // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream
+ mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data());
+ }
+}
+
+void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier)
+{
+ if (m_shell->shouldDumpResourceLoadCallbacks()) {
+ printResourceDescription(identifier);
+ fputs(" - didFinishLoading\n", stdout);
+ }
+ removeIdentifierForRequest(identifier);
+}
+
+void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error)
+{
+ if (m_shell->shouldDumpResourceLoadCallbacks()) {
+ printResourceDescription(identifier);
+ fputs(" - didFailLoadingWithError: ", stdout);
+ fputs(webkit_support::MakeURLErrorDescription(error).c_str(), stdout);
+ fputs("\n", stdout);
+ }
+ removeIdentifierForRequest(identifier);
+}
+
+void WebViewHost::didDisplayInsecureContent(WebFrame*)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks())
+ fputs("didDisplayInsecureContent\n", stdout);
+}
+
+void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin, const WebURL& insecureURL)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks())
+ fputs("didRunInsecureContent\n", stdout);
+}
+
+void WebViewHost::didDetectXSS(WebFrame*, const WebURL&, bool)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks())
+ fputs("didDetectXSS\n", stdout);
+}
+
+void WebViewHost::openFileSystem(WebFrame* frame, WebFileSystem::Type type, long long size, bool create, WebFileSystemCallbacks* callbacks)
+{
+ webkit_support::OpenFileSystem(frame, type, size, create, callbacks);
+}
+
+bool WebViewHost::willCheckAndDispatchMessageEvent(WebFrame* source, WebSecurityOrigin target, WebDOMMessageEvent event)
+{
+ if (m_shell->layoutTestController()->shouldInterceptPostMessage()) {
+ fputs("intercepted postMessage\n", stdout);
+ return true;
+ }
+
+ return false;
+}
+
+// Public functions -----------------------------------------------------------
+
+WebViewHost::WebViewHost(TestShell* shell)
+ : m_shell(shell)
+ , m_webWidget(0)
+ , m_lastRequestedTextCheckingCompletion(0)
+{
+ reset();
+}
+
+WebViewHost::~WebViewHost()
+{
+ // DevTools frontend page is supposed to be navigated only once and
+ // loading another URL in that Page is an error.
+ if (m_shell->devToolsWebView() != this) {
+ // Navigate to an empty page to fire all the destruction logic for the
+ // current page.
+ loadURLForFrame(GURL("about:blank"), WebString());
+ }
+
+ for (Vector<WebKit::WebWidget*>::iterator it = m_popupmenus.begin();
+ it < m_popupmenus.end(); ++it)
+ (*it)->close();
+
+ webWidget()->close();
+ if (m_inModalLoop)
+ webkit_support::QuitMessageLoop();
+}
+
+void WebViewHost::setWebWidget(WebKit::WebWidget* widget)
+{
+ m_webWidget = widget;
+ webView()->setSpellCheckClient(this);
+}
+
+WebView* WebViewHost::webView() const
+{
+ ASSERT(m_webWidget);
+ // DRT does not support popup widgets. So m_webWidget is always a WebView.
+ return static_cast<WebView*>(m_webWidget);
+}
+
+WebWidget* WebViewHost::webWidget() const
+{
+ ASSERT(m_webWidget);
+ return m_webWidget;
+}
+
+void WebViewHost::reset()
+{
+ m_policyDelegateEnabled = false;
+ m_policyDelegateIsPermissive = false;
+ m_policyDelegateShouldNotifyDone = false;
+ m_topLoadingFrame = 0;
+ m_pageId = -1;
+ m_lastPageIdUpdated = -1;
+ m_hasWindow = false;
+ m_inModalLoop = false;
+ m_smartInsertDeleteEnabled = true;
+ m_logConsoleOutput = true;
+#if OS(WINDOWS)
+ m_selectTrailingWhitespaceEnabled = true;
+#else
+ m_selectTrailingWhitespaceEnabled = false;
+#endif
+ m_blocksRedirects = false;
+ m_requestReturnNull = false;
+ m_isPainting = false;
+ m_canvas.clear();
+
+ m_navigationController = adoptPtr(new TestNavigationController(this));
+
+ m_pendingExtraData.clear();
+ m_resourceIdentifierMap.clear();
+ m_clearHeaders.clear();
+ m_editCommandName.clear();
+ m_editCommandValue.clear();
+
+ if (m_geolocationClientMock.get())
+ m_geolocationClientMock->resetMock();
+
+ if (m_speechInputControllerMock.get())
+ m_speechInputControllerMock->clearResults();
+
+ m_currentCursor = WebCursorInfo();
+ m_windowRect = WebRect();
+ m_paintRect = WebRect();
+
+ if (m_webWidget) {
+ webView()->mainFrame()->setName(WebString());
+ webView()->settings()->setMinimumTimerInterval(webkit_support::GetForegroundTabTimerInterval());
+ }
+}
+
+void WebViewHost::setSelectTrailingWhitespaceEnabled(bool enabled)
+{
+ m_selectTrailingWhitespaceEnabled = enabled;
+ // In upstream WebKit, smart insert/delete is mutually exclusive with select
+ // trailing whitespace, however, we allow both because Chromium on Windows
+ // allows both.
+}
+
+void WebViewHost::setSmartInsertDeleteEnabled(bool enabled)
+{
+ m_smartInsertDeleteEnabled = enabled;
+ // In upstream WebKit, smart insert/delete is mutually exclusive with select
+ // trailing whitespace, however, we allow both because Chromium on Windows
+ // allows both.
+}
+
+void WebViewHost::setLogConsoleOutput(bool enabled)
+{
+ m_logConsoleOutput = enabled;
+}
+
+void WebViewHost::setCustomPolicyDelegate(bool isCustom, bool isPermissive)
+{
+ m_policyDelegateEnabled = isCustom;
+ m_policyDelegateIsPermissive = isPermissive;
+}
+
+void WebViewHost::waitForPolicyDelegate()
+{
+ m_policyDelegateEnabled = true;
+ m_policyDelegateShouldNotifyDone = true;
+}
+
+void WebViewHost::setEditCommand(const string& name, const string& value)
+{
+ m_editCommandName = name;
+ m_editCommandValue = value;
+}
+
+void WebViewHost::clearEditCommand()
+{
+ m_editCommandName.clear();
+ m_editCommandValue.clear();
+}
+
+void WebViewHost::loadURLForFrame(const WebURL& url, const WebString& frameName)
+{
+ if (!url.isValid())
+ return;
+ TestShell::resizeWindowForTest(this, url);
+ navigationController()->loadEntry(TestNavigationEntry::create(-1, url, WebString(), frameName).get());
+}
+
+bool WebViewHost::navigate(const TestNavigationEntry& entry, bool reload)
+{
+ // Get the right target frame for the entry.
+ WebFrame* frame = webView()->mainFrame();
+ if (!entry.targetFrame().isEmpty())
+ frame = webView()->findFrameByName(entry.targetFrame());
+
+ // TODO(mpcomplete): should we clear the target frame, or should
+ // back/forward navigations maintain the target frame?
+
+ // A navigation resulting from loading a javascript URL should not be
+ // treated as a browser initiated event. Instead, we want it to look as if
+ // the page initiated any load resulting from JS execution.
+ if (!GURL(entry.URL()).SchemeIs("javascript"))
+ setPendingExtraData(adoptPtr(new TestShellExtraData(entry.pageID())));
+
+ // If we are reloading, then WebKit will use the state of the current page.
+ // Otherwise, we give it the state to navigate to.
+ if (reload) {
+ frame->reload(false);
+ } else if (!entry.contentState().isNull()) {
+ ASSERT(entry.pageID() != -1);
+ frame->loadHistoryItem(entry.contentState());
+ } else {
+ ASSERT(entry.pageID() == -1);
+ frame->loadRequest(WebURLRequest(entry.URL()));
+ }
+
+ // In case LoadRequest failed before DidCreateDataSource was called.
+ setPendingExtraData(nullptr);
+
+ // Restore focus to the main frame prior to loading new request.
+ // This makes sure that we don't have a focused iframe. Otherwise, that
+ // iframe would keep focus when the SetFocus called immediately after
+ // LoadRequest, thus making some tests fail (see http://b/issue?id=845337
+ // for more details).
+ webView()->setFocusedFrame(frame);
+ m_shell->setFocus(webView(), true);
+
+ return true;
+}
+
+// Private functions ----------------------------------------------------------
+
+LayoutTestController* WebViewHost::layoutTestController() const
+{
+ return m_shell->layoutTestController();
+}
+
+void WebViewHost::updateAddressBar(WebView* webView)
+{
+ WebFrame* mainFrame = webView->mainFrame();
+ WebDataSource* dataSource = mainFrame->dataSource();
+ if (!dataSource)
+ dataSource = mainFrame->provisionalDataSource();
+ if (!dataSource)
+ return;
+
+ setAddressBarURL(dataSource->request().url());
+}
+
+void WebViewHost::locationChangeDone(WebFrame* frame)
+{
+ if (frame != m_topLoadingFrame)
+ return;
+ m_topLoadingFrame = 0;
+ layoutTestController()->locationChangeDone();
+}
+
+void WebViewHost::updateForCommittedLoad(WebFrame* frame, bool isNewNavigation)
+{
+ // Code duplicated from RenderView::DidCommitLoadForFrame.
+ TestShellExtraData* extraData = static_cast<TestShellExtraData*>(frame->dataSource()->extraData());
+
+ if (isNewNavigation) {
+ // New navigation.
+ updateSessionHistory(frame);
+ m_pageId = nextPageID++;
+ } else if (extraData && extraData->pendingPageID != -1 && !extraData->requestCommitted) {
+ // This is a successful session history navigation!
+ updateSessionHistory(frame);
+ m_pageId = extraData->pendingPageID;
+ }
+
+ // Don't update session history multiple times.
+ if (extraData)
+ extraData->requestCommitted = true;
+
+ updateURL(frame);
+}
+
+void WebViewHost::updateURL(WebFrame* frame)
+{
+ WebDataSource* ds = frame->dataSource();
+ ASSERT(ds);
+ const WebURLRequest& request = ds->request();
+ RefPtr<TestNavigationEntry> entry(TestNavigationEntry::create());
+
+ // The referrer will be empty on https->http transitions. It
+ // would be nice if we could get the real referrer from somewhere.
+ entry->setPageID(m_pageId);
+ if (ds->hasUnreachableURL())
+ entry->setURL(ds->unreachableURL());
+ else
+ entry->setURL(request.url());
+
+ const WebHistoryItem& historyItem = frame->currentHistoryItem();
+ if (!historyItem.isNull())
+ entry->setContentState(historyItem);
+
+ navigationController()->didNavigateToEntry(entry.get());
+ updateAddressBar(frame->view());
+ m_lastPageIdUpdated = max(m_lastPageIdUpdated, m_pageId);
+}
+
+void WebViewHost::updateSessionHistory(WebFrame* frame)
+{
+ // If we have a valid page ID at this point, then it corresponds to the page
+ // we are navigating away from. Otherwise, this is the first navigation, so
+ // there is no past session history to record.
+ if (m_pageId == -1)
+ return;
+
+ TestNavigationEntry* entry = navigationController()->entryWithPageID(m_pageId);
+ if (!entry)
+ return;
+
+ const WebHistoryItem& historyItem = webView()->mainFrame()->previousHistoryItem();
+ if (historyItem.isNull())
+ return;
+
+ entry->setContentState(historyItem);
+}
+
+void WebViewHost::printFrameDescription(WebFrame* webframe)
+{
+ string name8 = webframe->name().utf8();
+ if (webframe == webView()->mainFrame()) {
+ if (!name8.length()) {
+ fputs("main frame", stdout);
+ return;
+ }
+ printf("main frame \"%s\"", name8.c_str());
+ return;
+ }
+ if (!name8.length()) {
+ fputs("frame (anonymous)", stdout);
+ return;
+ }
+ printf("frame \"%s\"", name8.c_str());
+}
+
+void WebViewHost::printFrameUserGestureStatus(WebFrame* webframe, const char* msg)
+{
+ bool isUserGesture = webframe->isProcessingUserGesture();
+ printf("Frame with user gesture \"%s\"%s", isUserGesture ? "true" : "false", msg);
+}
+
+void WebViewHost::printResourceDescription(unsigned identifier)
+{
+ ResourceMap::iterator it = m_resourceIdentifierMap.find(identifier);
+ printf("%s", it != m_resourceIdentifierMap.end() ? it->second.c_str() : "<unknown>");
+}
+
+void WebViewHost::setPendingExtraData(PassOwnPtr<TestShellExtraData> extraData)
+{
+ m_pendingExtraData = extraData;
+}
+
+void WebViewHost::setPageTitle(const WebString&)
+{
+ // Nothing to do in layout test.
+}
+
+void WebViewHost::setAddressBarURL(const WebURL&)
+{
+ // Nothing to do in layout test.
+}
+
+void WebViewHost::enterFullScreenNow()
+{
+ webView()->willEnterFullScreen();
+ webView()->didEnterFullScreen();
+}
+
+void WebViewHost::exitFullScreenNow()
+{
+ webView()->willExitFullScreen();
+ webView()->didExitFullScreen();
+}
+
+// Painting functions ---------------------------------------------------------
+
+void WebViewHost::updatePaintRect(const WebRect& rect)
+{
+ // m_paintRect = m_paintRect U rect
+ if (rect.isEmpty())
+ return;
+ if (m_paintRect.isEmpty()) {
+ m_paintRect = rect;
+ return;
+ }
+ int left = min(m_paintRect.x, rect.x);
+ int top = min(m_paintRect.y, rect.y);
+ int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width);
+ int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height);
+ m_paintRect = WebRect(left, top, right - left, bottom - top);
+}
+
+void WebViewHost::paintRect(const WebRect& rect)
+{
+ ASSERT(!m_isPainting);
+ ASSERT(canvas());
+ m_isPainting = true;
+#if USE(CG)
+ webWidget()->paint(skia::BeginPlatformPaint(canvas()), rect);
+ skia::EndPlatformPaint(canvas());
+#else
+ webWidget()->paint(canvas(), rect);
+#endif
+ m_isPainting = false;
+}
+
+void WebViewHost::paintInvalidatedRegion()
+{
+#if ENABLE(REQUEST_ANIMATION_FRAME)
+ webWidget()->animate(0.0);
+#endif
+ webWidget()->layout();
+ WebSize widgetSize = webWidget()->size();
+ WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
+
+ // Paint the canvas if necessary. Allow painting to generate extra rects
+ // for the first two calls. This is necessary because some WebCore rendering
+ // objects update their layout only when painted.
+ // Store the total area painted in total_paint. Then tell the gdk window
+ // to update that area after we're done painting it.
+ for (int i = 0; i < 3; ++i) {
+ // m_paintRect = intersect(m_paintRect , clientRect)
+ int left = max(m_paintRect.x, clientRect.x);
+ int top = max(m_paintRect.y, clientRect.y);
+ int right = min(m_paintRect.x + m_paintRect.width, clientRect.x + clientRect.width);
+ int bottom = min(m_paintRect.y + m_paintRect.height, clientRect.y + clientRect.height);
+ if (left >= right || top >= bottom)
+ m_paintRect = WebRect();
+ else
+ m_paintRect = WebRect(left, top, right - left, bottom - top);
+
+ if (m_paintRect.isEmpty())
+ continue;
+ WebRect rect(m_paintRect);
+ m_paintRect = WebRect();
+ paintRect(rect);
+ }
+ ASSERT(m_paintRect.isEmpty());
+}
+
+void WebViewHost::paintPagesWithBoundaries()
+{
+ ASSERT(!m_isPainting);
+ ASSERT(canvas());
+ m_isPainting = true;
+
+ WebSize pageSizeInPixels = webWidget()->size();
+ WebFrame* webFrame = webView()->mainFrame();
+
+ int pageCount = webFrame->printBegin(pageSizeInPixels);
+ int totalHeight = pageCount * (pageSizeInPixels.height + 1) - 1;
+
+ SkCanvas* testCanvas = skia::TryCreateBitmapCanvas(pageSizeInPixels.width, totalHeight, true);
+ if (testCanvas) {
+ discardBackingStore();
+ m_canvas = adoptPtr(testCanvas);
+ } else {
+ webFrame->printEnd();
+ return;
+ }
+
+#if WEBKIT_USING_SKIA
+ WebCanvas* webCanvas = canvas();
+#elif WEBKIT_USING_CG
+ const SkBitmap& canvasBitmap = canvas()->getDevice()->accessBitmap(false);
+ WebCanvas* webCanvas = CGBitmapContextCreate(canvasBitmap.getPixels(),
+ pageSizeInPixels.width, totalHeight,
+ 8, pageSizeInPixels.width * 4,
+ CGColorSpaceCreateDeviceRGB(),
+ kCGImageAlphaPremultipliedFirst |
+ kCGBitmapByteOrder32Host);
+ CGContextTranslateCTM(webCanvas, 0.0, totalHeight);
+ CGContextScaleCTM(webCanvas, 1.0, -1.0f);
+#endif
+
+ webFrame->printPagesWithBoundaries(webCanvas, pageSizeInPixels);
+ webFrame->printEnd();
+
+ m_isPainting = false;
+}
+
+SkCanvas* WebViewHost::canvas()
+{
+ if (m_canvas)
+ return m_canvas.get();
+ WebSize widgetSize = webWidget()->size();
+ resetScrollRect();
+ m_canvas = adoptPtr(skia::CreateBitmapCanvas(widgetSize.width, widgetSize.height, true));
+ return m_canvas.get();
+}
+
+void WebViewHost::resetScrollRect()
+{
+}
+
+void WebViewHost::discardBackingStore()
+{
+ m_canvas.clear();
+}
+
+// Paints the entire canvas a semi-transparent black (grayish). This is used
+// by the layout tests in fast/repaint. The alpha value matches upstream.
+void WebViewHost::displayRepaintMask()
+{
+ canvas()->drawARGB(167, 0, 0, 0);
+}
diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.h b/Tools/DumpRenderTree/chromium/WebViewHost.h
new file mode 100644
index 000000000..0bc4c38e6
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebViewHost.h
@@ -0,0 +1,368 @@
+/*
+ * 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 WebViewHost_h
+#define WebViewHost_h
+
+#include "MockSpellCheck.h"
+#include "Task.h"
+#include "TestNavigationController.h"
+#include "WebAccessibilityNotification.h"
+#include "WebCursorInfo.h"
+#include "WebFrameClient.h"
+#include "WebSpellCheckClient.h"
+#include "WebViewClient.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+class LayoutTestController;
+class SkCanvas;
+class TestShell;
+
+namespace WebKit {
+class WebFrame;
+class WebDeviceOrientationClient;
+class WebDeviceOrientationClientMock;
+class WebGeolocationClient;
+class WebGeolocationClientMock;
+class WebGeolocationServiceMock;
+class WebSharedWorkerClient;
+class WebSpeechInputController;
+class WebSpeechInputControllerMock;
+class WebSpeechInputListener;
+class WebURL;
+struct WebRect;
+struct WebURLError;
+struct WebWindowFeatures;
+}
+
+class WebViewHost : public WebKit::WebSpellCheckClient, public WebKit::WebViewClient, public WebKit::WebFrameClient, public NavigationHost {
+ public:
+ WebViewHost(TestShell*);
+ virtual ~WebViewHost();
+ void setWebWidget(WebKit::WebWidget*);
+ WebKit::WebView* webView() const;
+ WebKit::WebWidget* webWidget() const;
+ void reset();
+ void setSelectTrailingWhitespaceEnabled(bool);
+ void setSmartInsertDeleteEnabled(bool);
+ void setLogConsoleOutput(bool);
+ void waitForPolicyDelegate();
+ void setCustomPolicyDelegate(bool, bool);
+ WebKit::WebFrame* topLoadingFrame() { return m_topLoadingFrame; }
+ void setBlockRedirects(bool block) { m_blocksRedirects = block; }
+ void setRequestReturnNull(bool returnNull) { m_requestReturnNull = returnNull; }
+ void setEditCommand(const std::string& name, const std::string& value);
+ void clearEditCommand();
+ void setPendingExtraData(PassOwnPtr<TestShellExtraData>);
+
+ void paintRect(const WebKit::WebRect&);
+ void updatePaintRect(const WebKit::WebRect&);
+ void paintInvalidatedRegion();
+ void paintPagesWithBoundaries();
+ SkCanvas* canvas();
+ void displayRepaintMask();
+
+ void loadURLForFrame(const WebKit::WebURL&, const WebKit::WebString& frameName);
+ TestNavigationController* navigationController() { return m_navigationController.get(); }
+
+ void addClearHeader(const WTF::String& header) { m_clearHeaders.add(header); }
+ const HashSet<WTF::String>& clearHeaders() const { return m_clearHeaders; }
+ void closeWidget();
+
+ WebKit::WebContextMenuData* lastContextMenuData() const;
+ void clearContextMenuData();
+
+ WebKit::WebSpeechInputControllerMock* speechInputControllerMock() { return m_speechInputControllerMock.get(); }
+
+ // NavigationHost
+ virtual bool navigate(const TestNavigationEntry&, bool reload);
+
+ // WebKit::WebSpellCheckClient
+ virtual void spellCheck(const WebKit::WebString&, int& offset, int& length, WebKit::WebVector<WebKit::WebString>* optionalSuggestions);
+ virtual void requestCheckingOfText(const WebKit::WebString&, WebKit::WebTextCheckingCompletion*);
+ virtual WebKit::WebString autoCorrectWord(const WebKit::WebString&);
+
+ // WebKit::WebViewClient
+ virtual WebKit::WebView* createView(WebKit::WebFrame*, const WebKit::WebURLRequest&, const WebKit::WebWindowFeatures&, const WebKit::WebString&);
+ virtual WebKit::WebWidget* createPopupMenu(WebKit::WebPopupType);
+ virtual WebKit::WebWidget* createPopupMenu(const WebKit::WebPopupMenuInfo&);
+ virtual WebKit::WebStorageNamespace* createSessionStorageNamespace(unsigned quota);
+ virtual void didAddMessageToConsole(const WebKit::WebConsoleMessage&, const WebKit::WebString& sourceName, unsigned sourceLine);
+ virtual void didStartLoading();
+ virtual void didStopLoading();
+ virtual bool shouldBeginEditing(const WebKit::WebRange&);
+ virtual bool shouldEndEditing(const WebKit::WebRange&);
+ virtual bool shouldInsertNode(const WebKit::WebNode&, const WebKit::WebRange&, WebKit::WebEditingAction);
+ virtual bool shouldInsertText(const WebKit::WebString&, const WebKit::WebRange&, WebKit::WebEditingAction);
+ virtual bool shouldChangeSelectedRange(const WebKit::WebRange& from, const WebKit::WebRange& to, WebKit::WebTextAffinity, bool stillSelecting);
+ virtual bool shouldDeleteRange(const WebKit::WebRange&);
+ virtual bool shouldApplyStyle(const WebKit::WebString& style, const WebKit::WebRange&);
+ virtual bool isSmartInsertDeleteEnabled();
+ virtual bool isSelectTrailingWhitespaceEnabled();
+ virtual void didBeginEditing();
+ virtual void didChangeSelection(bool isSelectionEmpty);
+ virtual void didChangeContents();
+ virtual void didEndEditing();
+ virtual bool handleCurrentKeyboardEvent();
+ virtual void runModalAlertDialog(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual bool runModalConfirmDialog(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual bool runModalPromptDialog(WebKit::WebFrame*, const WebKit::WebString& message, const WebKit::WebString& defaultValue, WebKit::WebString* actualValue);
+ virtual bool runModalBeforeUnloadDialog(WebKit::WebFrame*, const WebKit::WebString&);
+ virtual void showContextMenu(WebKit::WebFrame*, const WebKit::WebContextMenuData&);
+ virtual void setStatusText(const WebKit::WebString&);
+ virtual void startDragging(const WebKit::WebDragData&, WebKit::WebDragOperationsMask, const WebKit::WebImage&, const WebKit::WebPoint&);
+ virtual void didUpdateLayout();
+ virtual void navigateBackForwardSoon(int offset);
+ virtual int historyBackListCount();
+ virtual int historyForwardListCount();
+ virtual void postAccessibilityNotification(const WebKit::WebAccessibilityObject&, WebKit::WebAccessibilityNotification);
+ virtual WebKit::WebNotificationPresenter* notificationPresenter();
+ virtual WebKit::WebGeolocationClient* geolocationClient();
+ virtual WebKit::WebSpeechInputController* speechInputController(WebKit::WebSpeechInputListener*);
+ virtual WebKit::WebDeviceOrientationClient* deviceOrientationClient();
+
+ // WebKit::WebWidgetClient
+ virtual void didInvalidateRect(const WebKit::WebRect&);
+ virtual void didScrollRect(int dx, int dy, const WebKit::WebRect&);
+ virtual void scheduleComposite();
+#if ENABLE(REQUEST_ANIMATION_FRAME)
+ virtual void scheduleAnimation();
+#endif
+ virtual void didFocus();
+ virtual void didBlur();
+ virtual void didChangeCursor(const WebKit::WebCursorInfo&);
+ virtual void closeWidgetSoon();
+ virtual void show(WebKit::WebNavigationPolicy);
+ virtual void runModal();
+ virtual bool enterFullScreen();
+ virtual void exitFullScreen();
+ virtual WebKit::WebRect windowRect();
+ virtual void setWindowRect(const WebKit::WebRect&);
+ virtual WebKit::WebRect rootWindowRect();
+ virtual WebKit::WebRect windowResizerRect();
+ virtual WebKit::WebScreenInfo screenInfo();
+
+ // WebKit::WebFrameClient
+ virtual WebKit::WebPlugin* createPlugin(WebKit::WebFrame*, const WebKit::WebPluginParams&);
+ virtual WebKit::WebWorker* createWorker(WebKit::WebFrame*, WebKit::WebSharedWorkerClient*);
+ virtual WebKit::WebMediaPlayer* createMediaPlayer(WebKit::WebFrame*, WebKit::WebMediaPlayerClient*);
+ virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost(WebKit::WebFrame*, WebKit::WebApplicationCacheHostClient*);
+ virtual void loadURLExternally(WebKit::WebFrame*, const WebKit::WebURLRequest&, WebKit::WebNavigationPolicy);
+ virtual void loadURLExternally(WebKit::WebFrame*, const WebKit::WebURLRequest&, WebKit::WebNavigationPolicy, const WebKit::WebString& downloadName);
+ virtual WebKit::WebNavigationPolicy decidePolicyForNavigation(
+ WebKit::WebFrame*, const WebKit::WebURLRequest&,
+ WebKit::WebNavigationType, const WebKit::WebNode&,
+ WebKit::WebNavigationPolicy, bool isRedirect);
+ virtual bool canHandleRequest(WebKit::WebFrame*, const WebKit::WebURLRequest&);
+ virtual WebKit::WebURLError cannotHandleRequestError(WebKit::WebFrame*, const WebKit::WebURLRequest&);
+ virtual WebKit::WebURLError cancelledError(WebKit::WebFrame*, const WebKit::WebURLRequest&);
+ virtual void unableToImplementPolicyWithError(WebKit::WebFrame*, const WebKit::WebURLError&);
+ virtual void willPerformClientRedirect(
+ WebKit::WebFrame*, const WebKit::WebURL& from, const WebKit::WebURL& to,
+ double interval, double fireTime);
+ virtual void didCancelClientRedirect(WebKit::WebFrame*);
+ virtual void didCreateDataSource(WebKit::WebFrame*, WebKit::WebDataSource*);
+ virtual void didStartProvisionalLoad(WebKit::WebFrame*);
+ virtual void didReceiveServerRedirectForProvisionalLoad(WebKit::WebFrame*);
+ virtual void didFailProvisionalLoad(WebKit::WebFrame*, const WebKit::WebURLError&);
+ virtual void didCommitProvisionalLoad(WebKit::WebFrame*, bool isNewNavigation);
+ virtual void didClearWindowObject(WebKit::WebFrame*);
+ virtual void didReceiveTitle(WebKit::WebFrame*, const WebKit::WebString&, WebKit::WebTextDirection);
+ virtual void didFinishDocumentLoad(WebKit::WebFrame*);
+ virtual void didHandleOnloadEvents(WebKit::WebFrame*);
+ virtual void didFailLoad(WebKit::WebFrame*, const WebKit::WebURLError&);
+ virtual void didFinishLoad(WebKit::WebFrame*);
+ virtual void didNavigateWithinPage(WebKit::WebFrame*, bool isNewNavigation);
+ virtual void didChangeLocationWithinPage(WebKit::WebFrame*);
+ virtual void assignIdentifierToRequest(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLRequest&);
+ virtual void removeIdentifierForRequest(unsigned identifier);
+ virtual void willSendRequest(WebKit::WebFrame*, unsigned identifier, WebKit::WebURLRequest&, const WebKit::WebURLResponse&);
+ virtual void didReceiveResponse(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLResponse&);
+ virtual void didFinishResourceLoad(WebKit::WebFrame*, unsigned identifier);
+ virtual void didFailResourceLoad(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLError&);
+ virtual void didDisplayInsecureContent(WebKit::WebFrame*);
+ virtual void didRunInsecureContent(WebKit::WebFrame*, const WebKit::WebSecurityOrigin&, const WebKit::WebURL&);
+ virtual void didDetectXSS(WebKit::WebFrame*, const WebKit::WebURL&, bool didBlockEntirePage);
+ virtual void openFileSystem(WebKit::WebFrame*, WebKit::WebFileSystem::Type, long long size, bool create, WebKit::WebFileSystemCallbacks*);
+ virtual bool willCheckAndDispatchMessageEvent(WebKit::WebFrame* source, WebKit::WebSecurityOrigin target, WebKit::WebDOMMessageEvent);
+
+ WebKit::WebDeviceOrientationClientMock* deviceOrientationClientMock();
+
+ // Spellcheck related helper APIs
+ MockSpellCheck* mockSpellCheck();
+ void finishLastTextCheck();
+
+ // Geolocation client mocks for LayoutTestController
+ WebKit::WebGeolocationClientMock* geolocationClientMock();
+
+ // Pending task list, Note taht the method is referred from MethodTask class.
+ TaskList* taskList() { return &m_taskList; }
+
+private:
+
+ class HostMethodTask : public MethodTask<WebViewHost> {
+ public:
+ typedef void (WebViewHost::*CallbackMethodType)();
+ HostMethodTask(WebViewHost* object, CallbackMethodType callback)
+ : MethodTask<WebViewHost>(object)
+ , m_callback(callback)
+ { }
+
+ virtual void runIfValid() { (m_object->*m_callback)(); }
+
+ private:
+ CallbackMethodType m_callback;
+ };
+
+ LayoutTestController* layoutTestController() const;
+
+ // Called the title of the page changes.
+ // Can be used to update the title of the window.
+ void setPageTitle(const WebKit::WebString&);
+
+ // Called when the URL of the page changes.
+ // Extracts the URL and forwards on to SetAddressBarURL().
+ void updateAddressBar(WebKit::WebView*);
+
+ // Called when the URL of the page changes.
+ // Should be used to update the text of the URL bar.
+ void setAddressBarURL(const WebKit::WebURL&);
+
+ void enterFullScreenNow();
+ void exitFullScreenNow();
+
+ // In the Mac code, this is called to trigger the end of a test after the
+ // page has finished loading. From here, we can generate the dump for the
+ // test.
+ void locationChangeDone(WebKit::WebFrame*);
+
+ void updateForCommittedLoad(WebKit::WebFrame*, bool isNewNavigation);
+ void updateURL(WebKit::WebFrame*);
+ void updateSessionHistory(WebKit::WebFrame*);
+
+ // Dumping a frame to the console.
+ void printFrameDescription(WebKit::WebFrame*);
+
+ // Dumping the user gesture status to the console.
+ void printFrameUserGestureStatus(WebKit::WebFrame*, const char*);
+
+ bool hasWindow() const { return m_hasWindow; }
+ void resetScrollRect();
+ void discardBackingStore();
+
+ // Causes navigation actions just printout the intended navigation instead
+ // of taking you to the page. This is used for cases like mailto, where you
+ // don't actually want to open the mail program.
+ bool m_policyDelegateEnabled;
+
+ // Toggles the behavior of the policy delegate. If true, then navigations
+ // will be allowed. Otherwise, they will be ignored (dropped).
+ bool m_policyDelegateIsPermissive;
+
+ // If true, the policy delegate will signal layout test completion.
+ bool m_policyDelegateShouldNotifyDone;
+
+ // Non-owning pointer. The WebViewHost instance is owned by this TestShell instance.
+ TestShell* m_shell;
+
+ // This delegate works for the following widget.
+ WebKit::WebWidget* m_webWidget;
+
+ // This is non-0 IFF a load is in progress.
+ WebKit::WebFrame* m_topLoadingFrame;
+
+ // For tracking session history. See RenderView.
+ int m_pageId;
+ int m_lastPageIdUpdated;
+
+ OwnPtr<TestShellExtraData> m_pendingExtraData;
+
+ // Maps resource identifiers to a descriptive string.
+ typedef HashMap<unsigned, std::string> ResourceMap;
+ ResourceMap m_resourceIdentifierMap;
+ void printResourceDescription(unsigned identifier);
+
+ WebKit::WebCursorInfo m_currentCursor;
+
+ bool m_hasWindow;
+ bool m_inModalLoop;
+ WebKit::WebRect m_windowRect;
+
+ // true if we want to enable smart insert/delete.
+ bool m_smartInsertDeleteEnabled;
+
+ // true if we want to enable selection of trailing whitespaces
+ bool m_selectTrailingWhitespaceEnabled;
+
+ // true if whatever is sent to the console should be logged to stdout.
+ bool m_logConsoleOutput;
+
+ // Set of headers to clear in willSendRequest.
+ HashSet<WTF::String> m_clearHeaders;
+
+ // true if we should block any redirects
+ bool m_blocksRedirects;
+
+ // true if we should block (set an empty request for) any requests
+ bool m_requestReturnNull;
+
+ // Edit command associated to the current keyboard event.
+ std::string m_editCommandName;
+ std::string m_editCommandValue;
+
+ // The mock spellchecker used in spellCheck().
+ MockSpellCheck m_spellcheck;
+
+ // Painting.
+ OwnPtr<SkCanvas> m_canvas;
+ WebKit::WebRect m_paintRect;
+ bool m_isPainting;
+
+ OwnPtr<WebKit::WebContextMenuData> m_lastContextMenuData;
+
+ // Geolocation
+ OwnPtr<WebKit::WebGeolocationClientMock> m_geolocationClientMock;
+
+ OwnPtr<WebKit::WebDeviceOrientationClientMock> m_deviceOrientationClientMock;
+ OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock;
+
+ OwnPtr<TestNavigationController> m_navigationController;
+
+ WebKit::WebString m_lastRequestedTextCheckString;
+ WebKit::WebTextCheckingCompletion* m_lastRequestedTextCheckingCompletion;
+
+ TaskList m_taskList;
+ Vector<WebKit::WebWidget*> m_popupmenus;
+};
+
+#endif // WebViewHost_h
diff --git a/Tools/DumpRenderTree/chromium/config.h b/Tools/DumpRenderTree/chromium/config.h
new file mode 100644
index 000000000..57b3a54fc
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/config.h
@@ -0,0 +1,53 @@
+/*
+ * 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 config_h
+#define config_h
+
+// To avoid confict of LOG in wtf/Assertions.h and LOG in base/logging.h,
+// skip base/loggin.h by defining BASE_LOGGING_H_ and define some macros
+// provided by base/logging.h.
+// FIXME: Remove this hack!
+#include <iostream>
+#define BASE_LOGGING_H_
+#define CHECK(condition) while (false && (condition)) std::cerr
+#define DCHECK(condition) while (false && (condition)) std::cerr
+#define DCHECK_EQ(a, b) while (false && (a) == (b)) std::cerr
+#define DCHECK_NE(a, b) while (false && (a) != (b)) std::cerr
+
+#include <wtf/Platform.h>
+#include <wtf/ExportMacros.h>
+
+#if OS(WINDOWS) && !COMPILER(GCC)
+// Allow 'this' to be used in base member initializer list.
+#pragma warning(disable : 4355)
+#endif
+
+#endif // config_h
diff --git a/Tools/DumpRenderTree/chromium/fonts.conf b/Tools/DumpRenderTree/chromium/fonts.conf
new file mode 100644
index 000000000..b75a9322e
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/fonts.conf
@@ -0,0 +1,229 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- /etc/fonts/fonts.conf file to configure system font access -->
+<fontconfig>
+ <match target="font">
+ <edit name="embeddedbitmap" mode="assign"><bool>false</bool></edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Times</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Times New Roman</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ </match>
+
+ <!-- Some layout tests specify Helvetica as a family and we need to make sure
+ that we don't fallback to Times New Roman for them -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Helvetica</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans-serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Times New Roman</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>mono</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Courier New</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>monospace</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Courier New</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Courier</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Courier New</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>cursive</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Comic Sans MS</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>fantasy</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Impact</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Monaco</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Times New Roman</string>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>NonAntiAliasedSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ <edit name="antialias" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SlightHintedGeorgia</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Georgia</string>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintslight</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>NonHintedSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Verdana</string>
+ </edit>
+ <!-- These deliberately contradict each other. The 'hinting' preference
+ should take priority -->
+ <edit name="hintstyle" mode="assign">
+ <const>hintfull</const>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>AutohintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ <edit name="autohint" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintmedium</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>HintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ <edit name="autohint" mode="assign">
+ <bool>false</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintmedium</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>FullAndAutoHintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ <edit name="autohint" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintfull</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SubpixelEnabledArial</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ <edit name="rgba" mode="assign">
+ <const>rgb</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SubpixelDisabledArial</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Arial</string>
+ </edit>
+ <edit name="rgba" mode="assign">
+ <const>none</const>
+ </edit>
+ </match>
+
+</fontconfig>
diff --git a/Tools/DumpRenderTree/config.h b/Tools/DumpRenderTree/config.h
new file mode 100644
index 000000000..d52cd84de
--- /dev/null
+++ b/Tools/DumpRenderTree/config.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#define Config_H
+
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
+#if defined(BUILDING_WITH_CMAKE)
+#include "cmakeconfig.h"
+#else
+#include "autotoolsconfig.h"
+#endif
+#endif
+
+#include <wtf/Platform.h>
+#include <wtf/ExportMacros.h>
+#if USE(JSC)
+#include <runtime/JSExportMacros.h>
+#endif
+
+// On MSW, wx headers need to be included before windows.h is.
+// The only way we can always ensure this is if we include wx here.
+#if PLATFORM(WX)
+#include <wx/defs.h>
+#endif
+
+
+#ifdef __cplusplus
+#undef new
+#undef delete
+#include <wtf/FastMalloc.h>
+#endif
+
+#if PLATFORM(MAC)
+#define WTF_USE_CF 1
+
+#if !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+#define BUILDING_ON_LEOPARD 1
+#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+#define BUILDING_ON_SNOW_LEOPARD 1
+#endif
+#endif // PLATFORM(MAC)
+
+#if OS(WINDOWS)
+// If we don't define these, they get defined in windef.h.
+// We want to use std::min and std::max
+#undef max
+#define max max
+#undef min
+#define min min
+#endif
+
+#if PLATFORM(WIN)
+#define WTF_USE_CF 1
+#if PLATFORM(WIN_CAIRO)
+#define WTF_USE_CAIRO 1
+#define WTF_USE_CURL 1
+#else
+#define WTF_USE_CG 1
+#define WTF_USE_CFNETWORK 1
+#endif
+
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+
+#undef WINVER
+#define WINVER 0x0500
+
+#undef _WINSOCKAPI_
+#define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h
+#endif // PLATFORM(WIN)
diff --git a/Tools/DumpRenderTree/efl/CMakeLists.txt b/Tools/DumpRenderTree/efl/CMakeLists.txt
new file mode 100644
index 000000000..c929191b2
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/CMakeLists.txt
@@ -0,0 +1,132 @@
+SET(DumpRenderTree_SOURCES
+ ${TOOLS_DIR}/DumpRenderTree/CyclicRedundancyCheck.cpp
+ ${TOOLS_DIR}/DumpRenderTree/GCController.cpp
+ ${TOOLS_DIR}/DumpRenderTree/LayoutTestController.cpp
+ ${TOOLS_DIR}/DumpRenderTree/PixelDumpSupport.cpp
+ ${TOOLS_DIR}/DumpRenderTree/WorkQueue.cpp
+ ${TOOLS_DIR}/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/DumpHistoryItem.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/DumpRenderTree.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/DumpRenderTreeChrome.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/DumpRenderTreeView.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/EventSender.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/FontManagement.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/GCControllerEfl.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/JSStringUtils.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/LayoutTestControllerEfl.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/PixelDumpSupportEfl.cpp
+ ${TOOLS_DIR}/DumpRenderTree/efl/WorkQueueItemEfl.cpp
+)
+
+SET(ImageDiff_SOURCES
+ ${TOOLS_DIR}/DumpRenderTree/efl/ImageDiff.cpp
+)
+
+SET(DumpRenderTree_LIBRARIES
+ ${JavaScriptCore_LIBRARY_NAME}
+ ${WebCore_LIBRARY_NAME}
+ ${WebKit_LIBRARY_NAME}
+ ${Cairo_LIBRARIES}
+ ${ECORE_X_LIBRARIES}
+ ${EDJE_LIBRARIES}
+ ${EFLDEPS_LIBRARIES}
+ ${EVAS_LIBRARIES}
+ ${LIBXML2_LIBRARIES}
+ ${LIBXSLT_LIBRARIES}
+ ${SQLITE_LIBRARIES}
+)
+
+SET(DumpRenderTree_LIBRARIES ${DumpRenderTree_LIBRARIES})
+SET(DumpRenderTree_INCLUDE_DIRECTORIES
+ "${WEBKIT_DIR}/efl/ewk"
+ ${WEBKIT_DIR}/efl
+ ${WEBCORE_DIR}
+ ${WEBCORE_DIR}/bridge
+ ${WEBCORE_DIR}/bridge/jsc
+ ${WEBCORE_DIR}/bindings
+ ${WEBCORE_DIR}/dom
+ ${WEBCORE_DIR}/editing
+ ${WEBCORE_DIR}/css
+ ${WEBCORE_DIR}/html
+ ${WEBCORE_DIR}/page
+ ${WEBCORE_DIR}/page/animation
+ ${WEBCORE_DIR}/platform
+ ${WEBCORE_DIR}/platform/animation
+ ${WEBCORE_DIR}/platform/text
+ ${WEBCORE_DIR}/platform/graphics
+ ${WEBCORE_DIR}/platform/graphics/cairo
+ ${WEBCORE_DIR}/platform/network
+ ${WEBCORE_DIR}/plugins
+ ${WEBCORE_DIR}/rendering
+ ${WEBCORE_DIR}/rendering/style
+ ${WEBCORE_DIR}/history
+ ${WEBCORE_DIR}/loader
+ ${WEBCORE_DIR}/loader/cache
+ ${WEBCORE_DIR}/loader/icon
+ ${JAVASCRIPTCORE_DIR}
+ ${JAVASCRIPTCORE_DIR}/API
+ ${JAVASCRIPTCORE_DIR}/assembler
+ ${JAVASCRIPTCORE_DIR}/dfg
+ ${JAVASCRIPTCORE_DIR}/heap
+ ${JAVASCRIPTCORE_DIR}/interpreter
+ ${JAVASCRIPTCORE_DIR}/jit
+ ${JAVASCRIPTCORE_DIR}/runtime
+ ${JAVASCRIPTCORE_DIR}/ForwardingHeaders
+ ${JAVASCRIPTCORE_DIR}/wtf
+ ${JAVASCRIPTCORE_DIR}/wtf/efl
+ ${TOOLS_DIR}/DumpRenderTree
+ ${TOOLS_DIR}/DumpRenderTree/cairo
+ ${TOOLS_DIR}/DumpRenderTree/efl
+ ${CMAKE_SOURCE_DIR}/Source
+ ${CMAKE_BINARY_DIR}
+ ${DERIVED_SOURCES_WEBCORE_DIR}
+ ${WEBCORE_DIR}/bindings/js
+ ${Cairo_INCLUDE_DIRS}
+ ${EDJE_INCLUDE_DIRS}
+ ${EFLDEPS_INCLUDE_DIRS}
+ ${EVAS_INCLUDE_DIRS}
+)
+
+SET(DumpRenderTree_LINK_FLAGS
+ ${ECORE_X_LDFLAGS}
+ ${EDJE_LDFLAGS}
+ ${EFLDEPS_LDFLAGS}
+ ${EVAS_LDFLAGS}
+)
+
+IF (ENABLE_GLIB_SUPPORT)
+ LIST(APPEND DumpRenderTree_INCLUDE_DIRECTORIES "${JAVASCRIPTCORE_DIR}/wtf/gobject")
+
+ LIST(APPEND DumpRenderTree_LIBRARIES
+ ${Gdk_LIBRARIES}
+ ${Glib_LIBRARIES}
+ ${Gthread_LIBRARIES}
+ )
+ENDIF ()
+
+IF (WTF_USE_SOUP)
+ LIST(APPEND DumpRenderTree_LIBRARIES ${LIBSOUP24_LIBRARIES})
+ LIST(APPEND DumpRenderTree_LINK_FLAGS ${LIBSOUP24_LDFLAGS})
+ LIST(APPEND DumpRenderTree_INCLUDE_DIRECTORIES ${LIBSOUP24_INCLUDE_DIRS} ${WEBCORE_DIR}/platform/network/soup)
+ENDIF ()
+
+IF (WTF_USE_CURL)
+ LIST(APPEND DumpRenderTree_LIBRARIES ${CURL_LIBRARIES})
+ LIST(APPEND DumpRenderTree_LINK_FLAGS ${CURL_LDFLAGS})
+ LIST(APPEND DumpRenderTree_INCLUDE_DIRECTORIES ${WEBCORE_DIR}/platform/network/curl)
+ENDIF ()
+
+ADD_DEFINITIONS(-DFONTS_CONF_DIR="${TOOLS_DIR}/DumpRenderTree/gtk/fonts"
+ -DDATA_DIR="${THEME_BINARY_DIR}")
+
+INCLUDE_DIRECTORIES(${DumpRenderTree_INCLUDE_DIRECTORIES})
+
+ADD_EXECUTABLE(Programs/DumpRenderTree ${DumpRenderTree_SOURCES})
+TARGET_LINK_LIBRARIES(Programs/DumpRenderTree ${DumpRenderTree_LIBRARIES})
+ADD_TARGET_PROPERTIES(Programs/DumpRenderTree LINK_FLAGS "${DumpRenderTree_LINK_FLAGS}")
+SET_TARGET_PROPERTIES(Programs/DumpRenderTree PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
+
+ADD_EXECUTABLE(Programs/ImageDiff ${ImageDiff_SOURCES})
+TARGET_LINK_LIBRARIES(Programs/ImageDiff ${DumpRenderTree_LIBRARIES})
+ADD_TARGET_PROPERTIES(Programs/ImageDiff LINK_FLAGS "${DumpRenderTree_LINK_FLAGS}")
+SET_TARGET_PROPERTIES(Programs/ImageDiff PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
diff --git a/Tools/DumpRenderTree/efl/DumpHistoryItem.cpp b/Tools/DumpRenderTree/efl/DumpHistoryItem.cpp
new file mode 100644
index 000000000..125b12847
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/DumpHistoryItem.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "DumpHistoryItem.h"
+
+#include "DumpRenderTree.h"
+#include "DumpRenderTreeChrome.h"
+#include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
+#include "ewk_private.h"
+#include <EWebKit.h>
+#include <algorithm>
+#include <cstdio>
+#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+Ewk_History_Item* prevTestBFItem = 0;
+const unsigned historyItemIndent = 8;
+
+static bool compareHistoryItemsByTarget(const Ewk_History_Item* item1, const Ewk_History_Item* item2)
+{
+ return WTF::codePointCompare(DumpRenderTreeSupportEfl::historyItemTarget(item1),
+ DumpRenderTreeSupportEfl::historyItemTarget(item2)) < 1;
+}
+
+static void dumpHistoryItem(const Ewk_History_Item* item, int indent, bool current)
+{
+ ASSERT(item);
+ int start = 0;
+ if (current) {
+ printf("curr->");
+ start = 6;
+ }
+ for (int i = start; i < indent; i++)
+ putchar(' ');
+
+ // normalize file URLs.
+ const char* uri = ewk_history_item_uri_get(item);
+ if (!strncasecmp(uri, "file://", sizeof("file://") - 1)) {
+ const char* pos = strstr(uri, "/LayoutTests/");
+ if (!pos)
+ return;
+
+ printf("(file test):%s", pos + sizeof("/LayoutTests/") - 1);
+ } else
+ printf("%s", uri);
+
+ const String target = DumpRenderTreeSupportEfl::historyItemTarget(item);
+ if (!target.isEmpty())
+ printf(" (in frame \"%s\")", target.utf8().data());
+ if (DumpRenderTreeSupportEfl::isTargetItem(item))
+ printf(" **nav target**");
+ putchar('\n');
+
+ HistoryItemChildrenVector children = DumpRenderTreeSupportEfl::childHistoryItems(item);
+
+ // Must sort to eliminate arbitrary result ordering which defeats reproducible testing.
+ std::stable_sort(children.begin(), children.end(), compareHistoryItemsByTarget);
+
+ const size_t size = children.size();
+ for (size_t i = 0; i < size; ++i)
+ dumpHistoryItem(children[i], indent + 4, false);
+}
+
+static void dumpBackForwardListForWebView(Evas_Object* view)
+{
+ printf("\n============== Back Forward List ==============\n");
+
+ const Ewk_History* history = ewk_view_history_get(view);
+
+ // Print out all items in the list after prevTestBFItem, which was from the previous test
+ // Gather items from the end of the list, the print them out from oldest to newest
+ Eina_List* itemsToPrint = 0;
+ void* historyItem;
+ Eina_List* backwardList = ewk_history_back_list_get(history);
+ EINA_LIST_FREE(backwardList, historyItem) {
+ if (historyItem == prevTestBFItem) {
+ eina_list_free(backwardList);
+ break;
+ }
+ itemsToPrint = eina_list_append(itemsToPrint, historyItem);
+ }
+
+ const Ewk_History_Item* currentItem = ewk_history_history_item_current_get(history);
+ if (currentItem)
+ itemsToPrint = eina_list_append(itemsToPrint, currentItem);
+
+ Eina_List* forwardList = ewk_history_forward_list_get(history);
+ EINA_LIST_FREE(forwardList, historyItem) {
+ ASSERT(historyItem != prevTestBFItem);
+ itemsToPrint = eina_list_append(itemsToPrint, historyItem);
+ }
+
+ EINA_LIST_FREE(itemsToPrint, historyItem) {
+ dumpHistoryItem(static_cast<Ewk_History_Item*>(historyItem), historyItemIndent, historyItem == currentItem);
+ ewk_history_item_free(static_cast<Ewk_History_Item*>(historyItem));
+ }
+
+ printf("===============================================\n");
+}
+
+void dumpBackForwardListForWebViews()
+{
+ // Dump the back forward list of the main WebView first
+ dumpBackForwardListForWebView(browser->mainView());
+
+ Vector<Evas_Object*>::const_iterator it = browser->extraViews().begin();
+ for (; it != browser->extraViews().end(); ++it)
+ dumpBackForwardListForWebView(*it);
+}
diff --git a/Tools/DumpRenderTree/efl/DumpHistoryItem.h b/Tools/DumpRenderTree/efl/DumpHistoryItem.h
new file mode 100644
index 000000000..ea8afeaaf
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/DumpHistoryItem.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 DumpHistoryItem_h
+#define DumpHistoryItem_h
+
+#include <Evas.h>
+
+void dumpBackForwardListForWebViews();
+
+#endif // DumpHistoryItem_h
diff --git a/Tools/DumpRenderTree/efl/DumpRenderTree.cpp b/Tools/DumpRenderTree/efl/DumpRenderTree.cpp
new file mode 100644
index 000000000..bb8f7d2d7
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/DumpRenderTree.cpp
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "DumpRenderTree.h"
+
+#include "DumpHistoryItem.h"
+#include "DumpRenderTreeChrome.h"
+#include "DumpRenderTreeView.h"
+#include "EventSender.h"
+#include "FontManagement.h"
+#include "LayoutTestController.h"
+#include "NotImplemented.h"
+#include "PixelDumpSupport.h"
+#include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
+#include "WorkQueue.h"
+#include "ewk_private.h"
+#include <EWebKit.h>
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <Ecore_File.h>
+#include <Edje.h>
+#include <Evas.h>
+#include <fontconfig/fontconfig.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <text/CString.h>
+#include <unistd.h>
+#include <wtf/OwnPtr.h>
+
+OwnPtr<DumpRenderTreeChrome> browser;
+Evas_Object* topLoadingFrame = 0;
+bool waitForPolicy = false;
+Ecore_Timer* waitToDumpWatchdog = 0;
+extern Ewk_History_Item* prevTestBFItem;
+
+// From the top-level DumpRenderTree.h
+RefPtr<LayoutTestController> gLayoutTestController;
+volatile bool done = false;
+
+static int dumpPixels = false;
+static int dumpTree = true;
+static int printSeparators = true;
+static int useX11Window = false;
+
+static String dumpFramesAsText(Evas_Object* frame)
+{
+ String result;
+
+ if (browser->mainFrame() != frame) {
+ result.append("\n--------\nFrame: '");
+ result.append(String::fromUTF8(ewk_frame_name_get(frame)));
+ result.append("'\n--------\n");
+ }
+
+ char* frameContents = ewk_frame_plain_text_get(frame);
+ result.append(String::fromUTF8(frameContents));
+ result.append("\n");
+ free(frameContents);
+
+ if (gLayoutTestController->dumpChildFramesAsText()) {
+ Eina_List* children = DumpRenderTreeSupportEfl::frameChildren(frame);
+ void* iterator;
+
+ EINA_LIST_FREE(children, iterator) {
+ Evas_Object* currentFrame = static_cast<Evas_Object*>(iterator);
+ String tempText(dumpFramesAsText(currentFrame));
+
+ if (tempText.isEmpty())
+ continue;
+
+ result.append(tempText);
+ }
+ }
+
+ return result;
+}
+
+static void dumpFrameScrollPosition(Evas_Object*)
+{
+ notImplemented();
+}
+
+static bool shouldLogFrameLoadDelegates(const String& pathOrURL)
+{
+ return pathOrURL.contains("loading/");
+}
+
+static bool shouldDumpAsText(const String& pathOrURL)
+{
+ return pathOrURL.contains("dumpAsText/");
+}
+
+static void sendPixelResultsEOF()
+{
+ puts("#EOF");
+ fflush(stdout);
+ fflush(stderr);
+}
+
+static void invalidateAnyPreviousWaitToDumpWatchdog()
+{
+ if (waitToDumpWatchdog) {
+ ecore_timer_del(waitToDumpWatchdog);
+ waitToDumpWatchdog = 0;
+ }
+ waitForPolicy = false;
+}
+
+static void onEcoreEvasResize(Ecore_Evas* ecoreEvas)
+{
+ int width, height;
+
+ ecore_evas_geometry_get(ecoreEvas, 0, 0, &width, &height);
+ evas_object_move(browser->mainView(), 0, 0);
+ evas_object_resize(browser->mainView(), width, height);
+}
+
+static void onCloseWindow(Ecore_Evas*)
+{
+ notImplemented();
+}
+
+static Eina_Bool useLongRunningServerMode(int argc, char** argv)
+{
+ return (argc == optind + 1 && !strcmp(argv[optind], "-"));
+}
+
+static bool parseCommandLineOptions(int argc, char** argv)
+{
+ static const option options[] = {
+ {"notree", no_argument, &dumpTree, false},
+ {"pixel-tests", no_argument, &dumpPixels, true},
+ {"tree", no_argument, &dumpTree, true},
+ {"gui", no_argument, &useX11Window, true},
+ {0, 0, 0, 0}
+ };
+
+ int option;
+ while ((option = getopt_long(argc, (char* const*)argv, "", options, 0)) != -1) {
+ switch (option) {
+ case '?':
+ case ':':
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static String getFinalTestURL(const String& testURL)
+{
+ const size_t hashSeparatorPos = testURL.find("'");
+ if (hashSeparatorPos != notFound)
+ return getFinalTestURL(testURL.left(hashSeparatorPos));
+
+ // Convert the path into a full file URL if it does not look
+ // like an HTTP/S URL (doesn't start with http:// or https://).
+ if (!testURL.startsWith("http://") && !testURL.startsWith("https://")) {
+ char* cFilePath = ecore_file_realpath(testURL.utf8().data());
+ const String filePath = String::fromUTF8(cFilePath);
+ free(cFilePath);
+
+ if (ecore_file_exists(filePath.utf8().data()))
+ return String("file://") + filePath;
+ }
+
+ return testURL;
+}
+
+static String getExpectedPixelHash(const String& testURL)
+{
+ const size_t hashSeparatorPos = testURL.find("'");
+ return (hashSeparatorPos != notFound) ? testURL.substring(hashSeparatorPos + 1) : String();
+}
+
+static void createLayoutTestController(const String& testURL, const String& expectedPixelHash)
+{
+ gLayoutTestController =
+ LayoutTestController::create(std::string(testURL.utf8().data()),
+ std::string(expectedPixelHash.utf8().data()));
+
+ topLoadingFrame = 0;
+ done = false;
+
+ gLayoutTestController->setIconDatabaseEnabled(false);
+
+ if (shouldLogFrameLoadDelegates(testURL))
+ gLayoutTestController->setDumpFrameLoadCallbacks(true);
+
+ gLayoutTestController->setDeveloperExtrasEnabled(true);
+
+ if (shouldDumpAsText(testURL)) {
+ gLayoutTestController->setDumpAsText(true);
+ gLayoutTestController->setGeneratePixelResults(false);
+ }
+}
+
+static void runTest(const char* cTestPathOrURL)
+{
+ const String testPathOrURL = String::fromUTF8(cTestPathOrURL);
+ ASSERT(!testPathOrURL.isEmpty());
+
+ const String testURL = getFinalTestURL(testPathOrURL);
+ const String expectedPixelHash = getExpectedPixelHash(testPathOrURL);
+
+ browser->resetDefaultsToConsistentValues();
+ createLayoutTestController(testURL, expectedPixelHash);
+
+ WorkQueue::shared()->clear();
+ WorkQueue::shared()->setFrozen(false);
+
+ const bool isSVGW3CTest = testURL.contains("svg/W3C-SVG-1.1");
+ const int width = isSVGW3CTest ? 480 : LayoutTestController::maxViewWidth;
+ const int height = isSVGW3CTest ? 360 : LayoutTestController::maxViewHeight;
+ evas_object_resize(browser->mainView(), width, height);
+
+ if (prevTestBFItem)
+ ewk_history_item_free(prevTestBFItem);
+ const Ewk_History* history = ewk_view_history_get(browser->mainView());
+ prevTestBFItem = ewk_history_history_item_current_get(history);
+
+ evas_object_focus_set(browser->mainView(), EINA_TRUE);
+ ewk_view_uri_set(browser->mainView(), testURL.utf8().data());
+
+ ecore_main_loop_begin();
+
+ gLayoutTestController->closeWebInspector();
+ gLayoutTestController->setDeveloperExtrasEnabled(false);
+
+ ewk_view_uri_set(browser->mainView(), "about:blank");
+
+ gLayoutTestController.clear();
+ sendPixelResultsEOF();
+}
+
+static void runTestingServerLoop()
+{
+ char filename[PATH_MAX];
+
+ while (fgets(filename, sizeof(filename), stdin)) {
+ char* newLine = strrchr(filename, '\n');
+ if (newLine)
+ *newLine = '\0';
+
+ if (filename[0] != '\0')
+ runTest(filename);
+ }
+}
+
+static void adjustOutputTypeByMimeType(const Evas_Object* frame)
+{
+ const String responseMimeType(DumpRenderTreeSupportEfl::responseMimeType(frame));
+ if (responseMimeType == "text/plain") {
+ gLayoutTestController->setDumpAsText(true);
+ gLayoutTestController->setGeneratePixelResults(false);
+ }
+}
+
+static void dumpFrameContentsAsText(Evas_Object* frame)
+{
+ String result;
+ if (gLayoutTestController->dumpAsText())
+ result = dumpFramesAsText(frame);
+ else
+ result = DumpRenderTreeSupportEfl::renderTreeDump(frame);
+
+ printf("%s", result.utf8().data());
+}
+
+static bool shouldDumpFrameScrollPosition()
+{
+ return gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive();
+}
+
+static bool shouldDumpPixelsAndCompareWithExpected()
+{
+ return dumpPixels && gLayoutTestController->generatePixelResults() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive();
+}
+
+static bool shouldDumpBackForwardList()
+{
+ return gLayoutTestController->dumpBackForwardList();
+}
+
+static bool initEfl()
+{
+ if (!ecore_evas_init())
+ return false;
+ if (!ecore_file_init()) {
+ ecore_evas_shutdown();
+ return false;
+ }
+ if (!edje_init()) {
+ ecore_file_shutdown();
+ ecore_evas_shutdown();
+ return false;
+ }
+ if (!ewk_init()) {
+ edje_shutdown();
+ ecore_file_shutdown();
+ ecore_evas_shutdown();
+ return false;
+ }
+
+ return true;
+}
+
+static void shutdownEfl()
+{
+ ewk_shutdown();
+ edje_shutdown();
+ ecore_file_shutdown();
+ ecore_evas_shutdown();
+}
+
+void displayWebView()
+{
+ notImplemented();
+}
+
+void dump()
+{
+ Evas_Object* frame = browser->mainFrame();
+
+ invalidateAnyPreviousWaitToDumpWatchdog();
+
+ if (dumpTree) {
+ adjustOutputTypeByMimeType(frame);
+ dumpFrameContentsAsText(frame);
+
+ if (shouldDumpFrameScrollPosition())
+ dumpFrameScrollPosition(frame);
+
+ if (shouldDumpBackForwardList())
+ dumpBackForwardListForWebViews();
+
+ if (printSeparators) {
+ puts("#EOF");
+ fputs("#EOF\n", stderr);
+ fflush(stdout);
+ fflush(stderr);
+ }
+ }
+
+ if (shouldDumpPixelsAndCompareWithExpected())
+ dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash());
+
+ done = true;
+ ecore_main_loop_quit();
+}
+
+static Ecore_Evas* initEcoreEvas()
+{
+ Ecore_Evas* ecoreEvas = useX11Window ? ecore_evas_new(0, 0, 0, 800, 600, 0) : ecore_evas_buffer_new(800, 600);
+ if (!ecoreEvas) {
+ shutdownEfl();
+ exit(EXIT_FAILURE);
+ }
+
+ ecore_evas_title_set(ecoreEvas, "EFL DumpRenderTree");
+ ecore_evas_callback_resize_set(ecoreEvas, onEcoreEvasResize);
+ ecore_evas_callback_delete_request_set(ecoreEvas, onCloseWindow);
+ ecore_evas_show(ecoreEvas);
+
+ return ecoreEvas;
+}
+
+int main(int argc, char** argv)
+{
+ if (!parseCommandLineOptions(argc, argv))
+ return EXIT_FAILURE;
+
+ if (!initEfl())
+ return EXIT_FAILURE;
+
+ OwnPtr<Ecore_Evas> ecoreEvas = adoptPtr(initEcoreEvas());
+ browser = DumpRenderTreeChrome::create(ecore_evas_get(ecoreEvas.get()));
+ addFontsToEnvironment();
+
+ if (useLongRunningServerMode(argc, argv)) {
+ printSeparators = true;
+ runTestingServerLoop();
+ } else {
+ printSeparators = (optind < argc - 1 || (dumpPixels && dumpTree));
+ for (int i = optind; i != argc; ++i)
+ runTest(argv[i]);
+ }
+
+ ecoreEvas.clear();
+
+ shutdownEfl();
+ return EXIT_SUCCESS;
+}
diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp
new file mode 100644
index 000000000..ce7a00d9f
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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
+ * HOLDERS OR ITS 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 "DumpRenderTreeChrome.h"
+
+#include "DumpRenderTree.h"
+#include "DumpRenderTreeView.h"
+#include "EventSender.h"
+#include "GCController.h"
+#include "LayoutTestController.h"
+#include "NotImplemented.h"
+#include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
+#include "WorkQueue.h"
+#include "ewk_private.h" // FIXME: create some WebCoreSupport/DumpRenderTree.cpp instead
+
+#include <EWebKit.h>
+#include <Ecore.h>
+#include <Eina.h>
+#include <Evas.h>
+#include <cstdio>
+#include <wtf/NotFound.h>
+
+PassOwnPtr<DumpRenderTreeChrome> DumpRenderTreeChrome::create(Evas* evas)
+{
+ OwnPtr<DumpRenderTreeChrome> chrome = adoptPtr(new DumpRenderTreeChrome(evas));
+
+ if (!chrome->initialize())
+ return nullptr;
+
+ return chrome.release();
+}
+
+DumpRenderTreeChrome::DumpRenderTreeChrome(Evas* evas)
+ : m_mainView(0)
+ , m_mainFrame(0)
+ , m_evas(evas)
+ , m_gcController(adoptPtr(new GCController))
+{
+}
+
+DumpRenderTreeChrome::~DumpRenderTreeChrome()
+{
+}
+
+Evas_Object* DumpRenderTreeChrome::createNewWindow()
+{
+ Evas_Object* newView = createView();
+
+ ewk_view_setting_scripts_can_open_windows_set(newView, EINA_TRUE);
+ ewk_view_setting_scripts_can_close_windows_set(newView, EINA_TRUE);
+
+ m_extraViews.append(newView);
+
+ return newView;
+}
+
+Evas_Object* DumpRenderTreeChrome::createView() const
+{
+ Evas_Object* view = drtViewAdd(m_evas);
+ if (!view)
+ return 0;
+
+ ewk_view_theme_set(view, DATA_DIR"/default.edj");
+
+ evas_object_smart_callback_add(view, "load,started", onLoadStarted, 0);
+ evas_object_smart_callback_add(view, "load,finished", onLoadFinished, 0);
+ evas_object_smart_callback_add(view, "title,changed", onTitleChanged, 0);
+ evas_object_smart_callback_add(view, "window,object,cleared", onWindowObjectCleared, m_gcController.get());
+ evas_object_smart_callback_add(view, "statusbar,text,set", onStatusbarTextSet, 0);
+ evas_object_smart_callback_add(view, "load,document,finished", onDocumentLoadFinished, 0);
+
+ return view;
+}
+
+void DumpRenderTreeChrome::removeWindow(Evas_Object* view)
+{
+ const size_t pos = m_extraViews.find(view);
+
+ if (pos == notFound)
+ return;
+
+ m_extraViews.remove(pos);
+ evas_object_del(view);
+}
+
+bool DumpRenderTreeChrome::initialize()
+{
+ DumpRenderTreeSupportEfl::setMockScrollbarsEnabled(true);
+
+ m_mainView = createView();
+ if (!m_mainView)
+ return false;
+
+ ewk_view_theme_set(m_mainView, DATA_DIR"/default.edj");
+
+ evas_object_name_set(m_mainView, "m_mainView");
+ evas_object_move(m_mainView, 0, 0);
+ evas_object_resize(m_mainView, 800, 600);
+ evas_object_layer_set(m_mainView, EVAS_LAYER_MAX);
+ evas_object_show(m_mainView);
+ evas_object_focus_set(m_mainView, EINA_TRUE);
+
+ m_mainFrame = ewk_view_frame_main_get(m_mainView);
+
+ return true;
+}
+
+Vector<Evas_Object*> DumpRenderTreeChrome::extraViews() const
+{
+ return m_extraViews;
+}
+
+Evas_Object* DumpRenderTreeChrome::mainFrame() const
+{
+ return m_mainFrame;
+}
+
+Evas_Object* DumpRenderTreeChrome::mainView() const
+{
+ return m_mainView;
+}
+
+void DumpRenderTreeChrome::resetDefaultsToConsistentValues()
+{
+ Vector<Evas_Object*>::iterator it = m_extraViews.begin();
+ for (; it != m_extraViews.end(); ++it)
+ evas_object_del(*it);
+ m_extraViews.clear();
+
+ ewk_settings_icon_database_clear();
+ ewk_settings_icon_database_path_set(0);
+
+ ewk_view_setting_private_browsing_set(mainView(), EINA_FALSE);
+ ewk_view_setting_spatial_navigation_set(mainView(), EINA_FALSE);
+ ewk_view_setting_enable_frame_flattening_set(mainView(), EINA_FALSE);
+ ewk_view_setting_application_cache_set(mainView(), EINA_TRUE);
+ ewk_view_setting_enable_scripts_set(mainView(), EINA_TRUE);
+ ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_STANDARD, "Times");
+ ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_MONOSPACE, "Courier");
+ ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_SERIF, "Times");
+ ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_SANS_SERIF, "Helvetica");
+ ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_CURSIVE, "cursive");
+ ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_FANTASY, "fantasy");
+ ewk_view_setting_font_default_size_set(mainView(), 16);
+ ewk_view_setting_font_monospace_size_set(mainView(), 13);
+ ewk_view_setting_font_minimum_size_set(mainView(), 0);
+ ewk_view_setting_caret_browsing_set(mainView(), EINA_FALSE);
+ ewk_view_setting_page_cache_set(mainView(), EINA_FALSE);
+ ewk_view_setting_enable_auto_resize_window_set(mainView(), EINA_TRUE);
+ ewk_view_setting_enable_plugins_set(mainView(), EINA_TRUE);
+ ewk_view_setting_scripts_can_open_windows_set(mainView(), EINA_TRUE);
+ ewk_view_setting_scripts_can_close_windows_set(mainView(), EINA_TRUE);
+
+ ewk_view_zoom_set(mainView(), 1.0, 0, 0);
+ ewk_view_scale_set(mainView(), 1.0, 0, 0);
+
+ ewk_history_clear(ewk_view_history_get(mainView()));
+
+ ewk_cookies_clear();
+ ewk_cookies_policy_set(EWK_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
+
+ DumpRenderTreeSupportEfl::clearFrameName(mainFrame());
+ DumpRenderTreeSupportEfl::clearOpener(mainFrame());
+}
+
+// Smart Callbacks
+// ---------------
+
+void DumpRenderTreeChrome::onWindowObjectCleared(void* userData, Evas_Object*, void* eventInfo)
+{
+ Ewk_Window_Object_Cleared_Event* objectClearedInfo = static_cast<Ewk_Window_Object_Cleared_Event*>(eventInfo);
+ JSValueRef exception = 0;
+ ASSERT(gLayoutTestController);
+
+ GCController* gcController = static_cast<GCController*>(userData);
+ ASSERT(gcController);
+
+ gLayoutTestController->makeWindowObject(objectClearedInfo->context, objectClearedInfo->windowObject, &exception);
+ ASSERT(!exception);
+
+ gcController->makeWindowObject(objectClearedInfo->context, objectClearedInfo->windowObject, &exception);
+ ASSERT(!exception);
+
+ JSRetainPtr<JSStringRef> controllerName(JSStringCreateWithUTF8CString("eventSender"));
+ JSObjectSetProperty(objectClearedInfo->context, objectClearedInfo->windowObject,
+ controllerName.get(),
+ makeEventSender(objectClearedInfo->context, !DumpRenderTreeSupportEfl::frameParent(objectClearedInfo->frame)),
+ kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
+}
+
+void DumpRenderTreeChrome::onLoadStarted(void*, Evas_Object* view, void*)
+{
+ // FIXME: we actually need the frame related to this event
+ Evas_Object* frame = ewk_view_frame_main_get(view);
+
+ // Make sure we only set this once per test. If it gets cleared, and then set again, we might
+ // end up doing two dumps for one test.
+ if (!topLoadingFrame && !done)
+ topLoadingFrame = frame;
+}
+
+Eina_Bool DumpRenderTreeChrome::processWork(void* data)
+{
+ Evas_Object* frame = static_cast<Evas_Object*>(data);
+
+ if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump())
+ dump();
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+void DumpRenderTreeChrome::onLoadFinished(void*, Evas_Object* view, void*)
+{
+ // FIXME: we actually need the frame related to this event
+ Evas_Object* frame = ewk_view_frame_main_get(view);
+
+ if (topLoadingFrame != frame)
+ return;
+
+ topLoadingFrame = 0;
+
+ WorkQueue::shared()->setFrozen(true);
+ if (gLayoutTestController->waitToDump())
+ return;
+
+ if (WorkQueue::shared()->count())
+ ecore_idler_add(processWork, frame);
+ else
+ dump();
+}
+
+void DumpRenderTreeChrome::onStatusbarTextSet(void*, Evas_Object*, void* eventInfo)
+{
+ if (!gLayoutTestController->dumpStatusCallbacks())
+ return;
+
+ const char* statusbarText = static_cast<const char*>(eventInfo);
+ printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", statusbarText);
+}
+
+void DumpRenderTreeChrome::onTitleChanged(void*, Evas_Object*, void*)
+{
+ notImplemented();
+}
+
+void DumpRenderTreeChrome::onDocumentLoadFinished(void*, Evas_Object*, void* eventInfo)
+{
+ const Evas_Object* frame = static_cast<Evas_Object*>(eventInfo);
+ const String frameName(DumpRenderTreeSupportEfl::suitableDRTFrameName(frame));
+
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didFinishDocumentLoadForFrame\n", frameName.utf8().data());
+ else if (!done) {
+ const unsigned pendingFrameUnloadEvents = DumpRenderTreeSupportEfl::pendingUnloadEventCount(frame);
+ if (pendingFrameUnloadEvents)
+ printf("%s - has %u onunload handler(s)\n", frameName.utf8().data(), pendingFrameUnloadEvents);
+ }
+}
diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h
new file mode 100644
index 000000000..4ea991806
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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
+ * HOLDERS OR ITS 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 DumpRenderTreeChrome_h
+#define DumpRenderTreeChrome_h
+
+#include "GCController.h"
+
+#include <Eina.h>
+#include <Evas.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+class DumpRenderTreeChrome {
+public:
+ ~DumpRenderTreeChrome();
+
+ static PassOwnPtr<DumpRenderTreeChrome> create(Evas*);
+
+ Evas_Object* createNewWindow();
+ void removeWindow(Evas_Object*);
+
+ Vector<Evas_Object*> extraViews() const;
+ Evas_Object* mainFrame() const;
+ Evas_Object* mainView() const;
+
+ void resetDefaultsToConsistentValues();
+
+private:
+ DumpRenderTreeChrome(Evas*);
+
+ Evas_Object* createView() const;
+ bool initialize();
+
+ Evas_Object* m_mainFrame;
+ Evas_Object* m_mainView;
+ Evas* m_evas;
+ OwnPtr<GCController> m_gcController;
+ Vector<Evas_Object*> m_extraViews;
+
+ // Smart callbacks
+ static void onWindowObjectCleared(void*, Evas_Object*, void*);
+ static void onLoadStarted(void*, Evas_Object*, void*);
+
+ static Eina_Bool processWork(void*);
+
+ static void onLoadFinished(void*, Evas_Object*, void*);
+
+ static void onStatusbarTextSet(void*, Evas_Object*, void*);
+
+ static void onTitleChanged(void*, Evas_Object*, void*);
+
+ static void onDocumentLoadFinished(void*, Evas_Object*, void*);
+};
+
+#endif // DumpRenderTreeChrome_h
diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h b/Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h
new file mode 100644
index 000000000..43812b19b
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Red istributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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
+ * HOLDERS OR ITS 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 DumpRenderTreeEfl_h
+#define DumpRenderTreeEfl_h
+
+#include <Ecore.h>
+#include <Evas.h>
+#include <wtf/OwnPtr.h>
+
+class DumpRenderTreeChrome;
+
+extern OwnPtr<DumpRenderTreeChrome> browser;
+extern Evas_Object* topLoadingFrame;
+extern bool waitForPolicy;
+extern Ecore_Timer* waitToDumpWatchdog;
+
+#endif /* DumpRenderTreeEfl_h */
diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp b/Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp
new file mode 100644
index 000000000..938c3fbdb
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Red istributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "DumpRenderTreeView.h"
+
+#include "DumpRenderTree.h"
+#include "DumpRenderTreeChrome.h"
+#include "LayoutTestController.h"
+#include <EWebKit.h>
+#include <Ecore.h>
+#include <Eina.h>
+#include <Evas.h>
+#include <cstdio>
+#include <cstdlib>
+
+using namespace std;
+
+static Ewk_View_Smart_Class gParentSmartClass = EWK_VIEW_SMART_CLASS_INIT_NULL;
+
+static void onConsoleMessage(Ewk_View_Smart_Data*, const char* message, unsigned int lineNumber, const char*)
+{
+ printf("CONSOLE MESSAGE: line %u: %s\n", lineNumber, message);
+}
+
+static void onJavaScriptAlert(Ewk_View_Smart_Data*, Evas_Object*, const char* message)
+{
+ printf("ALERT: %s\n", message);
+}
+
+static Eina_Bool onJavaScriptConfirm(Ewk_View_Smart_Data*, Evas_Object*, const char* message)
+{
+ printf("CONFIRM: %s\n", message);
+ return EINA_TRUE;
+}
+
+static Eina_Bool onJavaScriptPrompt(Ewk_View_Smart_Data*, Evas_Object*, const char* message, const char* defaultValue, char** value)
+{
+ printf("PROMPT: %s, default text: %s\n", message, defaultValue);
+ *value = strdup(defaultValue);
+ return EINA_TRUE;
+}
+
+static Evas_Object* onWindowCreate(Ewk_View_Smart_Data*, Eina_Bool, const Ewk_Window_Features*)
+{
+ return gLayoutTestController->canOpenWindows() ? browser->createNewWindow() : 0;
+}
+
+static Eina_Bool onWindowCloseDelayed(void* data)
+{
+ Evas_Object* view = static_cast<Evas_Object*>(data);
+ browser->removeWindow(view);
+ return EINA_FALSE;
+}
+
+static void onWindowClose(Ewk_View_Smart_Data* smartData)
+{
+ Evas_Object* view = smartData->self;
+ ecore_idler_add(onWindowCloseDelayed, view);
+}
+
+static bool shouldUseSingleBackingStore()
+{
+ const char* useSingleBackingStore = getenv("DRT_USE_SINGLE_BACKING_STORE");
+ return useSingleBackingStore && *useSingleBackingStore == '1';
+}
+
+static bool chooseAndInitializeAppropriateSmartClass(Ewk_View_Smart_Class* api)
+{
+ return shouldUseSingleBackingStore() ? ewk_view_single_smart_set(api) : ewk_view_tiled_smart_set(api);
+}
+
+Evas_Object* drtViewAdd(Evas* evas)
+{
+ static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("DRT_View");
+
+ if (!chooseAndInitializeAppropriateSmartClass(&api))
+ return 0;
+
+ if (EINA_UNLIKELY(!gParentSmartClass.sc.add))
+ ewk_view_base_smart_set(&gParentSmartClass);
+
+ api.add_console_message = onConsoleMessage;
+ api.run_javascript_alert = onJavaScriptAlert;
+ api.run_javascript_confirm = onJavaScriptConfirm;
+ api.run_javascript_prompt = onJavaScriptPrompt;
+ api.window_create = onWindowCreate;
+ api.window_close = onWindowClose;
+
+ return evas_object_smart_add(evas, evas_smart_class_new(&api.sc));
+}
diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeView.h b/Tools/DumpRenderTree/efl/DumpRenderTreeView.h
new file mode 100644
index 000000000..72ddab56d
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/DumpRenderTreeView.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Red istributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 DumpRenderTreeView_h
+#define DumpRenderTreeView_h
+
+#include <Evas.h>
+
+Evas_Object* drtViewAdd(Evas*);
+
+#endif // DumpRenderTreeView_h
diff --git a/Tools/DumpRenderTree/efl/EventSender.cpp b/Tools/DumpRenderTree/efl/EventSender.cpp
new file mode 100644
index 000000000..89130f00a
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/EventSender.cpp
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2010 Igalia S.L.
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "EventSender.h"
+
+#include "DumpRenderTree.h"
+#include "DumpRenderTreeChrome.h"
+#include "JSStringUtils.h"
+#include "NotImplemented.h"
+#include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
+#include "ewk_private.h"
+#include <EWebKit.h>
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <JavaScriptCore/OpaqueJSString.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/Platform.h>
+#include <wtf/text/CString.h>
+
+static bool gDragMode;
+static int gTimeOffset = 0;
+
+static int gLastMousePositionX;
+static int gLastMousePositionY;
+static int gLastClickPositionX;
+static int gLastClickPositionY;
+static int gLastClickTimeOffset;
+static int gLastClickButton;
+static int gButtonCurrentlyDown;
+static int gClickCount;
+
+static const float zoomMultiplierRatio = 1.2f;
+
+// Key event location code defined in DOM Level 3.
+enum KeyLocationCode {
+ DomKeyLocationStandard,
+ DomKeyLocationLeft,
+ DomKeyLocationRight,
+ DomKeyLocationNumpad
+};
+
+enum EvasKeyModifier {
+ EvasKeyModifierNone = 0,
+ EvasKeyModifierControl = 1 << 0,
+ EvasKeyModifierShift = 1 << 1,
+ EvasKeyModifierAlt = 1 << 2,
+ EvasKeyModifierMeta = 1 << 3
+};
+
+enum EvasMouseButton {
+ EvasMouseButtonNone,
+ EvasMouseButtonLeft,
+ EvasMouseButtonMiddle,
+ EvasMouseButtonRight
+};
+
+enum EvasMouseEvent {
+ EvasMouseEventNone = 0,
+ EvasMouseEventDown = 1 << 0,
+ EvasMouseEventUp = 1 << 1,
+ EvasMouseEventMove = 1 << 2,
+ EvasMouseEventScrollUp = 1 << 3,
+ EvasMouseEventScrollDown = 1 << 4,
+ EvasMouseEventScrollLeft = 1 << 5,
+ EvasMouseEventScrollRight = 1 << 6,
+ EvasMouseEventClick = EvasMouseEventMove | EvasMouseEventDown | EvasMouseEventUp,
+};
+
+static void setEvasModifiers(Evas* evas, EvasKeyModifier modifiers)
+{
+ static const char* modifierNames[] = { "Control", "Shift", "Alt", "Super" };
+ for (unsigned modifier = 0; modifier < 4; ++modifier) {
+ if (modifiers & (1 << modifier))
+ evas_key_modifier_on(evas, modifierNames[modifier]);
+ else
+ evas_key_modifier_off(evas, modifierNames[modifier]);
+ }
+}
+
+static EvasMouseButton translateMouseButtonNumber(int eventSenderButtonNumber)
+{
+ static const EvasMouseButton translationTable[] = {
+ EvasMouseButtonLeft,
+ EvasMouseButtonMiddle,
+ EvasMouseButtonRight,
+ EvasMouseButtonMiddle // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
+ };
+ static const unsigned translationTableSize = sizeof(translationTable) / sizeof(translationTable[0]);
+
+ if (eventSenderButtonNumber < translationTableSize)
+ return translationTable[eventSenderButtonNumber];
+
+ return EvasMouseButtonLeft;
+}
+
+static bool sendMouseEvent(Evas* evas, EvasMouseEvent event, int buttonNumber, EvasKeyModifier modifiers)
+{
+ unsigned timeStamp = 0;
+
+ DumpRenderTreeSupportEfl::layoutFrame(browser->mainFrame());
+
+ setEvasModifiers(evas, modifiers);
+ if (event & EvasMouseEventMove)
+ evas_event_feed_mouse_move(evas, gLastMousePositionX, gLastMousePositionY, timeStamp++, 0);
+ if (event & EvasMouseEventDown)
+ evas_event_feed_mouse_down(evas, buttonNumber, EVAS_BUTTON_NONE, timeStamp++, 0);
+ if (event & EvasMouseEventUp)
+ evas_event_feed_mouse_up(evas, buttonNumber, EVAS_BUTTON_NONE, timeStamp++, 0);
+
+ const bool horizontal = !!(event & EvasMouseEventScrollLeft | event & EvasMouseEventScrollRight);
+ const bool vertical = !!(event & EvasMouseEventScrollUp | event & EvasMouseEventScrollDown);
+ if (vertical && horizontal) {
+ evas_event_feed_mouse_wheel(evas, 0, (event & EvasMouseEventScrollUp) ? 10 : -10, timeStamp, 0);
+ evas_event_feed_mouse_wheel(evas, 1, (event & EvasMouseEventScrollLeft) ? 10 : -10, timeStamp, 0);
+ } else if (vertical)
+ evas_event_feed_mouse_wheel(evas, 0, (event & EvasMouseEventScrollUp) ? 10 : -10, timeStamp, 0);
+ else if (horizontal)
+ evas_event_feed_mouse_wheel(evas, 1, (event & EvasMouseEventScrollLeft) ? 10 : -10, timeStamp, 0);
+
+ setEvasModifiers(evas, EvasKeyModifierNone);
+
+ return true;
+}
+
+static Eina_Bool sendClick(void*)
+{
+ return !!sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventClick, EvasMouseButtonLeft, EvasKeyModifierNone);
+}
+
+static JSValueRef scheduleAsynchronousClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ ecore_idler_add(sendClick, 0);
+ return JSValueMakeUndefined(context);
+}
+
+static void updateClickCount(int button)
+{
+ if (gLastClickPositionX != gLastMousePositionX
+ || gLastClickPositionY != gLastMousePositionY
+ || gLastClickButton != button
+ || gTimeOffset - gLastClickTimeOffset >= 1)
+ gClickCount = 1;
+ else
+ gClickCount++;
+}
+
+static EvasKeyModifier modifierFromJSValue(JSContextRef context, const JSValueRef value)
+{
+ JSRetainPtr<JSStringRef> jsKeyValue(Adopt, JSValueToStringCopy(context, value, 0));
+
+ if (equals(jsKeyValue, "ctrlKey") || equals(jsKeyValue, "addSelectionKey"))
+ return EvasKeyModifierControl;
+ if (equals(jsKeyValue, "shiftKey") || equals(jsKeyValue, "rangeSelectionKey"))
+ return EvasKeyModifierShift;
+ if (equals(jsKeyValue, "altKey"))
+ return EvasKeyModifierAlt;
+ if (equals(jsKeyValue, "metaKey"))
+ return EvasKeyModifierMeta;
+
+ return EvasKeyModifierNone;
+}
+
+static EvasKeyModifier modifiersFromJSValue(JSContextRef context, const JSValueRef modifiers)
+{
+ // The value may either be a string with a single modifier or an array of modifiers.
+ if (JSValueIsString(context, modifiers))
+ return modifierFromJSValue(context, modifiers);
+
+ JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0);
+ if (!modifiersArray)
+ return EvasKeyModifierNone;
+
+ unsigned modifier = 0;
+ int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, JSStringCreateWithUTF8CString("length"), 0), 0);
+ for (int i = 0; i < modifiersCount; ++i)
+ modifier |= static_cast<unsigned>(modifierFromJSValue(context, JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0)));
+ return static_cast<EvasKeyModifier>(modifier);
+}
+
+static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int button = 0;
+ if (argumentCount == 1) {
+ button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+
+ if (exception && *exception)
+ return JSValueMakeUndefined(context);
+ }
+
+ button = translateMouseButtonNumber(button);
+ // If the same mouse button is already in the down position don't send another event as it may confuse Xvfb.
+ if (gButtonCurrentlyDown == button)
+ return JSValueMakeUndefined(context);
+
+ updateClickCount(button);
+
+ EvasKeyModifier modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone;
+ if (!sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventDown, button, modifiers))
+ return JSValueMakeUndefined(context);
+
+ gButtonCurrentlyDown = button;
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int button = 0;
+ if (argumentCount == 1) {
+ button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+ if (exception && *exception)
+ return JSValueMakeUndefined(context);
+ }
+
+ gLastClickPositionX = gLastMousePositionX;
+ gLastClickPositionY = gLastMousePositionY;
+ gLastClickButton = gButtonCurrentlyDown;
+ gLastClickTimeOffset = gTimeOffset;
+ gButtonCurrentlyDown = 0;
+
+ EvasKeyModifier modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone;
+ sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventUp, translateMouseButtonNumber(button), modifiers);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ gLastMousePositionX = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+ if (exception && *exception)
+ return JSValueMakeUndefined(context);
+ gLastMousePositionY = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
+ if (exception && *exception)
+ return JSValueMakeUndefined(context);
+
+ sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventMove, EvasMouseButtonNone, EvasKeyModifierNone);
+ return JSValueMakeUndefined(context);
+}
+
+static EvasMouseEvent evasMouseEventFromHorizontalAndVerticalOffsets(int horizontalOffset, int verticalOffset)
+{
+ unsigned mouseEvent = 0;
+
+ if (verticalOffset > 0)
+ mouseEvent |= EvasMouseEventScrollUp;
+ else if (verticalOffset < 0)
+ mouseEvent |= EvasMouseEventScrollDown;
+
+ if (horizontalOffset > 0)
+ mouseEvent |= EvasMouseEventScrollRight;
+ else if (horizontalOffset < 0)
+ mouseEvent |= EvasMouseEventScrollLeft;
+
+ return static_cast<EvasMouseEvent>(mouseEvent);
+}
+
+static JSValueRef mouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ const int horizontal = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+ if (exception && *exception)
+ return JSValueMakeUndefined(context);
+ const int vertical = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
+ if (exception && *exception)
+ return JSValueMakeUndefined(context);
+
+ sendMouseEvent(evas_object_evas_get(browser->mainFrame()), evasMouseEventFromHorizontalAndVerticalOffsets(horizontal, vertical), EvasMouseButtonNone, EvasKeyModifierNone);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef continuousMouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return JSValueMakeUndefined(context);
+}
+
+static const char* keyPadNameFromJSValue(JSStringRef character)
+{
+ if (equals(character, "leftArrow"))
+ return "KP_Left";
+ if (equals(character, "rightArrow"))
+ return "KP_Right";
+ if (equals(character, "upArrow"))
+ return "KP_Up";
+ if (equals(character, "downArrow"))
+ return "KP_Down";
+ if (equals(character, "pageUp"))
+ return "KP_Prior";
+ if (equals(character, "pageDown"))
+ return "KP_Next";
+ if (equals(character, "home"))
+ return "KP_Home";
+ if (equals(character, "end"))
+ return "KP_End";
+ if (equals(character, "insert"))
+ return "KP_Insert";
+ if (equals(character, "delete"))
+ return "KP_Delete";
+
+ return 0;
+}
+
+static const char* keyNameFromJSValue(JSStringRef character)
+{
+ if (equals(character, "leftArrow"))
+ return "Left";
+ if (equals(character, "rightArrow"))
+ return "Right";
+ if (equals(character, "upArrow"))
+ return "Up";
+ if (equals(character, "downArrow"))
+ return "Down";
+ if (equals(character, "pageUp"))
+ return "Prior";
+ if (equals(character, "pageDown"))
+ return "Next";
+ if (equals(character, "home"))
+ return "Home";
+ if (equals(character, "end"))
+ return "End";
+ if (equals(character, "insert"))
+ return "Insert";
+ if (equals(character, "delete"))
+ return "Delete";
+ if (equals(character, "printScreen"))
+ return "Print";
+ if (equals(character, "menu"))
+ return "Menu";
+ if (equals(character, "F1"))
+ return "F1";
+ if (equals(character, "F2"))
+ return "F2";
+ if (equals(character, "F3"))
+ return "F3";
+ if (equals(character, "F4"))
+ return "F4";
+ if (equals(character, "F5"))
+ return "F5";
+ if (equals(character, "F6"))
+ return "F6";
+ if (equals(character, "F7"))
+ return "F7";
+ if (equals(character, "F8"))
+ return "F8";
+ if (equals(character, "F9"))
+ return "F9";
+ if (equals(character, "F10"))
+ return "F10";
+ if (equals(character, "F11"))
+ return "F11";
+ if (equals(character, "F12"))
+ return "F12";
+
+ int charCode = JSStringGetCharactersPtr(character)[0];
+ if (charCode == '\n' || charCode == '\r')
+ return "Return";
+ if (charCode == '\t')
+ return "Tab";
+ if (charCode == '\x8')
+ return "BackSpace";
+
+ return 0;
+}
+
+static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ Evas_Object* view = ewk_frame_view_get(browser->mainFrame());
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ // handle location argument.
+ int location = DomKeyLocationStandard;
+ if (argumentCount > 2)
+ location = static_cast<int>(JSValueToNumber(context, arguments[2], exception));
+
+ JSRetainPtr<JSStringRef> character(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ if (exception && *exception)
+ return JSValueMakeUndefined(context);
+
+ // send the event
+ Evas* evas = evas_object_evas_get(view);
+ if (argumentCount >= 2)
+ setEvasModifiers(evas, modifiersFromJSValue(context, arguments[1]));
+
+ const CString cCharacter = character.get()->ustring().utf8();
+ const char* keyName = (location == DomKeyLocationNumpad) ? keyPadNameFromJSValue(character.get()) : keyNameFromJSValue(character.get());
+
+ if (!keyName)
+ keyName = cCharacter.data();
+
+ DumpRenderTreeSupportEfl::layoutFrame(browser->mainFrame());
+ evas_event_feed_key_down(evas, keyName, keyName, keyName, 0, 0, 0);
+ evas_event_feed_key_up(evas, keyName, keyName, keyName, 0, 1, 0);
+
+ setEvasModifiers(evas, EvasKeyModifierNone);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef scalePageByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 3)
+ return JSValueMakeUndefined(context);
+
+ Evas_Object* view = ewk_frame_view_get(browser->mainFrame());
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ float scaleFactor = JSValueToNumber(context, arguments[0], exception);
+ float x = JSValueToNumber(context, arguments[1], exception);
+ float y = JSValueToNumber(context, arguments[2], exception);
+ ewk_view_scale_set(view, scaleFactor, x, y);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSStaticFunction staticFunctions[] = {
+ { "mouseScrollBy", mouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "continuousMouseScrollBy", continuousMouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scheduleAsynchronousClick", scheduleAsynchronousClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scalePageBy", scalePageByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+};
+
+static JSStaticValue staticValues[] = {
+ { 0, 0, 0, 0 }
+};
+
+static JSClassRef getClass(JSContextRef context)
+{
+ static JSClassRef eventSenderClass = 0;
+
+ if (!eventSenderClass) {
+ JSClassDefinition classDefinition = {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ classDefinition.staticFunctions = staticFunctions;
+ classDefinition.staticValues = staticValues;
+
+ eventSenderClass = JSClassCreate(&classDefinition);
+ }
+
+ return eventSenderClass;
+}
+
+JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame)
+{
+ if (isTopFrame) {
+ gDragMode = true;
+
+ // Fly forward in time one second when the main frame loads. This will
+ // ensure that when a test begins clicking in the same location as
+ // a previous test, those clicks won't be interpreted as continuations
+ // of the previous test's click sequences.
+ gTimeOffset += 1000;
+
+ gLastMousePositionX = gLastMousePositionY = 0;
+ gLastClickPositionX = gLastClickPositionY = 0;
+ gLastClickTimeOffset = 0;
+ gLastClickButton = 0;
+ gButtonCurrentlyDown = 0;
+ gClickCount = 0;
+ }
+
+ return JSObjectMake(context, getClass(context), 0);
+}
diff --git a/Tools/DumpRenderTree/efl/EventSender.h b/Tools/DumpRenderTree/efl/EventSender.h
new file mode 100644
index 000000000..bded6552d
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/EventSender.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 EventSender_h
+#define EventSender_h
+
+typedef const struct OpaqueJSContext* JSContextRef;
+typedef struct OpaqueJSValue* JSObjectRef;
+
+// The boolean parameter refers to whether this is being called from a top-level frame.
+JSObjectRef makeEventSender(JSContextRef, bool);
+
+#endif // EventSender_h
diff --git a/Tools/DumpRenderTree/efl/FontManagement.cpp b/Tools/DumpRenderTree/efl/FontManagement.cpp
new file mode 100644
index 000000000..4cf2fb69b
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/FontManagement.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "FontManagement.h"
+
+#include <Ecore_File.h>
+#include <cstdio>
+#include <fontconfig/fontconfig.h>
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+static Vector<String> getFontDirectories()
+{
+ Vector<String> fontDirPaths;
+
+ fontDirPaths.append(String("/usr/share/fonts/TTF/"));
+ fontDirPaths.append(String("/usr/share/fonts/truetype/ttf-liberation/"));
+ fontDirPaths.append(String("/usr/share/fonts/liberation/"));
+ fontDirPaths.append(String("/usr/share/fonts/truetype/ttf-dejavu/"));
+ fontDirPaths.append(String("/usr/share/fonts/dejavu/"));
+ fontDirPaths.append(String("/usr/share/fonts/OTF/")); // MathML
+ fontDirPaths.append(String("/usr/share/fonts/opentype/stix/")); // MathML
+ fontDirPaths.append(String("/usr/share/fonts/stix/")); // MathML
+
+ return fontDirPaths;
+}
+
+static Vector<String> getFontFiles()
+{
+ Vector<String> fontFilePaths;
+
+ // Ahem is used by many layout tests.
+ fontFilePaths.append(String(FONTS_CONF_DIR "/AHEM____.TTF"));
+ // A font with no valid Fontconfig encoding to test https://bugs.webkit.org/show_bug.cgi?id=47452
+ fontFilePaths.append(String(FONTS_CONF_DIR "/FontWithNoValidEncoding.fon"));
+
+ for (int i = 1; i <= 9; i++) {
+ char fontPath[PATH_MAX];
+ snprintf(fontPath, PATH_MAX - 1,
+ FONTS_CONF_DIR "/../../fonts/WebKitWeightWatcher%i00.ttf", i);
+
+ fontFilePaths.append(String(fontPath));
+ }
+
+ return fontFilePaths;
+}
+
+static size_t addFontDirectories(const Vector<String>& fontDirectories, FcConfig* config)
+{
+ size_t addedDirectories = 0;
+
+ for (Vector<String>::const_iterator it = fontDirectories.begin();
+ it != fontDirectories.end(); ++it) {
+ const CString currentDirectory = (*it).utf8();
+ const char* path = currentDirectory.data();
+
+ if (ecore_file_is_dir(path)) {
+ if (!FcConfigAppFontAddDir(config, reinterpret_cast<const FcChar8*>(path))) {
+ fprintf(stderr, "Could not load font at %s!\n", path);
+ continue;
+ }
+
+ ++addedDirectories;
+ }
+ }
+
+ return addedDirectories;
+}
+
+static void addFontFiles(const Vector<String>& fontFiles, FcConfig* config)
+{
+ for (Vector<String>::const_iterator it = fontFiles.begin(); it != fontFiles.end(); ++it) {
+ const CString currentFile = (*it).utf8();
+ const char* path = currentFile.data();
+
+ if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(path)))
+ fprintf(stderr, "Could not load font at %s!\n", path);
+ }
+}
+
+void addFontsToEnvironment()
+{
+ FcInit();
+
+ // Load our configuration file, which sets up proper aliases for family
+ // names like sans, serif and monospace.
+ FcConfig* config = FcConfigCreate();
+ const char* fontConfigFilename = FONTS_CONF_DIR "/fonts.conf";
+ if (!FcConfigParseAndLoad(config, reinterpret_cast<const FcChar8*>(fontConfigFilename), true)) {
+ fprintf(stderr, "Couldn't load font configuration file from: %s\n", fontConfigFilename);
+ exit(1);
+ }
+
+ if (!addFontDirectories(getFontDirectories(), config)) {
+ fprintf(stderr, "None of the font directories could be added. Either install them "
+ "or file a bug at http://bugs.webkit.org if they are installed in "
+ "another location.\n");
+ exit(1);
+ }
+
+ addFontFiles(getFontFiles(), config);
+
+ if (!FcConfigSetCurrent(config)) {
+ fprintf(stderr, "Could not set the current font configuration!\n");
+ exit(1);
+ }
+}
+
diff --git a/Tools/DumpRenderTree/efl/FontManagement.h b/Tools/DumpRenderTree/efl/FontManagement.h
new file mode 100644
index 000000000..d497513ae
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/FontManagement.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 FontManagement_h
+#define FontManagement_h
+
+void addFontsToEnvironment();
+
+#endif // FontManagement_h
diff --git a/Tools/DumpRenderTree/efl/GCControllerEfl.cpp b/Tools/DumpRenderTree/efl/GCControllerEfl.cpp
new file mode 100644
index 000000000..1f55a5ce6
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/GCControllerEfl.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h"
+
+#include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
+#include "ewk_private.h"
+
+void GCController::collect() const
+{
+ DumpRenderTreeSupportEfl::garbageCollectorCollect();
+}
+
+void GCController::collectOnAlternateThread(bool waitUntilDone) const
+{
+ DumpRenderTreeSupportEfl::garbageCollectorCollectOnAlternateThread(waitUntilDone);
+}
+
+size_t GCController::getJSObjectCount() const
+{
+ return DumpRenderTreeSupportEfl::javaScriptObjectsCount();
+}
diff --git a/Tools/DumpRenderTree/efl/ImageDiff.cpp b/Tools/DumpRenderTree/efl/ImageDiff.cpp
new file mode 100644
index 000000000..754ecb22a
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/ImageDiff.cpp
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
+ * Copyright (C) 2010 Igalia S.L.
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 <Ecore.h>
+#include <Ecore_Evas.h>
+#include <Evas.h>
+#include <algorithm>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+enum PixelComponent {
+ Red,
+ Green,
+ Blue,
+ Alpha
+};
+
+static OwnPtr<Ecore_Evas> gEcoreEvas;
+static double gTolerance = 0;
+
+static void abortWithErrorMessage(const char* errorMessage);
+
+static unsigned char* pixelFromImageData(unsigned char* imageData, int rowStride, int x, int y)
+{
+ return imageData + (y * rowStride) + (x << 2);
+}
+
+static Evas_Object* differenceImageFromDifferenceBuffer(Evas* evas, unsigned char* buffer, int width, int height)
+{
+ Evas_Object* image = evas_object_image_filled_add(evas);
+ if (!image)
+ abortWithErrorMessage("could not create difference image");
+
+ evas_object_image_size_set(image, width, height);
+ evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888);
+
+ unsigned char* diffPixels = static_cast<unsigned char*>(evas_object_image_data_get(image, EINA_TRUE));
+ const int rowStride = evas_object_image_stride_get(image);
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ unsigned char* diffPixel = pixelFromImageData(diffPixels, rowStride, x, y);
+ diffPixel[Red] = diffPixel[Green] = diffPixel[Blue] = *buffer++;
+ diffPixel[Alpha] = 0xff;
+ }
+ }
+
+ evas_object_image_data_set(image, diffPixels);
+
+ return image;
+}
+
+static float computeDistanceBetweenPixelComponents(unsigned char actualComponent, unsigned char baseComponent)
+{
+ return (actualComponent - baseComponent) / std::max<float>(255 - baseComponent, baseComponent);
+}
+
+static float computeDistanceBetweenPixelComponents(unsigned char* actualPixel, unsigned char* basePixel, PixelComponent component)
+{
+ return computeDistanceBetweenPixelComponents(actualPixel[component], basePixel[component]);
+}
+
+static float calculatePixelDifference(unsigned char* basePixel, unsigned char* actualPixel)
+{
+ const float red = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Red);
+ const float green = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Green);
+ const float blue = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Blue);
+ const float alpha = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Alpha);
+ return sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f;
+}
+
+static float calculateDifference(Evas_Object* baselineImage, Evas_Object* actualImage, OwnPtr<Evas_Object>& differenceImage)
+{
+ int width, height, baselineWidth, baselineHeight;
+ evas_object_image_size_get(actualImage, &width, &height);
+ evas_object_image_size_get(baselineImage, &baselineWidth, &baselineHeight);
+
+ if (width != baselineWidth || height != baselineHeight) {
+ printf("Error, test and reference image have different sizes.\n");
+ return 100; // Completely different.
+ }
+
+ OwnArrayPtr<unsigned char> diffBuffer = adoptArrayPtr(new unsigned char[width * height]);
+ if (!diffBuffer)
+ abortWithErrorMessage("could not create difference buffer");
+
+ const int actualRowStride = evas_object_image_stride_get(actualImage);
+ const int baseRowStride = evas_object_image_stride_get(baselineImage);
+ unsigned numberOfDifferentPixels = 0;
+ float totalDistance = 0;
+ float maxDistance = 0;
+ unsigned char* actualPixels = static_cast<unsigned char*>(evas_object_image_data_get(actualImage, EINA_FALSE));
+ unsigned char* basePixels = static_cast<unsigned char*>(evas_object_image_data_get(baselineImage, EINA_FALSE));
+ unsigned char* currentDiffPixel = diffBuffer.get();
+
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ unsigned char* actualPixel = pixelFromImageData(actualPixels, actualRowStride, x, y);
+ unsigned char* basePixel = pixelFromImageData(basePixels, baseRowStride, x, y);
+
+ const float distance = calculatePixelDifference(basePixel, actualPixel);
+ *currentDiffPixel++ = static_cast<unsigned char>(distance * 255.0f);
+
+ if (distance >= 1.0f / 255.0f) {
+ ++numberOfDifferentPixels;
+ totalDistance += distance;
+ maxDistance = std::max<float>(maxDistance, distance);
+ }
+ }
+ }
+
+ // When using evas_object_image_data_get(), a complementary evas_object_data_set() must be
+ // issued to balance the reference count, even if the image hasn't been changed.
+ evas_object_image_data_set(baselineImage, basePixels);
+ evas_object_image_data_set(actualImage, actualPixels);
+
+ // Compute the difference as a percentage combining both the number of
+ // different pixels and their difference amount i.e. the average distance
+ // over the entire image
+ float difference = 0;
+ if (numberOfDifferentPixels)
+ difference = 100.0f * totalDistance / (height * width);
+ if (difference <= gTolerance)
+ difference = 0;
+ else {
+ difference = roundf(difference * 100.0f) / 100.0f;
+ difference = std::max(difference, 0.01f); // round to 2 decimal places
+
+ differenceImage = adoptPtr(differenceImageFromDifferenceBuffer(evas_object_evas_get(baselineImage), diffBuffer.get(), width, height));
+ }
+
+ return difference;
+}
+
+static int getTemporaryFile(char *fileName, size_t fileNameLength)
+{
+ char* tempDirectory = getenv("TMPDIR");
+ if (!tempDirectory)
+ tempDirectory = getenv("TEMP");
+
+ if (tempDirectory)
+ snprintf(fileName, fileNameLength, "%s/ImageDiffXXXXXX.png", tempDirectory);
+ else {
+#if __linux__
+ strcpy(fileName, "/dev/shm/ImageDiffXXXXXX.png");
+ const int fileDescriptor = mkstemps(fileName, sizeof(".png") - 1);
+ if (fileDescriptor >= 0)
+ return fileDescriptor;
+#endif // __linux__
+
+ strcpy(fileName, "ImageDiffXXXXXX.png");
+ }
+
+ return mkstemps(fileName, sizeof(".png") - 1);
+}
+
+static void printImage(Evas_Object* image)
+{
+ char fileName[PATH_MAX];
+
+ const int tempImageFd = getTemporaryFile(fileName, PATH_MAX);
+ if (tempImageFd == -1)
+ abortWithErrorMessage("could not create temporary file");
+
+ evas_render(evas_object_evas_get(image));
+
+ if (evas_object_image_save(image, fileName, 0, 0)) {
+ struct stat fileInfo;
+ if (!stat(fileName, &fileInfo)) {
+ printf("Content-Length: %ld\n", fileInfo.st_size);
+ fflush(stdout);
+
+ unsigned char buffer[2048];
+ ssize_t bytesRead;
+ while ((bytesRead = read(tempImageFd, buffer, sizeof(buffer))) > 0)
+ write(1, buffer, bytesRead);
+ }
+ }
+ close(tempImageFd);
+ unlink(fileName);
+}
+
+static void printImageDifferences(Evas_Object* baselineImage, Evas_Object* actualImage)
+{
+ OwnPtr<Evas_Object> differenceImage;
+ const float difference = calculateDifference(baselineImage, actualImage, differenceImage);
+
+ if (difference > 0.0f) {
+ if (differenceImage)
+ printImage(differenceImage.get());
+
+ printf("diff: %01.2f%% failed\n", difference);
+ } else
+ printf("diff: %01.2f%% passed\n", difference);
+}
+
+static void resizeEcoreEvasIfNeeded(Evas_Object* image)
+{
+ int newWidth, newHeight;
+ evas_object_image_size_get(image, &newWidth, &newHeight);
+
+ int currentWidth, currentHeight;
+ ecore_evas_screen_geometry_get(gEcoreEvas.get(), 0, 0, &currentWidth, &currentHeight);
+
+ if (newWidth > currentWidth)
+ currentWidth = newWidth;
+ if (newHeight > currentHeight)
+ currentHeight = newHeight;
+
+ ecore_evas_resize(gEcoreEvas.get(), currentWidth, currentHeight);
+}
+
+static PassOwnPtr<Evas_Object> readImageFromStdin(Evas* evas, long imageSize)
+{
+ OwnArrayPtr<unsigned char> imageBuffer = adoptArrayPtr(new unsigned char[imageSize]);
+ if (!imageBuffer)
+ abortWithErrorMessage("cannot allocate image");
+
+ const size_t bytesRead = fread(imageBuffer.get(), 1, imageSize, stdin);
+ if (!bytesRead)
+ return PassOwnPtr<Evas_Object>();
+
+ Evas_Object* image = evas_object_image_filled_add(evas);
+ evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888);
+ evas_object_image_memfile_set(image, imageBuffer.get(), bytesRead, 0, 0);
+
+ resizeEcoreEvasIfNeeded(image);
+
+ return adoptPtr(image);
+}
+
+static bool parseCommandLineOptions(int argc, char** argv)
+{
+ static const option options[] = {
+ { "tolerance", required_argument, 0, 't' },
+ { 0, 0, 0, 0 }
+ };
+ int option;
+
+ while ((option = getopt_long(argc, (char* const*)argv, "t:", options, 0)) != -1) {
+ switch (option) {
+ case 't':
+ gTolerance = atof(optarg);
+ break;
+ case '?':
+ case ':':
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void shutdownEfl()
+{
+ ecore_evas_shutdown();
+ ecore_shutdown();
+ evas_shutdown();
+}
+
+static void abortWithErrorMessage(const char* errorMessage)
+{
+ shutdownEfl();
+
+ printf("Error, %s.\n", errorMessage);
+ exit(EXIT_FAILURE);
+}
+
+static Evas* initEfl()
+{
+ evas_init();
+ ecore_init();
+ ecore_evas_init();
+
+ gEcoreEvas = adoptPtr(ecore_evas_buffer_new(1, 1));
+ Evas* evas = ecore_evas_get(gEcoreEvas.get());
+ if (!evas)
+ abortWithErrorMessage("could not create Ecore_Evas buffer");
+
+ return evas;
+}
+
+int main(int argc, char* argv[])
+{
+ if (!parseCommandLineOptions(argc, argv))
+ return EXIT_FAILURE;
+
+ Evas* evas = initEfl();
+
+ OwnPtr<Evas_Object> actualImage;
+ OwnPtr<Evas_Object> baselineImage;
+
+ char buffer[2048];
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ char* contentLengthStart = strstr(buffer, "Content-Length: ");
+ if (!contentLengthStart)
+ continue;
+ long imageSize;
+ if (sscanf(contentLengthStart, "Content-Length: %ld", &imageSize) == 1) {
+ if (imageSize <= 0)
+ abortWithErrorMessage("image size must be specified");
+
+ if (!actualImage)
+ actualImage = readImageFromStdin(evas, imageSize);
+ else if (!baselineImage) {
+ baselineImage = readImageFromStdin(evas, imageSize);
+
+ printImageDifferences(baselineImage.get(), actualImage.get());
+
+ actualImage.clear();
+ baselineImage.clear();
+ }
+ }
+
+ fflush(stdout);
+ }
+
+ gEcoreEvas.clear(); // Make sure ecore_evas_free is called before the EFL are shut down
+
+ shutdownEfl();
+ return EXIT_SUCCESS;
+}
diff --git a/Tools/DumpRenderTree/efl/JSStringUtils.cpp b/Tools/DumpRenderTree/efl/JSStringUtils.cpp
new file mode 100644
index 000000000..19ca55736
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/JSStringUtils.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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
+ * HOLDERS OR ITS 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 "JSStringUtils.h"
+
+bool equals(JSStringRef jsString, const char* cString)
+{
+ return JSStringIsEqualToUTF8CString(jsString, cString);
+}
+
+bool equals(JSRetainPtr<JSStringRef> jsString, const char* cString)
+{
+ return equals(jsString.get(), cString);
+}
diff --git a/Tools/DumpRenderTree/efl/JSStringUtils.h b/Tools/DumpRenderTree/efl/JSStringUtils.h
new file mode 100644
index 000000000..04d7e0812
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/JSStringUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS 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
+ * HOLDERS OR ITS 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 JSStringUtils_h
+#define JSStringUtils_h
+
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+
+bool equals(JSStringRef, const char*);
+bool equals(JSRetainPtr<JSStringRef>, const char*);
+
+#endif // JSStringUtils_h
+
diff --git a/Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp b/Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp
new file mode 100644
index 000000000..8dd0a37ca
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp
@@ -0,0 +1,785 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Michael Alonzo <jmalonzo@gmail.com>
+ * Copyright (C) 2009,2011 Collabora Ltd.
+ * Copyright (C) 2010 Joone Hur <joone@kldp.org>
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "LayoutTestController.h"
+
+#include "DumpRenderTree.h"
+#include "DumpRenderTreeChrome.h"
+#include "JSStringUtils.h"
+#include "NotImplemented.h"
+#include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
+#include "WorkQueue.h"
+#include "WorkQueueItem.h"
+#include "ewk_private.h"
+#include <EWebKit.h>
+#include <Ecore_File.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <JavaScriptCore/OpaqueJSString.h>
+#include <JavaScriptCore/wtf/text/WTFString.h>
+#include <KURL.h>
+#include <editing/FindOptions.h>
+#include <stdio.h>
+
+LayoutTestController::~LayoutTestController()
+{
+}
+
+void LayoutTestController::addDisallowedURL(JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::clearBackForwardList()
+{
+ notImplemented();
+}
+
+JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef)
+{
+ notImplemented();
+ return 0;
+}
+
+JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef)
+{
+ notImplemented();
+ return 0;
+}
+
+void LayoutTestController::dispatchPendingLoadRequests()
+{
+ // FIXME: Implement for testing fix for 6727495
+ notImplemented();
+}
+
+void LayoutTestController::display()
+{
+ displayWebView();
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id)
+{
+ const Evas_Object* mainFrame = browser->mainFrame();
+ const String counterValue(DumpRenderTreeSupportEfl::counterValueByElementId(mainFrame, id->ustring().utf8().data()));
+ return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(counterValue.utf8().data()));
+}
+
+void LayoutTestController::keepWebHistory()
+{
+ notImplemented();
+}
+
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef)
+{
+ notImplemented();
+ return JSValueMakeUndefined(context);
+}
+
+JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef, int, int, unsigned, unsigned, unsigned, unsigned, bool)
+{
+ notImplemented();
+ return JSValueMakeUndefined(context);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ notImplemented();
+ return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(""));
+}
+
+int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidth, float pageHeight)
+{
+ return DumpRenderTreeSupportEfl::numberOfPagesForElementId(browser->mainFrame(), id->ustring().utf8().data(), pageWidth, pageHeight);
+}
+
+int LayoutTestController::numberOfPages(float pageWidth, float pageHeight)
+{
+ return DumpRenderTreeSupportEfl::numberOfPages(browser->mainFrame(), pageWidth, pageHeight);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char*, int) const
+{
+ notImplemented();
+ return 0;
+}
+
+bool LayoutTestController::isPageBoxVisible(int) const
+{
+ notImplemented();
+ return false;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int, int, int, int, int, int, int) const
+{
+ notImplemented();
+ return 0;
+}
+
+size_t LayoutTestController::webHistoryItemCount()
+{
+ const Ewk_History* history = ewk_view_history_get(browser->mainView());
+ if (!history)
+ return -1;
+
+ return ewk_history_back_list_length(history) + ewk_history_forward_list_length(history);
+}
+
+unsigned LayoutTestController::workerThreadCount() const
+{
+ return DumpRenderTreeSupportEfl::workerThreadCount();
+}
+
+void LayoutTestController::notifyDone()
+{
+ if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
+ dump();
+ m_waitToDump = false;
+ waitForPolicy = false;
+}
+
+JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url)
+{
+ // Function introduced in r28690. This may need special-casing on Windows.
+ return JSStringRetain(url); // Do nothing on Unix.
+}
+
+void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target)
+{
+ WebCore::KURL baseURL(WebCore::KURL(), String::fromUTF8(ewk_frame_uri_get(browser->mainFrame())));
+ WebCore::KURL absoluteURL(baseURL, WTF::String(url->characters(), url->length()));
+
+ JSRetainPtr<JSStringRef> jsAbsoluteURL(
+ Adopt, JSStringCreateWithUTF8CString(absoluteURL.string().utf8().data()));
+
+ WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target));
+}
+
+void LayoutTestController::setAcceptsEditing(bool acceptsEditing)
+{
+ ewk_view_editable_set(browser->mainView(), acceptsEditing);
+}
+
+void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
+{
+ ewk_cookies_policy_set(alwaysAcceptCookies ? EWK_COOKIE_JAR_ACCEPT_ALWAYS : EWK_COOKIE_JAR_ACCEPT_NEVER);
+}
+
+void LayoutTestController::setCustomPolicyDelegate(bool, bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::waitForPolicyDelegate()
+{
+ waitForPolicy = true;
+ setWaitToDump(true);
+}
+
+void LayoutTestController::setScrollbarPolicy(JSStringRef, JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef, JSStringRef, JSStringRef, bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef, JSStringRef, JSStringRef, bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setTabKeyCyclesThroughElements(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setUseDashboardCompatibilityMode(bool)
+{
+ notImplemented();
+}
+
+static CString gUserStyleSheet;
+static bool gUserStyleSheetEnabled = true;
+
+void LayoutTestController::setUserStyleSheetEnabled(bool flag)
+{
+ gUserStyleSheetEnabled = flag;
+ ewk_view_setting_user_stylesheet_set(browser->mainView(), flag ? gUserStyleSheet.data() : 0);
+}
+
+void LayoutTestController::setUserStyleSheetLocation(JSStringRef path)
+{
+ gUserStyleSheet = path->ustring().utf8();
+
+ if (gUserStyleSheetEnabled)
+ setUserStyleSheetEnabled(true);
+}
+
+void LayoutTestController::setValueForUser(JSContextRef, JSValueRef, JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setViewModeMediaFeature(JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setWindowIsKey(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(bool)
+{
+ notImplemented();
+}
+
+static Eina_Bool waitToDumpWatchdogFired(void*)
+{
+ waitToDumpWatchdog = 0;
+ gLayoutTestController->waitToDumpWatchdogTimerFired();
+ return ECORE_CALLBACK_CANCEL;
+}
+
+void LayoutTestController::setWaitToDump(bool waitUntilDone)
+{
+ static const double timeoutSeconds = 30;
+
+ m_waitToDump = waitUntilDone;
+ if (m_waitToDump && !waitToDumpWatchdog)
+ waitToDumpWatchdog = ecore_timer_add(timeoutSeconds, waitToDumpWatchdogFired, 0);
+}
+
+int LayoutTestController::windowCount()
+{
+ return browser->extraViews().size() + 1; // + 1 for the main view.
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(bool flag)
+{
+ ewk_view_setting_private_browsing_set(browser->mainView(), flag);
+}
+
+void LayoutTestController::setJavaScriptCanAccessClipboard(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setXSSAuditorEnabled(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setFrameFlatteningEnabled(bool flag)
+{
+ ewk_view_setting_enable_frame_flattening_set(browser->mainView(), flag);
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool flag)
+{
+ ewk_view_setting_spatial_navigation_set(browser->mainView(), flag);
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setAuthorAndUserStylesEnabled(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setAutofilled(JSContextRef, JSValueRef, bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::disableImageLoading()
+{
+ // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27896
+ // Also need to make sure image loading is re-enabled for each new test.
+ notImplemented();
+}
+
+void LayoutTestController::setMockDeviceOrientation(bool, double, bool, double, bool, double)
+{
+ // FIXME: Implement for DeviceOrientation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=30335.
+ notImplemented();
+}
+
+void LayoutTestController::setMockGeolocationPosition(double, double, double)
+{
+ // FIXME: Implement for Geolocation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=28264.
+ notImplemented();
+}
+
+void LayoutTestController::setMockGeolocationError(int, JSStringRef)
+{
+ // FIXME: Implement for Geolocation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=28264.
+ notImplemented();
+}
+
+void LayoutTestController::setGeolocationPermission(bool allow)
+{
+ // FIXME: Implement for Geolocation layout tests.
+ setGeolocationPermissionCommon(allow);
+}
+
+int LayoutTestController::numberOfPendingGeolocationPermissionRequests()
+{
+ // FIXME: Implement for Geolocation layout tests.
+ return -1;
+}
+
+void LayoutTestController::addMockSpeechInputResult(JSStringRef, double, JSStringRef)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+ notImplemented();
+}
+
+void LayoutTestController::startSpeechInput(JSContextRef inputElement)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+ notImplemented();
+}
+
+void LayoutTestController::setIconDatabaseEnabled(bool enabled)
+{
+ ewk_settings_icon_database_path_set(0);
+
+ if (!enabled)
+ return;
+
+ String databasePath;
+ const char* tempDir = getenv("TMPDIR");
+
+ if (tempDir)
+ databasePath = String::fromUTF8(tempDir);
+ else if (tempDir = getenv("TEMP"))
+ databasePath = String::fromUTF8(tempDir);
+ else
+ databasePath = String::fromUTF8("/tmp");
+
+ databasePath.append("/DumpRenderTree/IconDatabase");
+
+ if (ecore_file_mkpath(databasePath.utf8().data()))
+ ewk_settings_icon_database_path_set(databasePath.utf8().data());
+}
+
+void LayoutTestController::setJavaScriptProfilingEnabled(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setPopupBlockingEnabled(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setPluginsEnabled(bool flag)
+{
+ ewk_view_setting_enable_plugins_set(browser->mainView(), flag);
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef)
+{
+ notImplemented();
+ return false;
+}
+
+void LayoutTestController::execCommand(JSStringRef, JSStringRef)
+{
+ notImplemented();
+}
+
+bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray)
+{
+ JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
+ JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
+ if (!JSValueIsNumber(context, lengthValue))
+ return false;
+
+ WebCore::FindOptions options = 0;
+
+ const size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
+ for (size_t i = 0; i < length; ++i) {
+ JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
+ if (!JSValueIsString(context, value))
+ continue;
+
+ JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0));
+
+ if (equals(optionName, "CaseInsensitive"))
+ options |= WebCore::CaseInsensitive;
+ else if (equals(optionName, "AtWordStarts"))
+ options |= WebCore::AtWordStarts;
+ else if (equals(optionName, "TreatMedialCapitalAsWordStart"))
+ options |= WebCore::TreatMedialCapitalAsWordStart;
+ else if (equals(optionName, "Backwards"))
+ options |= WebCore::Backwards;
+ else if (equals(optionName, "WrapAround"))
+ options |= WebCore::WrapAround;
+ else if (equals(optionName, "StartInSelection"))
+ options |= WebCore::StartInSelection;
+ }
+
+ return DumpRenderTreeSupportEfl::findString(browser->mainView(), target->ustring().utf8().data(), options);
+}
+
+bool LayoutTestController::isCommandEnabled(JSStringRef name)
+{
+ return false;
+}
+
+void LayoutTestController::setCacheModel(int)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::clearPersistentUserStyleSheet()
+{
+ notImplemented();
+}
+
+void LayoutTestController::clearAllApplicationCaches()
+{
+ ewk_settings_application_cache_clear();
+}
+
+void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long)
+{
+ // FIXME: Implement to support application cache quotas.
+ notImplemented();
+}
+
+void LayoutTestController::clearApplicationCacheForOrigin(OpaqueJSString*)
+{
+ // FIXME: Implement to support deleting all application caches for an origin.
+ notImplemented();
+}
+
+long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef)
+{
+ // FIXME: Implement to support getting disk usage in bytes for an origin.
+ notImplemented();
+ return 0;
+}
+
+JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context)
+{
+ // FIXME: Implement to get origins that contain application caches.
+ notImplemented();
+ return JSValueMakeUndefined(context);
+}
+
+long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef)
+{
+ notImplemented();
+ return 0;
+}
+
+void LayoutTestController::clearAllDatabases()
+{
+ ewk_settings_web_database_clear();
+}
+
+void LayoutTestController::setDatabaseQuota(unsigned long long quota)
+{
+ ewk_settings_web_database_default_quota_set(quota);
+}
+
+JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context)
+{
+ notImplemented();
+ return JSValueMakeUndefined(context);
+}
+
+void LayoutTestController::deleteAllLocalStorage()
+{
+ notImplemented();
+}
+
+void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::observeStorageTrackerNotifications(unsigned)
+{
+ notImplemented();
+}
+
+void LayoutTestController::syncLocalStorage()
+{
+ notImplemented();
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool, JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::goBack()
+{
+ // FIXME: implement to enable loader/navigation-while-deferring-loads.html
+ notImplemented();
+}
+
+void LayoutTestController::setDefersLoading(bool)
+{
+ // FIXME: implement to enable loader/navigation-while-deferring-loads.html
+ notImplemented();
+}
+
+void LayoutTestController::setAppCacheMaximumSize(unsigned long long size)
+{
+ ewk_settings_application_cache_max_quota_set(size);
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
+{
+ return DumpRenderTreeSupportEfl::pauseAnimation(browser->mainFrame(), animationName->ustring().utf8().data(), elementId->ustring().utf8().data(), time);
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId)
+{
+ return DumpRenderTreeSupportEfl::pauseTransition(browser->mainFrame(), propertyName->ustring().utf8().data(), elementId->ustring().utf8().data(), time);
+}
+
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
+{
+ return DumpRenderTreeSupportEfl::pauseSVGAnimation(browser->mainFrame(), animationId->ustring().utf8().data(), elementId->ustring().utf8().data(), time);
+}
+
+unsigned LayoutTestController::numberOfActiveAnimations() const
+{
+ return DumpRenderTreeSupportEfl::activeAnimationsCount(browser->mainFrame());
+}
+
+void LayoutTestController::suspendAnimations() const
+{
+ DumpRenderTreeSupportEfl::suspendAnimations(browser->mainFrame());
+}
+
+void LayoutTestController::resumeAnimations() const
+{
+ DumpRenderTreeSupportEfl::resumeAnimations(browser->mainFrame());
+}
+
+void LayoutTestController::overridePreference(JSStringRef, JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::addUserScript(JSStringRef, bool, bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::addUserStyleSheet(JSStringRef, bool)
+{
+ // FIXME: needs more investigation why userscripts/user-style-top-frame-only.html fails when allFrames is false.
+ notImplemented();
+}
+
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
+{
+ ewk_view_setting_enable_developer_extras_set(browser->mainView(), enabled);
+}
+
+void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool)
+{
+ notImplemented();
+}
+
+void LayoutTestController::showWebInspector()
+{
+ notImplemented();
+}
+
+void LayoutTestController::closeWebInspector()
+{
+ notImplemented();
+}
+
+void LayoutTestController::evaluateInWebInspector(long, JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned, JSObjectRef, JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::removeAllVisitedLinks()
+{
+ notImplemented();
+}
+
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ notImplemented();
+ return false;
+}
+
+void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef, JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::apiTestGoToCurrentBackForwardItem()
+{
+ notImplemented();
+}
+
+void LayoutTestController::setWebViewEditable(bool)
+{
+ ewk_frame_editable_set(browser->mainFrame(), EINA_TRUE);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef, JSValueRef) const
+{
+ notImplemented();
+ return 0;
+}
+
+void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setEditingBehavior(const char*)
+{
+ notImplemented();
+}
+
+void LayoutTestController::abortModal()
+{
+ notImplemented();
+}
+
+bool LayoutTestController::hasSpellingMarker(int, int)
+{
+ notImplemented();
+ return false;
+}
+
+bool LayoutTestController::hasGrammarMarker(int, int)
+{
+ notImplemented();
+ return false;
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int, int, int, int, int)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setSerializeHTTPLoads(bool)
+{
+ // FIXME: Implement if needed for https://bugs.webkit.org/show_bug.cgi?id=50758.
+ notImplemented();
+}
+
+void LayoutTestController::setMinimumTimerInterval(double)
+{
+ notImplemented();
+}
+
+void LayoutTestController::setTextDirection(JSStringRef)
+{
+ notImplemented();
+}
+
+void LayoutTestController::allowRoundingHacks()
+{
+ notImplemented();
+}
+
+void LayoutTestController::addChromeInputField()
+{
+ notImplemented();
+}
+
+void LayoutTestController::removeChromeInputField()
+{
+ notImplemented();
+}
+
+void LayoutTestController::focusWebView()
+{
+ notImplemented();
+}
+
+void LayoutTestController::setBackingScaleFactor(double)
+{
+ notImplemented();
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title)
+{
+}
diff --git a/Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp b/Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp
new file mode 100644
index 000000000..109374ec9
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
+ * Copyright (C) 2010 Igalia S.L.
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h"
+#include "DumpRenderTreeChrome.h"
+#include "IntRect.h"
+#include "PixelDumpSupportCairo.h"
+#include "RefPtrCairo.h"
+#include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
+#include "ewk_private.h"
+
+PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool drawSelectionRect)
+{
+ Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(browser->mainView()));
+ Ewk_View_Private_Data* privateData = static_cast<Ewk_View_Private_Data*>(smartData->_priv);
+ const Evas_Object* mainFrame = browser->mainFrame();
+
+ int x, y, width, height;
+ if (!ewk_frame_visible_content_geometry_get(mainFrame, EINA_TRUE, &x, &y, &width, &height))
+ return 0;
+
+ RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height));
+ RefPtr<cairo_t> context = adoptRef(cairo_create(surface.get()));
+
+ const Eina_Rectangle rect = { x, y, width, height };
+ if (!ewk_view_paint(privateData, context.get(), &rect))
+ return 0;
+
+ if (drawSelectionRect) {
+ const WebCore::IntRect selectionRect = DumpRenderTreeSupportEfl::selectionRectangle(mainFrame);
+
+ if (!selectionRect.isEmpty()) {
+ cairo_set_line_width(context.get(), 1.0);
+ cairo_rectangle(context.get(), selectionRect.x(), selectionRect.y(), selectionRect.width(), selectionRect.height());
+ cairo_set_source_rgba(context.get(), 1.0, 0.0, 0.0, 1.0);
+ cairo_stroke(context.get());
+ }
+ }
+
+ return BitmapContext::createByAdoptingBitmapAndContext(0, context.release().leakRef());
+}
diff --git a/Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp b/Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp
new file mode 100644
index 000000000..356a6553c
--- /dev/null
+++ b/Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WorkQueueItem.h"
+
+#include "DumpRenderTree.h"
+#include "DumpRenderTreeChrome.h"
+
+#include <EWebKit.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <JavaScriptCore/OpaqueJSString.h>
+#include <JavaScriptCore/runtime/UString.h>
+#include <JavaScriptCore/wtf/text/CString.h>
+
+bool LoadItem::invoke() const
+{
+ Evas_Object* targetFrame;
+
+ if (!m_target->length())
+ targetFrame = browser->mainFrame();
+ else
+ targetFrame = ewk_frame_child_find(browser->mainFrame(), m_target->ustring().utf8().data());
+
+ ewk_frame_uri_set(targetFrame, m_url->ustring().utf8().data());
+
+ return true;
+}
+
+bool LoadHTMLStringItem::invoke() const
+{
+ if (!m_unreachableURL->length())
+ ewk_frame_contents_set(browser->mainFrame(), m_content->ustring().utf8().data(), 0, 0, 0, m_baseURL->ustring().utf8().data());
+ else
+ ewk_frame_contents_alternate_set(browser->mainFrame(), m_content->ustring().utf8().data(), 0, 0, 0, m_baseURL->ustring().utf8().data(), m_unreachableURL->ustring().utf8().data());
+
+ return true;
+}
+
+bool ReloadItem::invoke() const
+{
+ ewk_view_reload(browser->mainView());
+ return true;
+}
+
+bool ScriptItem::invoke() const
+{
+ return ewk_frame_script_execute(browser->mainFrame(), m_script->ustring().utf8().data());
+}
+
+bool BackForwardItem::invoke() const
+{
+ if (m_howFar == 1)
+ ewk_view_forward(browser->mainView());
+ else if (m_howFar == -1)
+ ewk_view_back(browser->mainView());
+ else
+ ewk_view_navigate(browser->mainView(), m_howFar);
+
+ return true;
+}
diff --git a/Tools/DumpRenderTree/fonts/WebKit Layout Tests 2.ttf b/Tools/DumpRenderTree/fonts/WebKit Layout Tests 2.ttf
new file mode 100644
index 000000000..e732fbc42
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKit Layout Tests 2.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKit Layout Tests.ttf b/Tools/DumpRenderTree/fonts/WebKit Layout Tests.ttf
new file mode 100644
index 000000000..f9f997e63
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKit Layout Tests.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher100.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher100.ttf
new file mode 100644
index 000000000..22b00dec7
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher100.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher200.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher200.ttf
new file mode 100644
index 000000000..1ccadbad5
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher200.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher300.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher300.ttf
new file mode 100644
index 000000000..ab5563dfa
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher300.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher400.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher400.ttf
new file mode 100644
index 000000000..56d279e0e
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher400.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher500.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher500.ttf
new file mode 100644
index 000000000..d827d7d85
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher500.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher600.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher600.ttf
new file mode 100644
index 000000000..914159670
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher600.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher700.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher700.ttf
new file mode 100644
index 000000000..a2d05059d
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher700.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher800.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher800.ttf
new file mode 100644
index 000000000..d0f354bf3
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher800.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/WebKitWeightWatcher900.ttf b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher900.ttf
new file mode 100644
index 000000000..6b895ca71
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher900.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp
new file mode 100644
index 000000000..f50b033ef
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "AccessibilityCallbacks.h"
+
+#include "AccessibilityController.h"
+#include "DumpRenderTree.h"
+#include "GOwnPtr.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include <gtk/gtk.h>
+#include <webkit/webkit.h>
+
+static guint stateChangeListenerId = 0;
+static guint focusEventListenerId = 0;
+static guint activeDescendantChangedListenerId = 0;
+static guint childrenChangedListenerId = 0;
+static guint propertyChangedListenerId = 0;
+static guint visibleDataChangedListenerId = 0;
+
+static void printAccessibilityEvent(AtkObject* accessible, const gchar* signalName)
+{
+ // Sanity check.
+ if (!accessible || !ATK_IS_OBJECT(accessible) || !signalName)
+ return;
+
+ const gchar* objectName = atk_object_get_name(accessible);
+ guint objectRole = atk_object_get_role(accessible);
+
+ // Try to always provide a name to be logged for the object.
+ if (!objectName || *objectName == '\0')
+ objectName = "(No name)";
+
+ printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n",
+ signalName, objectName, objectRole);
+}
+
+static gboolean axObjectEventListener(GSignalInvocationHint *signalHint,
+ guint numParamValues,
+ const GValue *paramValues,
+ gpointer data)
+{
+ // At least we should receive the instance emitting the signal.
+ if (numParamValues < 1)
+ return TRUE;
+
+ AtkObject* accessible = ATK_OBJECT(g_value_get_object(&paramValues[0]));
+ if (!accessible || !ATK_IS_OBJECT(accessible))
+ return TRUE;
+
+ GSignalQuery signal_query;
+ GOwnPtr<gchar> signalName;
+
+ g_signal_query(signalHint->signal_id, &signal_query);
+
+ if (!g_strcmp0(signal_query.signal_name, "state-change")) {
+ signalName.set(g_strdup_printf("state-change:%s = %d",
+ g_value_get_string(&paramValues[1]),
+ g_value_get_boolean(&paramValues[2])));
+ } else if (!g_strcmp0(signal_query.signal_name, "focus-event")) {
+ signalName.set(g_strdup_printf("focus-event = %d",
+ g_value_get_boolean(&paramValues[1])));
+ } else if (!g_strcmp0(signal_query.signal_name, "children-changed")) {
+ signalName.set(g_strdup_printf("children-changed = %d",
+ g_value_get_uint(&paramValues[1])));
+ } else if (!g_strcmp0(signal_query.signal_name, "property-change")) {
+ signalName.set(g_strdup_printf("property-change:%s",
+ g_quark_to_string(signalHint->detail)));
+ } else
+ signalName.set(g_strdup(signal_query.signal_name));
+
+ printAccessibilityEvent(accessible, signalName.get());
+
+ return TRUE;
+}
+
+void connectAccessibilityCallbacks()
+{
+ // Ensure no callbacks are connected before.
+ disconnectAccessibilityCallbacks();
+
+ // Ensure that accessibility is initialized for the WebView by querying for
+ // the root accessible object, which will create the full hierarchy.
+ DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame);
+
+ // Add global listeners for AtkObject's signals.
+ stateChangeListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:state-change");
+ focusEventListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:focus-event");
+ activeDescendantChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:active-descendant-changed");
+ childrenChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:children-changed");
+ propertyChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:property-change");
+ visibleDataChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:visible-data-changed");
+
+ // Ensure the Atk interface types are registered, otherwise
+ // the AtkDocument signal handlers below won't get registered.
+ GObject* dummyAxObject = G_OBJECT(g_object_new(ATK_TYPE_OBJECT, 0));
+ AtkObject* dummyNoOpAxObject = atk_no_op_object_new(dummyAxObject);
+ g_object_unref(G_OBJECT(dummyNoOpAxObject));
+ g_object_unref(dummyAxObject);
+}
+
+void disconnectAccessibilityCallbacks()
+{
+ // AtkObject signals.
+ if (stateChangeListenerId) {
+ atk_remove_global_event_listener(stateChangeListenerId);
+ stateChangeListenerId = 0;
+ }
+ if (focusEventListenerId) {
+ atk_remove_global_event_listener(focusEventListenerId);
+ focusEventListenerId = 0;
+ }
+ if (activeDescendantChangedListenerId) {
+ atk_remove_global_event_listener(activeDescendantChangedListenerId);
+ activeDescendantChangedListenerId = 0;
+ }
+ if (childrenChangedListenerId) {
+ atk_remove_global_event_listener(childrenChangedListenerId);
+ childrenChangedListenerId = 0;
+ }
+ if (propertyChangedListenerId) {
+ atk_remove_global_event_listener(propertyChangedListenerId);
+ propertyChangedListenerId = 0;
+ }
+ if (visibleDataChangedListenerId) {
+ atk_remove_global_event_listener(visibleDataChangedListenerId);
+ visibleDataChangedListenerId = 0;
+ }
+}
+
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h
new file mode 100644
index 000000000..7225757e6
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 AccessibilityCallbacks_h
+#define AccessibilityCallbacks_h
+
+void connectAccessibilityCallbacks();
+void disconnectAccessibilityCallbacks();
+
+#endif
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
new file mode 100644
index 000000000..ceeb8dfcb
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 Jan Michael Alonzo
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityController.h"
+
+#include "AccessibilityCallbacks.h"
+#include "AccessibilityUIElement.h"
+#include "DumpRenderTree.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+
+#include <atk/atk.h>
+#include <gtk/gtk.h>
+#include <webkit/webkit.h>
+
+static bool loggingAccessibilityEvents = false;
+
+AccessibilityController::AccessibilityController()
+{
+}
+
+AccessibilityController::~AccessibilityController()
+{
+}
+
+AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y)
+{
+ // FIXME: implement
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityController::focusedElement()
+{
+ AtkObject* accessible = DumpRenderTreeSupportGtk::getFocusedAccessibleElement(mainFrame);
+ if (!accessible)
+ return 0;
+
+ return AccessibilityUIElement(accessible);
+}
+
+AccessibilityUIElement AccessibilityController::rootElement()
+{
+ AtkObject* accessible = DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame);
+ if (!accessible)
+ return 0;
+
+ return AccessibilityUIElement(accessible);
+}
+
+void AccessibilityController::setLogFocusEvents(bool)
+{
+}
+
+void AccessibilityController::setLogScrollingStartEvents(bool)
+{
+}
+
+void AccessibilityController::setLogValueChangeEvents(bool)
+{
+}
+
+void AccessibilityController::setLogAccessibilityEvents(bool logAccessibilityEvents)
+{
+ if (logAccessibilityEvents == loggingAccessibilityEvents)
+ return;
+
+ if (!logAccessibilityEvents) {
+ disconnectAccessibilityCallbacks();
+ loggingAccessibilityEvents = false;
+ return;
+ }
+
+ connectAccessibilityCallbacks();
+ loggingAccessibilityEvents = true;
+}
+
+bool AccessibilityController::addNotificationListener(JSObjectRef)
+{
+ return false;
+}
+
+void AccessibilityController::removeNotificationListener()
+{
+}
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
new file mode 100644
index 000000000..ad5df14c9
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
@@ -0,0 +1,820 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 Jan Michael Alonzo
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityUIElement.h"
+
+#include "GOwnPtr.h"
+#include "GRefPtr.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include <JavaScriptCore/JSStringRef.h>
+#include <atk/atk.h>
+#include <gtk/gtk.h>
+#include <wtf/Assertions.h>
+
+AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
+ : m_element(element)
+{
+}
+
+AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
+ : m_element(other.m_element)
+{
+}
+
+AccessibilityUIElement::~AccessibilityUIElement()
+{
+}
+
+void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elements)
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&)
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children)
+{
+ int count = childrenCount();
+ for (int i = 0; i < count; i++) {
+ AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i);
+ children.append(AccessibilityUIElement(child));
+ }
+}
+
+void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned start, unsigned end)
+{
+ for (unsigned i = start; i < end; i++) {
+ AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i);
+ elementVector.append(AccessibilityUIElement(child));
+ }
+}
+
+int AccessibilityUIElement::rowCount()
+{
+ if (!m_element)
+ return 0;
+
+ ASSERT(ATK_IS_TABLE(m_element));
+
+ return atk_table_get_n_rows(ATK_TABLE(m_element));
+}
+
+int AccessibilityUIElement::columnCount()
+{
+ if (!m_element)
+ return 0;
+
+ ASSERT(ATK_IS_TABLE(m_element));
+
+ return atk_table_get_n_columns(ATK_TABLE(m_element));
+}
+
+int AccessibilityUIElement::childrenCount()
+{
+ if (!m_element)
+ return 0;
+
+ ASSERT(ATK_IS_OBJECT(m_element));
+
+ return atk_object_get_n_accessible_children(ATK_OBJECT(m_element));
+}
+
+AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y)
+{
+ // FIXME: implement
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
+{
+ // FIXME: implement
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ Vector<AccessibilityUIElement> children;
+ getChildrenWithRange(children, index, index + 1);
+
+ if (children.size() == 1)
+ return children.at(0);
+
+ return 0;
+}
+
+unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
+{
+ // FIXME: implement
+ return 0;
+}
+
+gchar* attributeSetToString(AtkAttributeSet* attributeSet)
+{
+ GString* str = g_string_new(0);
+ for (GSList* attributes = attributeSet; attributes; attributes = attributes->next) {
+ AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data);
+ g_string_append(str, g_strconcat(attribute->name, ":", attribute->value, NULL));
+ if (attributes->next)
+ g_string_append(str, ", ");
+ }
+
+ return g_string_free(str, FALSE);
+}
+
+JSStringRef AccessibilityUIElement::allAttributes()
+{
+ if (!m_element)
+ return JSStringCreateWithCharacters(0, 0);
+
+ ASSERT(ATK_IS_OBJECT(m_element));
+ return JSStringCreateWithUTF8CString(attributeSetToString(atk_object_get_attributes(ATK_OBJECT(m_element))));
+}
+
+JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfDocumentLinks()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+AccessibilityUIElement AccessibilityUIElement::titleUIElement()
+{
+ // FIXME: implement
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::parentElement()
+{
+ if (!m_element)
+ return 0;
+
+ ASSERT(ATK_IS_OBJECT(m_element));
+
+ AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element));
+ return parent ? AccessibilityUIElement(parent) : 0;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfChildren()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::parameterizedAttributeNames()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::role()
+{
+ AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
+
+ if (!role)
+ return JSStringCreateWithCharacters(0, 0);
+
+ const gchar* roleName = atk_role_get_name(role);
+ GOwnPtr<gchar> axRole(g_strdup_printf("AXRole: %s", roleName));
+
+ return JSStringCreateWithUTF8CString(axRole.get());
+}
+
+JSStringRef AccessibilityUIElement::subrole()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::roleDescription()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::title()
+{
+ const gchar* name = atk_object_get_name(ATK_OBJECT(m_element));
+
+ if (!name)
+ return JSStringCreateWithCharacters(0, 0);
+
+ GOwnPtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name));
+
+ return JSStringCreateWithUTF8CString(axTitle.get());
+}
+
+JSStringRef AccessibilityUIElement::description()
+{
+ const gchar* description = atk_object_get_description(ATK_OBJECT(m_element));
+
+ if (!description)
+ return JSStringCreateWithCharacters(0, 0);
+
+ GOwnPtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description));
+
+ return JSStringCreateWithUTF8CString(axDesc.get());
+}
+
+JSStringRef AccessibilityUIElement::stringValue()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::language()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::helpText() const
+{
+ return 0;
+}
+
+double AccessibilityUIElement::x()
+{
+ int x, y;
+
+ atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN);
+
+ return x;
+}
+
+double AccessibilityUIElement::y()
+{
+ int x, y;
+
+ atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN);
+
+ return y;
+}
+
+double AccessibilityUIElement::width()
+{
+ int width, height;
+
+ atk_component_get_size(ATK_COMPONENT(m_element), &width, &height);
+
+ return width;
+}
+
+double AccessibilityUIElement::height()
+{
+ int width, height;
+
+ atk_component_get_size(ATK_COMPONENT(m_element), &width, &height);
+
+ return height;
+}
+
+double AccessibilityUIElement::clickPointX()
+{
+ return 0.f;
+}
+
+double AccessibilityUIElement::clickPointY()
+{
+ return 0.f;
+}
+
+JSStringRef AccessibilityUIElement::orientation() const
+{
+ return 0;
+}
+
+double AccessibilityUIElement::intValue() const
+{
+ GValue value = { 0, { { 0 } } };
+
+ if (!ATK_IS_VALUE(m_element))
+ return 0.0f;
+
+ atk_value_get_current_value(ATK_VALUE(m_element), &value);
+
+ if (G_VALUE_HOLDS_DOUBLE(&value))
+ return g_value_get_double(&value);
+ else if (G_VALUE_HOLDS_INT(&value))
+ return static_cast<double>(g_value_get_int(&value));
+ else
+ return 0.0f;
+}
+
+double AccessibilityUIElement::minValue()
+{
+ GValue value = { 0, { { 0 } } };
+
+ if (!ATK_IS_VALUE(m_element))
+ return 0.0f;
+
+ atk_value_get_minimum_value(ATK_VALUE(m_element), &value);
+
+ if (G_VALUE_HOLDS_DOUBLE(&value))
+ return g_value_get_double(&value);
+ else if (G_VALUE_HOLDS_INT(&value))
+ return static_cast<double>(g_value_get_int(&value));
+ else
+ return 0.0f;
+}
+
+double AccessibilityUIElement::maxValue()
+{
+ GValue value = { 0, { { 0 } } };
+
+ if (!ATK_IS_VALUE(m_element))
+ return 0.0f;
+
+ atk_value_get_maximum_value(ATK_VALUE(m_element), &value);
+
+ if (G_VALUE_HOLDS_DOUBLE(&value))
+ return g_value_get_double(&value);
+ else if (G_VALUE_HOLDS_INT(&value))
+ return static_cast<double>(g_value_get_int(&value));
+ else
+ return 0.0f;
+}
+
+JSStringRef AccessibilityUIElement::valueDescription()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+static bool checkElementState(PlatformUIElement element, AtkStateType stateType)
+{
+ if (!ATK_IS_OBJECT(element))
+ return false;
+
+ GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(element)));
+ return atk_state_set_contains_state(stateSet.get(), stateType);
+}
+
+bool AccessibilityUIElement::isEnabled()
+{
+ return checkElementState(m_element, ATK_STATE_ENABLED);
+}
+
+int AccessibilityUIElement::insertionPointLineNumber()
+{
+ // FIXME: implement
+ return 0;
+}
+
+bool AccessibilityUIElement::isActionSupported(JSStringRef action)
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isRequired() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isFocused() const
+{
+ if (!ATK_IS_OBJECT(m_element))
+ return false;
+
+ GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
+ gboolean isFocused = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSED);
+
+ return isFocused;
+}
+
+bool AccessibilityUIElement::isSelected() const
+{
+ return checkElementState(m_element, ATK_STATE_SELECTED);
+}
+
+int AccessibilityUIElement::hierarchicalLevel() const
+{
+ // FIXME: implement
+ return 0;
+}
+
+bool AccessibilityUIElement::ariaIsGrabbed() const
+{
+ return false;
+}
+
+JSStringRef AccessibilityUIElement::ariaDropEffects() const
+{
+ return 0;
+}
+
+bool AccessibilityUIElement::isExpanded() const
+{
+ if (!ATK_IS_OBJECT(m_element))
+ return false;
+
+ GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
+ gboolean isExpanded = atk_state_set_contains_state(stateSet.get(), ATK_STATE_EXPANDED);
+
+ return isExpanded;
+}
+
+bool AccessibilityUIElement::isChecked() const
+{
+ if (!ATK_IS_OBJECT(m_element))
+ return false;
+
+ GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
+ gboolean isChecked = atk_state_set_contains_state(stateSet.get(), ATK_STATE_CHECKED);
+
+ return isChecked;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfColumnHeaders()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfRowHeaders()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfColumns()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfRows()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfVisibleCells()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfHeader()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+int AccessibilityUIElement::indexInTable()
+{
+ // FIXME: implement
+ return 0;
+}
+
+static JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
+{
+ GOwnPtr<gchar> rangeString(g_strdup("{0, 0}"));
+
+ if (!element)
+ return JSStringCreateWithUTF8CString(rangeString.get());
+
+ ASSERT(ATK_IS_OBJECT(element));
+
+ AtkObject* axTable = atk_object_get_parent(ATK_OBJECT(element));
+ if (!axTable || !ATK_IS_TABLE(axTable))
+ return JSStringCreateWithUTF8CString(rangeString.get());
+
+ // Look for the cell in the table.
+ gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element));
+ if (indexInParent == -1)
+ return JSStringCreateWithUTF8CString(rangeString.get());
+
+ int row = -1;
+ int column = -1;
+ row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent);
+ column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent);
+
+ // Get the actual values, if row and columns are valid values.
+ if (row != -1 && column != -1) {
+ int base = 0;
+ int length = 0;
+ if (isRowRange) {
+ base = row;
+ length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column);
+ } else {
+ base = column;
+ length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column);
+ }
+ rangeString.set(g_strdup_printf("{%d, %d}", base, length));
+ }
+
+ return JSStringCreateWithUTF8CString(rangeString.get());
+}
+
+JSStringRef AccessibilityUIElement::rowIndexRange()
+{
+ // Range in table for rows.
+ return indexRangeInTable(m_element, true);
+}
+
+JSStringRef AccessibilityUIElement::columnIndexRange()
+{
+ // Range in table for columns.
+ return indexRangeInTable(m_element, false);
+}
+
+int AccessibilityUIElement::lineForIndex(int)
+{
+ // FIXME: implement
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned)
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned)
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
+{
+ // FIXME: implement
+ return false;
+}
+
+AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(AccessibilityUIElement* startElement, bool isDirectionNext, JSStringRef searchKey, JSStringRef searchText)
+{
+ // FIXME: implement
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row)
+{
+ if (!m_element)
+ return 0;
+
+ ASSERT(ATK_IS_TABLE(m_element));
+
+ AtkObject* foundCell = atk_table_ref_at(ATK_TABLE(m_element), row, column);
+ return foundCell ? AccessibilityUIElement(foundCell) : 0;
+}
+
+JSStringRef AccessibilityUIElement::selectedTextRange()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
+{
+ // FIXME: implement
+}
+
+JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
+{
+ // FIXME: implement
+ return 0.0f;
+}
+
+bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
+{
+ return false;
+}
+
+void AccessibilityUIElement::increment()
+{
+ if (!m_element)
+ return;
+
+ ASSERT(ATK_IS_OBJECT(m_element));
+ DumpRenderTreeSupportGtk::incrementAccessibilityValue(ATK_OBJECT(m_element));
+}
+
+void AccessibilityUIElement::decrement()
+{
+ if (!m_element)
+ return;
+
+ ASSERT(ATK_IS_OBJECT(m_element));
+ DumpRenderTreeSupportGtk::decrementAccessibilityValue(ATK_OBJECT(m_element));
+}
+
+void AccessibilityUIElement::press()
+{
+ if (!m_element)
+ return;
+
+ ASSERT(ATK_IS_OBJECT(m_element));
+
+ if (!ATK_IS_ACTION(m_element))
+ return;
+
+ // Only one action per object is supported so far.
+ atk_action_do_action(ATK_ACTION(m_element), 0);
+}
+
+void AccessibilityUIElement::showMenu()
+{
+ // FIXME: implement
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::accessibilityValue() const
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::documentEncoding()
+{
+ AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
+ if (role != ATK_ROLE_DOCUMENT_FRAME)
+ return JSStringCreateWithCharacters(0, 0);
+
+ return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "Encoding"));
+}
+
+JSStringRef AccessibilityUIElement::documentURI()
+{
+ AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
+ if (role != ATK_ROLE_DOCUMENT_FRAME)
+ return JSStringCreateWithCharacters(0, 0);
+
+ return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "URI"));
+}
+
+JSStringRef AccessibilityUIElement::url()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
+{
+ // FIXME: implement
+ return false;
+}
+
+void AccessibilityUIElement::removeNotificationListener()
+{
+ // FIXME: implement
+}
+
+bool AccessibilityUIElement::isFocusable() const
+{
+ if (!ATK_IS_OBJECT(m_element))
+ return false;
+
+ GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
+ gboolean isFocusable = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSABLE);
+
+ return isFocusable;
+}
+
+bool AccessibilityUIElement::isSelectable() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isMultiSelectable() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isSelectedOptionActive() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isVisible() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isOffScreen() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isCollapsed() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isIgnored() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::hasPopup() const
+{
+ // FIXME: implement
+ return false;
+}
+
+void AccessibilityUIElement::takeFocus()
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::takeSelection()
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::addSelection()
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::removeSelection()
+{
+ // FIXME: implement
+}
diff --git a/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp
new file mode 100644
index 000000000..d6bb426f2
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp
@@ -0,0 +1,1208 @@
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2008 Alp Toker <alp@nuanti.com>
+ * Copyright (C) 2009 Jan Alonzo <jmalonzo@gmail.com>
+ * Copyright (C) 2010, 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h"
+
+#include "AccessibilityController.h"
+#include "EditingCallbacks.h"
+#include "EventSender.h"
+#include "GCController.h"
+#include "GOwnPtr.h"
+#include "LayoutTestController.h"
+#include "PixelDumpSupport.h"
+#include "PlainTextController.h"
+#include "SelfScrollingWebKitWebView.h"
+#include "TextInputController.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include "WebCoreTestSupport.h"
+#include "WorkQueue.h"
+#include "WorkQueueItem.h"
+#include <JavaScriptCore/JavaScript.h>
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <getopt.h>
+#include <gtk/gtk.h>
+#include <webkit/webkit.h>
+#include <wtf/Assertions.h>
+#include <wtf/gobject/GlibUtilities.h>
+
+#if PLATFORM(X11)
+#include <fontconfig/fontconfig.h>
+#endif
+
+
+using namespace std;
+
+extern "C" {
+// This API is not yet public.
+extern gchar* webkit_web_history_item_get_target(WebKitWebHistoryItem*);
+extern gboolean webkit_web_history_item_is_target_item(WebKitWebHistoryItem*);
+extern GList* webkit_web_history_item_get_children(WebKitWebHistoryItem*);
+extern void webkit_web_settings_add_extra_plugin_directory(WebKitWebView* view, const gchar* directory);
+extern gchar* webkit_web_frame_get_response_mime_type(WebKitWebFrame* frame);
+}
+
+volatile bool done;
+static bool printSeparators;
+static int dumpPixels;
+static int dumpTree = 1;
+
+AccessibilityController* axController = 0;
+RefPtr<LayoutTestController> gLayoutTestController;
+static GCController* gcController = 0;
+static WebKitWebView* webView;
+static GtkWidget* window;
+static GtkWidget* container;
+static GtkWidget* webInspectorWindow;
+WebKitWebFrame* mainFrame = 0;
+WebKitWebFrame* topLoadingFrame = 0;
+guint waitToDumpWatchdog = 0;
+bool waitForPolicy = false;
+
+// This is a list of opened webviews
+GSList* webViewList = 0;
+
+// current b/f item at the end of the previous test
+static WebKitWebHistoryItem* prevTestBFItem = NULL;
+
+const unsigned historyItemIndent = 8;
+
+static void runTest(const string& testPathOrURL);
+
+static bool shouldLogFrameLoadDelegates(const string& pathOrURL)
+{
+ return pathOrURL.find("loading/") != string::npos;
+}
+
+static bool shouldOpenWebInspector(const string& pathOrURL)
+{
+ return pathOrURL.find("inspector/") != string::npos;
+}
+
+static bool shouldDumpAsText(const string& pathOrURL)
+{
+ return pathOrURL.find("dumpAsText/") != string::npos;
+}
+
+static bool shouldEnableDeveloperExtras(const string& pathOrURL)
+{
+ return true;
+}
+
+void dumpFrameScrollPosition(WebKitWebFrame* frame)
+{
+
+}
+
+void displayWebView()
+{
+ gtk_widget_queue_draw(GTK_WIDGET(webView));
+}
+
+static void appendString(gchar*& target, gchar* string)
+{
+ gchar* oldString = target;
+ target = g_strconcat(target, string, NULL);
+ g_free(oldString);
+}
+
+static void initializeGtkFontSettings(const char* testURL)
+{
+ GtkSettings* settings = gtk_settings_get_default();
+ if (!settings)
+ return;
+ g_object_set(settings,
+ "gtk-xft-dpi", 98304, // This is 96 * 1024 or 96 DPI according to the GTK+ docs.
+ "gtk-xft-antialias", 1,
+ "gtk-xft-hinting", 0,
+ "gtk-font-name", "Liberation Sans 12",
+ NULL);
+ gdk_screen_set_resolution(gdk_screen_get_default(), 96.0);
+
+ // One test needs subpixel anti-aliasing turned on, but generally we
+ // want all text in other tests to use to grayscale anti-aliasing.
+ if (testURL && strstr(testURL, "xsettings_antialias_settings.html"))
+ g_object_set(settings, "gtk-xft-rgba", "rgb", NULL);
+ else
+ g_object_set(settings, "gtk-xft-rgba", "none", NULL);
+
+ GdkScreen* screen = gdk_screen_get_default();
+ ASSERT(screen);
+ const cairo_font_options_t* screenOptions = gdk_screen_get_font_options(screen);
+ ASSERT(screenOptions);
+ cairo_font_options_t* options = cairo_font_options_copy(screenOptions);
+ // Turn off text metrics hinting, which quantizes metrics to pixels in device space.
+ cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF);
+ gdk_screen_set_font_options(screen, options);
+ cairo_font_options_destroy(options);
+}
+
+CString getTopLevelPath()
+{
+ if (const char* topLevelDirectory = g_getenv("WEBKIT_TOP_LEVEL"))
+ return topLevelDirectory;
+
+ // If the environment variable wasn't provided then assume we were built into
+ // WebKitBuild/Debug or WebKitBuild/Release. Obviously this will fail if the build
+ // directory is non-standard, but we can't do much more about this.
+ GOwnPtr<char> parentPath(g_path_get_dirname(getCurrentExecutablePath().data()));
+ GOwnPtr<char> layoutTestsPath(g_build_filename(parentPath.get(), "..", "..", "..", NULL));
+ GOwnPtr<char> absoluteTopLevelPath(realpath(layoutTestsPath.get(), 0));
+ return absoluteTopLevelPath.get();
+}
+
+static void initializeFonts(const char* testURL = 0)
+{
+#if PLATFORM(X11)
+ initializeGtkFontSettings(testURL);
+
+ FcInit();
+
+ // If a test resulted a font being added or removed via the @font-face rule, then
+ // we want to reset the FontConfig configuration to prevent it from affecting other tests.
+ static int numFonts = 0;
+ FcFontSet* appFontSet = FcConfigGetFonts(0, FcSetApplication);
+ if (appFontSet && numFonts && appFontSet->nfont == numFonts)
+ return;
+
+ // Load our configuration file, which sets up proper aliases for family
+ // names like sans, serif and monospace.
+ FcConfig* config = FcConfigCreate();
+ GOwnPtr<gchar> fontConfigFilename(g_build_filename(FONTS_CONF_DIR, "fonts.conf", NULL));
+ if (!FcConfigParseAndLoad(config, reinterpret_cast<FcChar8*>(fontConfigFilename.get()), true))
+ g_error("Couldn't load font configuration file from: %s", fontConfigFilename.get());
+
+ CString topLevelPath = getTopLevelPath();
+ GOwnPtr<char> fontsPath(g_build_filename(topLevelPath.data(), "WebKitBuild", "Dependencies",
+ "Root", "webkitgtk-test-fonts", NULL));
+ if (!g_file_test(fontsPath.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
+ g_error("Could not locate test fonts at %s. Is WEBKIT_TOP_LEVEL set?", fontsPath.get());
+
+ GOwnPtr<GError> error;
+ GOwnPtr<GDir> fontsDirectory(g_dir_open(fontsPath.get(), 0, &error.outPtr()));
+ while (const char* directoryEntry = g_dir_read_name(fontsDirectory.get())) {
+ if (!g_str_has_suffix(directoryEntry, ".ttf") && !g_str_has_suffix(directoryEntry, ".otf"))
+ continue;
+ GOwnPtr<gchar> fontPath(g_build_filename(fontsPath.get(), directoryEntry, NULL));
+ if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(fontPath.get())))
+ g_error("Could not load font at %s!", fontPath.get());
+
+ }
+
+ // Ahem is used by many layout tests.
+ GOwnPtr<gchar> ahemFontFilename(g_build_filename(FONTS_CONF_DIR, "AHEM____.TTF", NULL));
+ if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(ahemFontFilename.get())))
+ g_error("Could not load font at %s!", ahemFontFilename.get());
+
+ for (int i = 1; i <= 9; i++) {
+ GOwnPtr<gchar> fontFilename(g_strdup_printf("WebKitWeightWatcher%i00.ttf", i));
+ GOwnPtr<gchar> fontPath(g_build_filename(FONTS_CONF_DIR, "..", "..", "fonts", fontFilename.get(), NULL));
+ if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontPath.get())))
+ g_error("Could not load font at %s!", fontPath.get());
+ }
+
+ // A font with no valid Fontconfig encoding to test https://bugs.webkit.org/show_bug.cgi?id=47452
+ GOwnPtr<gchar> fontWithNoValidEncodingFilename(g_build_filename(FONTS_CONF_DIR, "FontWithNoValidEncoding.fon", NULL));
+ if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontWithNoValidEncodingFilename.get())))
+ g_error("Could not load font at %s!", fontWithNoValidEncodingFilename.get());
+
+ if (!FcConfigSetCurrent(config))
+ g_error("Could not set the current font configuration!");
+
+ numFonts = FcConfigGetFonts(config, FcSetApplication)->nfont;
+#endif
+}
+
+static gchar* dumpFramesAsText(WebKitWebFrame* frame)
+{
+ gchar* result = 0;
+
+ // Add header for all but the main frame.
+ bool isMainFrame = (webkit_web_view_get_main_frame(webView) == frame);
+
+ CString innerText = DumpRenderTreeSupportGtk::getInnerText(frame);
+ if (isMainFrame)
+ result = g_strdup_printf("%s\n", innerText.data());
+ else {
+ const gchar* frameName = webkit_web_frame_get_name(frame);
+ result = g_strdup_printf("\n--------\nFrame: '%s'\n--------\n%s\n", frameName, innerText.data());
+ }
+
+ if (gLayoutTestController->dumpChildFramesAsText()) {
+ GSList* children = DumpRenderTreeSupportGtk::getFrameChildren(frame);
+ for (GSList* child = children; child; child = g_slist_next(child))
+ appendString(result, dumpFramesAsText(static_cast<WebKitWebFrame* >(child->data)));
+ g_slist_free(children);
+ }
+
+ return result;
+}
+
+static gint compareHistoryItems(gpointer* item1, gpointer* item2)
+{
+ GOwnPtr<gchar> firstItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item1)));
+ GOwnPtr<gchar> secondItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item2)));
+ return g_ascii_strcasecmp(firstItemTarget.get(), secondItemTarget.get());
+}
+
+static void dumpHistoryItem(WebKitWebHistoryItem* item, int indent, bool current)
+{
+ ASSERT(item != NULL);
+ int start = 0;
+ g_object_ref(item);
+ if (current) {
+ printf("curr->");
+ start = 6;
+ }
+ for (int i = start; i < indent; i++)
+ putchar(' ');
+
+ // normalize file URLs.
+ const gchar* uri = webkit_web_history_item_get_uri(item);
+ gchar* uriScheme = g_uri_parse_scheme(uri);
+ if (g_strcmp0(uriScheme, "file") == 0) {
+ gchar* pos = g_strstr_len(uri, -1, "/LayoutTests/");
+ if (!pos)
+ return;
+
+ GString* result = g_string_sized_new(strlen(uri));
+ result = g_string_append(result, "(file test):");
+ result = g_string_append(result, pos + strlen("/LayoutTests/"));
+ printf("%s", result->str);
+ g_string_free(result, TRUE);
+ } else
+ printf("%s", uri);
+
+ g_free(uriScheme);
+
+ const gchar* target = webkit_web_history_item_get_target(item);
+ if (target && strlen(target) > 0)
+ printf(" (in frame \"%s\")", target);
+ if (webkit_web_history_item_is_target_item(item))
+ printf(" **nav target**");
+ putchar('\n');
+
+ if (GList* kids = webkit_web_history_item_get_children(item)) {
+ // must sort to eliminate arbitrary result ordering which defeats reproducible testing
+ for (GList* kid = g_list_sort(kids, (GCompareFunc) compareHistoryItems); kid; kid = g_list_next(kid)) {
+ WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(kid->data);
+ dumpHistoryItem(item, indent + 4, FALSE);
+ g_object_unref(item);
+ }
+ g_list_free(kids);
+ }
+ g_object_unref(item);
+}
+
+static void dumpBackForwardListForWebView(WebKitWebView* view)
+{
+ printf("\n============== Back Forward List ==============\n");
+ WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(view);
+
+ // Print out all items in the list after prevTestBFItem, which was from the previous test
+ // Gather items from the end of the list, the print them out from oldest to newest
+ GList* itemsToPrint = NULL;
+ gint forwardListCount = webkit_web_back_forward_list_get_forward_length(bfList);
+ for (int i = forwardListCount; i > 0; i--) {
+ WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i);
+ // something is wrong if the item from the last test is in the forward part of the b/f list
+ ASSERT(item != prevTestBFItem);
+ g_object_ref(item);
+ itemsToPrint = g_list_prepend(itemsToPrint, item);
+ }
+
+ WebKitWebHistoryItem* currentItem = webkit_web_back_forward_list_get_current_item(bfList);
+ g_object_ref(currentItem);
+ itemsToPrint = g_list_prepend(itemsToPrint, currentItem);
+
+ gint backListCount = webkit_web_back_forward_list_get_back_length(bfList);
+ for (int i = -1; i >= -(backListCount); i--) {
+ WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i);
+ if (item == prevTestBFItem)
+ break;
+ g_object_ref(item);
+ itemsToPrint = g_list_prepend(itemsToPrint, item);
+ }
+
+ for (GList* itemToPrint = itemsToPrint; itemToPrint; itemToPrint = g_list_next(itemToPrint)) {
+ WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(itemToPrint->data);
+ dumpHistoryItem(item, historyItemIndent, item == currentItem);
+ g_object_unref(item);
+ }
+
+ g_list_free(itemsToPrint);
+ printf("===============================================\n");
+}
+
+static void dumpBackForwardListForAllWebViews()
+{
+ // Dump the back forward list of the main WebView first
+ dumpBackForwardListForWebView(webView);
+
+ // The view list is prepended. Reverse the list so we get the order right.
+ for (GSList* currentView = g_slist_reverse(webViewList); currentView; currentView = g_slist_next(currentView))
+ dumpBackForwardListForWebView(WEBKIT_WEB_VIEW(currentView->data));
+}
+
+static void invalidateAnyPreviousWaitToDumpWatchdog()
+{
+ if (waitToDumpWatchdog) {
+ g_source_remove(waitToDumpWatchdog);
+ waitToDumpWatchdog = 0;
+ }
+
+ waitForPolicy = false;
+}
+
+static void resetDefaultsToConsistentValues()
+{
+ WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
+ GOwnPtr<gchar> localStoragePath(g_build_filename(g_get_user_data_dir(), "DumpRenderTreeGtk", "databases", NULL));
+ g_object_set(G_OBJECT(settings),
+ "enable-private-browsing", FALSE,
+ "enable-developer-extras", FALSE,
+ "enable-spell-checking", TRUE,
+ "enable-html5-database", TRUE,
+ "enable-html5-local-storage", TRUE,
+ "html5-local-storage-database-path", localStoragePath.get(),
+ "enable-xss-auditor", FALSE,
+ "enable-spatial-navigation", FALSE,
+ "enable-frame-flattening", FALSE,
+ "javascript-can-access-clipboard", TRUE,
+ "javascript-can-open-windows-automatically", TRUE,
+ "enable-offline-web-application-cache", TRUE,
+ "enable-universal-access-from-file-uris", TRUE,
+ "enable-scripts", TRUE,
+ "enable-dom-paste", TRUE,
+ "default-font-family", "Times",
+ "monospace-font-family", "Courier",
+ "serif-font-family", "Times",
+ "sans-serif-font-family", "Helvetica",
+ "cursive-font-family", "cursive",
+ "fantasy-font-family", "fantasy",
+ "default-font-size", 12,
+ "default-monospace-font-size", 10,
+ "minimum-font-size", 0,
+ "enable-caret-browsing", FALSE,
+ "enable-page-cache", FALSE,
+ "auto-resize-window", TRUE,
+ "enable-java-applet", FALSE,
+ "enable-plugins", TRUE,
+ "enable-hyperlink-auditing", FALSE,
+ "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX,
+ "enable-fullscreen", TRUE,
+ NULL);
+ webkit_web_view_set_settings(webView, settings);
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
+
+ DumpRenderTreeSupportGtk::clearMainFrameName(mainFrame);
+ DumpRenderTreeSupportGtk::scalePageBy(webView, 1, 0, 0);
+
+ WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
+ g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", FALSE, NULL);
+
+ webkit_web_view_set_zoom_level(webView, 1.0);
+ DumpRenderTreeSupportGtk::setMinimumTimerInterval(webView, DumpRenderTreeSupportGtk::defaultMinimumTimerInterval());
+
+ DumpRenderTreeSupportGtk::resetOriginAccessWhiteLists();
+
+ WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
+ webkit_web_back_forward_list_clear(list);
+
+ SoupSession* session = webkit_get_default_session();
+ SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
+
+ // We only create the jar when the soup backend needs to do
+ // HTTP. Should we initialize it earlier, perhaps?
+ if (jar)
+ g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, NULL);
+
+ setlocale(LC_ALL, "");
+
+ DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(true);
+ webkit_icon_database_set_path(webkit_get_icon_database(), 0);
+ DumpRenderTreeSupportGtk::setSelectTrailingWhitespaceEnabled(false);
+ DumpRenderTreeSupportGtk::setSmartInsertDeleteEnabled(webView, true);
+
+ if (axController)
+ axController->resetToConsistentState();
+
+ DumpRenderTreeSupportGtk::clearOpener(mainFrame);
+
+ DumpRenderTreeSupportGtk::resetGeolocationClientMock(webView);
+
+ DumpRenderTreeSupportGtk::setHixie76WebSocketProtocolEnabled(webView, true);
+}
+
+static bool useLongRunningServerMode(int argc, char *argv[])
+{
+ // This assumes you've already called getopt_long
+ return (argc == optind+1 && !strcmp(argv[optind], "-"));
+}
+
+static void runTestingServerLoop()
+{
+ // When DumpRenderTree runs in server mode, we just wait around for file names
+ // to be passed to us and read each in turn, passing the results back to the client
+ char filenameBuffer[2048];
+ while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
+ char* newLineCharacter = strchr(filenameBuffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (!strlen(filenameBuffer))
+ continue;
+
+ runTest(filenameBuffer);
+ }
+}
+
+static void initializeGlobalsFromCommandLineOptions(int argc, char *argv[])
+{
+ struct option options[] = {
+ {"notree", no_argument, &dumpTree, false},
+ {"pixel-tests", no_argument, &dumpPixels, true},
+ {"tree", no_argument, &dumpTree, true},
+ {NULL, 0, NULL, 0}
+ };
+
+ int option;
+ while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) {
+ switch (option) {
+ case '?': // unknown or ambiguous option
+ case ':': // missing argument
+ exit(1);
+ break;
+ }
+ }
+}
+
+
+void dump()
+{
+ invalidateAnyPreviousWaitToDumpWatchdog();
+
+ if (dumpTree) {
+ char* result = 0;
+ gchar* responseMimeType = webkit_web_frame_get_response_mime_type(mainFrame);
+
+ if (g_str_equal(responseMimeType, "text/plain")) {
+ gLayoutTestController->setDumpAsText(true);
+ gLayoutTestController->setGeneratePixelResults(false);
+ }
+ g_free(responseMimeType);
+
+ if (gLayoutTestController->dumpAsText())
+ result = dumpFramesAsText(mainFrame);
+ else {
+ // Widget resizing is done asynchronously in GTK+. We pump the main
+ // loop here, to flush any pending resize requests. This prevents
+ // timing issues which affect the size of elements in the output.
+ // We only enable this workaround for tests that print the render tree
+ // because this seems to break some dumpAsText tests: see bug 39988
+ // After fixing that test, we should apply this approach to all dumps.
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ result = g_strdup(DumpRenderTreeSupportGtk::dumpRenderTree(mainFrame).data());
+ }
+
+ if (!result) {
+ const char* errorMessage;
+ if (gLayoutTestController->dumpAsText())
+ errorMessage = "[documentElement innerText]";
+ else if (gLayoutTestController->dumpDOMAsWebArchive())
+ errorMessage = "[[mainFrame DOMDocument] webArchive]";
+ else if (gLayoutTestController->dumpSourceAsWebArchive())
+ errorMessage = "[[mainFrame dataSource] webArchive]";
+ else
+ errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";
+ printf("ERROR: nil result from %s", errorMessage);
+ } else {
+ printf("%s", result);
+ g_free(result);
+ if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive())
+ dumpFrameScrollPosition(mainFrame);
+
+ if (gLayoutTestController->dumpBackForwardList())
+ dumpBackForwardListForAllWebViews();
+ }
+
+ if (printSeparators) {
+ puts("#EOF"); // terminate the content block
+ fputs("#EOF\n", stderr);
+ fflush(stdout);
+ fflush(stderr);
+ }
+ }
+
+ if (dumpPixels
+ && gLayoutTestController->generatePixelResults()
+ && !gLayoutTestController->dumpDOMAsWebArchive()
+ && !gLayoutTestController->dumpSourceAsWebArchive())
+ dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash());
+
+ // FIXME: call displayWebView here when we support --paint
+
+ done = true;
+ gtk_main_quit();
+}
+
+static void setDefaultsToConsistentStateValuesForTesting()
+{
+ resetDefaultsToConsistentValues();
+
+ /* Disable the default auth dialog for testing */
+ SoupSession* session = webkit_get_default_session();
+ soup_session_remove_feature_by_type(session, WEBKIT_TYPE_SOUP_AUTH_DIALOG);
+
+#if PLATFORM(X11)
+ webkit_web_settings_add_extra_plugin_directory(webView, TEST_PLUGIN_DIR);
+#endif
+
+ gchar* databaseDirectory = g_build_filename(g_get_user_data_dir(), "gtkwebkitdrt", "databases", NULL);
+ webkit_set_web_database_directory_path(databaseDirectory);
+ g_free(databaseDirectory);
+
+#if defined(GTK_API_VERSION_2)
+ gtk_rc_parse_string("style \"nix_scrollbar_spacing\" "
+ "{ "
+ " GtkScrolledWindow::scrollbar-spacing = 0 "
+ "} "
+ "class \"GtkWidget\" style \"nix_scrollbar_spacing\"");
+
+#else
+ GtkCssProvider* cssProvider = gtk_css_provider_new();
+ gtk_css_provider_load_from_data(cssProvider,
+ " * { "
+ " -GtkScrolledWindow-scrollbar-spacing: 0;"
+ "} ",
+ -1, 0);
+ gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()),
+ GTK_STYLE_PROVIDER(cssProvider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ g_object_unref(cssProvider);
+#endif
+}
+
+static void sendPixelResultsEOF()
+{
+ puts("#EOF");
+
+ fflush(stdout);
+ fflush(stderr);
+}
+
+static void runTest(const string& testPathOrURL)
+{
+ ASSERT(!testPathOrURL.empty());
+
+ // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows.
+ string testURL(testPathOrURL);
+ string expectedPixelHash;
+ size_t separatorPos = testURL.find("'");
+ if (separatorPos != string::npos) {
+ testURL = string(testPathOrURL, 0, separatorPos);
+ expectedPixelHash = string(testPathOrURL, separatorPos + 1);
+ }
+
+ // Convert the path into a full file URL if it does not look
+ // like an HTTP/S URL (doesn't start with http:// or https://).
+ if (testURL.find("http://") && testURL.find("https://")) {
+ GFile* testFile = g_file_new_for_path(testURL.c_str());
+ gchar* testURLCString = g_file_get_uri(testFile);
+ testURL = testURLCString;
+ g_free(testURLCString);
+ g_object_unref(testFile);
+ }
+
+ resetDefaultsToConsistentValues();
+
+ gLayoutTestController = LayoutTestController::create(testURL, expectedPixelHash);
+ topLoadingFrame = 0;
+ done = false;
+
+ gLayoutTestController->setIconDatabaseEnabled(false);
+
+ if (shouldLogFrameLoadDelegates(testURL))
+ gLayoutTestController->setDumpFrameLoadCallbacks(true);
+
+ if (shouldEnableDeveloperExtras(testURL)) {
+ gLayoutTestController->setDeveloperExtrasEnabled(true);
+ if (shouldOpenWebInspector(testURL))
+ gLayoutTestController->showWebInspector();
+ if (shouldDumpAsText(testURL)) {
+ gLayoutTestController->setDumpAsText(true);
+ gLayoutTestController->setGeneratePixelResults(false);
+ }
+ }
+
+ WorkQueue::shared()->clear();
+ WorkQueue::shared()->setFrozen(false);
+
+ bool isSVGW3CTest = (testURL.find("svg/W3C-SVG-1.1") != string::npos);
+ GtkAllocation size;
+ size.x = size.y = 0;
+ size.width = isSVGW3CTest ? 480 : LayoutTestController::maxViewWidth;
+ size.height = isSVGW3CTest ? 360 : LayoutTestController::maxViewHeight;
+ gtk_window_resize(GTK_WINDOW(window), size.width, size.height);
+ gtk_widget_size_allocate(container, &size);
+
+ if (prevTestBFItem)
+ g_object_unref(prevTestBFItem);
+ WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(webView);
+ prevTestBFItem = webkit_web_back_forward_list_get_current_item(bfList);
+ if (prevTestBFItem)
+ g_object_ref(prevTestBFItem);
+
+ initializeFonts(testURL.c_str());
+
+ // Focus the web view before loading the test to avoid focusing problems
+ gtk_widget_grab_focus(GTK_WIDGET(webView));
+ webkit_web_view_open(webView, testURL.c_str());
+
+ gtk_main();
+
+ // If developer extras enabled Web Inspector may have been open by the test.
+ if (shouldEnableDeveloperExtras(testURL)) {
+ gLayoutTestController->closeWebInspector();
+ gLayoutTestController->setDeveloperExtrasEnabled(false);
+ }
+
+ // Also check if we still have opened webViews and free them.
+ if (gLayoutTestController->closeRemainingWindowsWhenComplete() || webViewList) {
+ while (webViewList) {
+ g_object_unref(WEBKIT_WEB_VIEW(webViewList->data));
+ webViewList = g_slist_next(webViewList);
+ }
+ g_slist_free(webViewList);
+ webViewList = 0;
+ }
+
+ WebCoreTestSupport::resetInternalsObject(webkit_web_frame_get_global_context(mainFrame));
+
+ // A blank load seems to be necessary to reset state after certain tests.
+ webkit_web_view_open(webView, "about:blank");
+
+ gLayoutTestController.clear();
+
+ // terminate the (possibly empty) pixels block after all the state reset
+ sendPixelResultsEOF();
+}
+
+void webViewLoadStarted(WebKitWebView* view, WebKitWebFrame* frame, void*)
+{
+ // Make sure we only set this once per test. If it gets cleared, and then set again, we might
+ // end up doing two dumps for one test.
+ if (!topLoadingFrame && !done)
+ topLoadingFrame = frame;
+}
+
+static gboolean processWork(void* data)
+{
+ // if we finish all the commands, we're ready to dump state
+ if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump())
+ dump();
+
+ return FALSE;
+}
+
+static char* getFrameNameSuitableForTestResult(WebKitWebView* view, WebKitWebFrame* frame)
+{
+ char* frameName = g_strdup(webkit_web_frame_get_name(frame));
+
+ if (frame == webkit_web_view_get_main_frame(view)) {
+ // This is a bit strange. Shouldn't web_frame_get_name return NULL?
+ if (frameName && (frameName[0] != '\0')) {
+ char* tmp = g_strdup_printf("main frame \"%s\"", frameName);
+ g_free(frameName);
+ frameName = tmp;
+ } else {
+ g_free(frameName);
+ frameName = g_strdup("main frame");
+ }
+ } else if (!frameName || (frameName[0] == '\0')) {
+ g_free(frameName);
+ frameName = g_strdup("frame (anonymous)");
+ } else {
+ char* tmp = g_strdup_printf("frame \"%s\"", frameName);
+ g_free(frameName);
+ frameName = tmp;
+ }
+
+ return frameName;
+}
+
+static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
+{
+ // The deprecated "load-finished" signal is triggered by postProgressFinishedNotification(),
+ // so we can use it here in the DRT to provide the correct dump.
+ if (frame != topLoadingFrame)
+ return;
+ if (gLayoutTestController->dumpProgressFinishedCallback())
+ printf("postProgressFinishedNotification\n");
+}
+
+static gboolean webViewLoadError(WebKitWebView*, WebKitWebFrame*, gchar*, gpointer, gpointer)
+{
+ return TRUE; // Return true here to disable the default error page.
+}
+
+static void webViewDocumentLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ char* frameName = getFrameNameSuitableForTestResult(view, frame);
+ printf("%s - didFinishDocumentLoadForFrame\n", frameName);
+ g_free(frameName);
+ } else if (!done) {
+ guint pendingFrameUnloadEvents = DumpRenderTreeSupportGtk::getPendingUnloadEventCount(frame);
+ if (pendingFrameUnloadEvents) {
+ char* frameName = getFrameNameSuitableForTestResult(view, frame);
+ printf("%s - has %u onunload handler(s)\n", frameName, pendingFrameUnloadEvents);
+ g_free(frameName);
+ }
+ }
+}
+
+static void webViewOnloadEvent(WebKitWebView* view, WebKitWebFrame* frame, void*)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ char* frameName = getFrameNameSuitableForTestResult(view, frame);
+ printf("%s - didHandleOnloadEventsForFrame\n", frameName);
+ g_free(frameName);
+ }
+}
+
+static void addControllerToWindow(JSContextRef context, JSObjectRef windowObject, const char* controllerName, JSValueRef controller)
+{
+ JSStringRef controllerNameStr = JSStringCreateWithUTF8CString(controllerName);
+ JSObjectSetProperty(context, windowObject, controllerNameStr, controller, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
+ JSStringRelease(controllerNameStr);
+}
+
+static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* frame, JSGlobalContextRef context, JSObjectRef windowObject, gpointer data)
+{
+ JSValueRef exception = 0;
+ ASSERT(gLayoutTestController);
+
+ gLayoutTestController->makeWindowObject(context, windowObject, &exception);
+ ASSERT(!exception);
+
+ gcController->makeWindowObject(context, windowObject, &exception);
+ ASSERT(!exception);
+
+ axController->makeWindowObject(context, windowObject, &exception);
+ ASSERT(!exception);
+
+ addControllerToWindow(context, windowObject, "eventSender", makeEventSender(context, !webkit_web_frame_get_parent(frame)));
+ addControllerToWindow(context, windowObject, "plainText", makePlainTextController(context));
+ addControllerToWindow(context, windowObject, "textInputController", makeTextInputController(context));
+ WebCoreTestSupport::injectInternalsObject(context);
+}
+
+static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data)
+{
+ gchar* testMessage = 0;
+ const gchar* uriScheme;
+
+ // Tests expect only the filename part of local URIs
+ uriScheme = g_strstr_len(message, -1, "file://");
+ if (uriScheme) {
+ GString* tempString = g_string_sized_new(strlen(message));
+ gchar* filename = g_strrstr(uriScheme, G_DIR_SEPARATOR_S);
+
+ if (filename) {
+ filename += strlen(G_DIR_SEPARATOR_S);
+ tempString = g_string_append_len(tempString, message, (uriScheme - message));
+ tempString = g_string_append_len(tempString, filename, strlen(filename));
+ testMessage = g_string_free(tempString, FALSE);
+ }
+ }
+
+ fprintf(stdout, "CONSOLE MESSAGE: line %d: %s\n", line, testMessage ? testMessage : message);
+ g_free(testMessage);
+
+ return TRUE;
+}
+
+
+static gboolean webViewScriptAlert(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gpointer data)
+{
+ fprintf(stdout, "ALERT: %s\n", message);
+ return TRUE;
+}
+
+static gboolean webViewScriptPrompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value, gpointer data)
+{
+ fprintf(stdout, "PROMPT: %s, default text: %s\n", message, defaultValue);
+ *value = g_strdup(defaultValue);
+ return TRUE;
+}
+
+static gboolean webViewScriptConfirm(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm, gpointer data)
+{
+ fprintf(stdout, "CONFIRM: %s\n", message);
+ *didConfirm = TRUE;
+ return TRUE;
+}
+
+static void webViewTitleChanged(WebKitWebView* view, WebKitWebFrame* frame, const gchar* title, gpointer data)
+{
+ if (gLayoutTestController->dumpTitleChanges() && !done)
+ printf("TITLE CHANGED: %s\n", title ? title : "");
+}
+
+static bool webViewNavigationPolicyDecisionRequested(WebKitWebView* view, WebKitWebFrame* frame,
+ WebKitNetworkRequest* request,
+ WebKitWebNavigationAction* navAction,
+ WebKitWebPolicyDecision* policyDecision)
+{
+ // Use the default handler if we're not waiting for policy,
+ // i.e., LayoutTestController::waitForPolicyDelegate
+ if (!waitForPolicy)
+ return FALSE;
+
+ gchar* typeDescription;
+ WebKitWebNavigationReason reason;
+ g_object_get(G_OBJECT(navAction), "reason", &reason, NULL);
+
+ switch(reason) {
+ case WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED:
+ typeDescription = g_strdup("link clicked");
+ break;
+ case WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED:
+ typeDescription = g_strdup("form submitted");
+ break;
+ case WEBKIT_WEB_NAVIGATION_REASON_BACK_FORWARD:
+ typeDescription = g_strdup("back/forward");
+ break;
+ case WEBKIT_WEB_NAVIGATION_REASON_RELOAD:
+ typeDescription = g_strdup("reload");
+ break;
+ case WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED:
+ typeDescription = g_strdup("form resubmitted");
+ break;
+ case WEBKIT_WEB_NAVIGATION_REASON_OTHER:
+ typeDescription = g_strdup("other");
+ break;
+ default:
+ typeDescription = g_strdup("illegal value");
+ }
+
+ printf("Policy delegate: attempt to load %s with navigation type '%s'\n", webkit_network_request_get_uri(request), typeDescription);
+ g_free(typeDescription);
+
+ webkit_web_policy_decision_ignore(policyDecision);
+ gLayoutTestController->notifyDone();
+
+ return TRUE;
+}
+
+static void webViewStatusBarTextChanged(WebKitWebView* view, const gchar* message, gpointer data)
+{
+ // Are we doing anything wrong? One test that does not call
+ // dumpStatusCallbacks gets true here
+ if (gLayoutTestController->dumpStatusCallbacks())
+ printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message);
+}
+
+static gboolean webViewClose(WebKitWebView* view)
+{
+ ASSERT(view);
+
+ webViewList = g_slist_remove(webViewList, view);
+ g_object_unref(view);
+
+ return TRUE;
+}
+
+static void databaseQuotaExceeded(WebKitWebView* view, WebKitWebFrame* frame, WebKitWebDatabase *database)
+{
+ ASSERT(view);
+ ASSERT(frame);
+ ASSERT(database);
+
+ WebKitSecurityOrigin* origin = webkit_web_database_get_security_origin(database);
+ if (gLayoutTestController->dumpDatabaseCallbacks()) {
+ printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n",
+ webkit_security_origin_get_protocol(origin),
+ webkit_security_origin_get_host(origin),
+ webkit_security_origin_get_port(origin),
+ webkit_web_database_get_name(database));
+ }
+ webkit_security_origin_set_web_database_quota(origin, 5 * 1024 * 1024);
+}
+
+static bool
+geolocationPolicyDecisionRequested(WebKitWebView*, WebKitWebFrame*, WebKitGeolocationPolicyDecision* decision)
+{
+ if (!gLayoutTestController->isGeolocationPermissionSet())
+ return FALSE;
+ if (gLayoutTestController->geolocationPermission())
+ webkit_geolocation_policy_allow(decision);
+ else
+ webkit_geolocation_policy_deny(decision);
+
+ return TRUE;
+}
+
+
+static WebKitWebView* webViewCreate(WebKitWebView*, WebKitWebFrame*);
+
+static gboolean webInspectorShowWindow(WebKitWebInspector*, gpointer data)
+{
+ gtk_window_set_default_size(GTK_WINDOW(webInspectorWindow), 800, 600);
+ gtk_widget_show_all(webInspectorWindow);
+ return TRUE;
+}
+
+static gboolean webInspectorCloseWindow(WebKitWebInspector*, gpointer data)
+{
+ gtk_widget_destroy(webInspectorWindow);
+ webInspectorWindow = 0;
+ return TRUE;
+}
+
+static WebKitWebView* webInspectorInspectWebView(WebKitWebInspector*, gpointer data)
+{
+ webInspectorWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ GtkWidget* webView = self_scrolling_webkit_web_view_new();
+ gtk_container_add(GTK_CONTAINER(webInspectorWindow),
+ webView);
+
+ return WEBKIT_WEB_VIEW(webView);
+}
+
+static void topLoadingFrameLoadFinished()
+{
+ topLoadingFrame = 0;
+ WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
+ if (gLayoutTestController->waitToDump())
+ return;
+
+ if (WorkQueue::shared()->count())
+ g_timeout_add(0, processWork, 0);
+ else
+ dump();
+}
+
+static void webFrameLoadStatusNotified(WebKitWebFrame* frame, gpointer user_data)
+{
+ WebKitLoadStatus loadStatus = webkit_web_frame_get_load_status(frame);
+
+ if (gLayoutTestController->dumpFrameLoadCallbacks()) {
+ GOwnPtr<char> frameName(getFrameNameSuitableForTestResult(webkit_web_frame_get_web_view(frame), frame));
+
+ switch (loadStatus) {
+ case WEBKIT_LOAD_PROVISIONAL:
+ if (!done)
+ printf("%s - didStartProvisionalLoadForFrame\n", frameName.get());
+ break;
+ case WEBKIT_LOAD_COMMITTED:
+ if (!done)
+ printf("%s - didCommitLoadForFrame\n", frameName.get());
+ break;
+ case WEBKIT_LOAD_FINISHED:
+ if (!done)
+ printf("%s - didFinishLoadForFrame\n", frameName.get());
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((loadStatus == WEBKIT_LOAD_FINISHED || loadStatus == WEBKIT_LOAD_FAILED)
+ && frame == topLoadingFrame)
+ topLoadingFrameLoadFinished();
+}
+
+static void frameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, gpointer user_data)
+{
+ g_signal_connect(webFrame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
+}
+
+static void willSendRequestCallback(WebKitWebView* webView, WebKitWebFrame*, WebKitWebResource*, WebKitNetworkRequest* request, WebKitNetworkResponse*)
+{
+ if (!done && gLayoutTestController->willSendRequestReturnsNull()) {
+ // As requested by the LayoutTestController, don't perform the request.
+ webkit_network_request_set_uri(request, "about:blank");
+ return;
+ }
+
+ SoupMessage* soupMessage = webkit_network_request_get_message(request);
+ SoupURI* uri = soup_uri_new(webkit_network_request_get_uri(request));
+
+ if (SOUP_URI_VALID_FOR_HTTP(uri) && g_strcmp0(uri->host, "127.0.0.1")
+ && g_strcmp0(uri->host, "255.255.255.255")
+ && g_ascii_strncasecmp(uri->host, "localhost", 9)) {
+ printf("Blocked access to external URL %s\n", soup_uri_to_string(uri, FALSE));
+ soup_uri_free(uri);
+ return;
+ }
+ if (uri)
+ soup_uri_free(uri);
+
+ if (soupMessage) {
+ const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders();
+ for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header)
+ soup_message_headers_remove(soupMessage->request_headers, header->c_str());
+ }
+}
+
+static WebKitWebView* createWebView()
+{
+ // It is important to declare DRT is running early so when creating
+ // web view mock clients are used instead of proper ones.
+ DumpRenderTreeSupportGtk::setDumpRenderTreeModeEnabled(true);
+
+ WebKitWebView* view = WEBKIT_WEB_VIEW(self_scrolling_webkit_web_view_new());
+
+ g_object_connect(G_OBJECT(view),
+ "signal::load-started", webViewLoadStarted, 0,
+ "signal::load-finished", webViewLoadFinished, 0,
+ "signal::load-error", webViewLoadError, 0,
+ "signal::window-object-cleared", webViewWindowObjectCleared, 0,
+ "signal::console-message", webViewConsoleMessage, 0,
+ "signal::script-alert", webViewScriptAlert, 0,
+ "signal::script-prompt", webViewScriptPrompt, 0,
+ "signal::script-confirm", webViewScriptConfirm, 0,
+ "signal::title-changed", webViewTitleChanged, 0,
+ "signal::navigation-policy-decision-requested", webViewNavigationPolicyDecisionRequested, 0,
+ "signal::status-bar-text-changed", webViewStatusBarTextChanged, 0,
+ "signal::create-web-view", webViewCreate, 0,
+ "signal::close-web-view", webViewClose, 0,
+ "signal::database-quota-exceeded", databaseQuotaExceeded, 0,
+ "signal::document-load-finished", webViewDocumentLoadFinished, 0,
+ "signal::geolocation-policy-decision-requested", geolocationPolicyDecisionRequested, 0,
+ "signal::onload-event", webViewOnloadEvent, 0,
+ "signal::drag-begin", dragBeginCallback, 0,
+ "signal::drag-end", dragEndCallback, 0,
+ "signal::drag-failed", dragFailedCallback, 0,
+ "signal::frame-created", frameCreatedCallback, 0,
+ "signal::resource-request-starting", willSendRequestCallback, 0,
+
+ NULL);
+ connectEditingCallbacks(view);
+
+ WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
+ g_object_connect(G_OBJECT(inspector),
+ "signal::inspect-web-view", webInspectorInspectWebView, 0,
+ "signal::show-window", webInspectorShowWindow, 0,
+ "signal::close-window", webInspectorCloseWindow, 0,
+ NULL);
+
+ if (webView) {
+ WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
+ webkit_web_view_set_settings(view, settings);
+ }
+
+ // frame-created is not issued for main frame. That's why we must do this here
+ WebKitWebFrame* frame = webkit_web_view_get_main_frame(view);
+ g_signal_connect(frame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
+
+ return view;
+}
+
+static WebKitWebView* webViewCreate(WebKitWebView* view, WebKitWebFrame* frame)
+{
+ if (!gLayoutTestController->canOpenWindows())
+ return 0;
+
+ // Make sure that waitUntilDone has been called.
+ ASSERT(gLayoutTestController->waitToDump());
+
+ WebKitWebView* newWebView = createWebView();
+ g_object_ref_sink(G_OBJECT(newWebView));
+ webViewList = g_slist_prepend(webViewList, newWebView);
+ return newWebView;
+}
+
+static void logHandler(const gchar* domain, GLogLevelFlags level, const gchar* message, gpointer data)
+{
+ if (level < G_LOG_LEVEL_DEBUG)
+ fprintf(stderr, "%s\n", message);
+}
+
+int main(int argc, char* argv[])
+{
+ gtk_init(&argc, &argv);
+
+ // Some plugins might try to use the GLib logger for printing debug
+ // messages. This will cause tests to fail because of unexpected output.
+ // We squelch all debug messages sent to the logger.
+ g_log_set_default_handler(logHandler, 0);
+
+ initializeGlobalsFromCommandLineOptions(argc, argv);
+ initializeFonts();
+
+ window = gtk_window_new(GTK_WINDOW_POPUP);
+#ifdef GTK_API_VERSION_2
+ container = gtk_hbox_new(TRUE, 0);
+#else
+ container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous(GTK_BOX(container), TRUE);
+#endif
+ gtk_container_add(GTK_CONTAINER(window), container);
+ gtk_widget_show_all(window);
+
+ webView = createWebView();
+ gtk_box_pack_start(GTK_BOX(container), GTK_WIDGET(webView), TRUE, TRUE, 0);
+ gtk_widget_realize(GTK_WIDGET(webView));
+ gtk_widget_show_all(container);
+ mainFrame = webkit_web_view_get_main_frame(webView);
+
+ setDefaultsToConsistentStateValuesForTesting();
+
+ gcController = new GCController();
+ axController = new AccessibilityController();
+
+ if (useLongRunningServerMode(argc, argv)) {
+ printSeparators = true;
+ runTestingServerLoop();
+ } else {
+ printSeparators = (optind < argc-1 || (dumpPixels && dumpTree));
+ for (int i = optind; i != argc; ++i)
+ runTest(argv[i]);
+ }
+
+ delete gcController;
+ gcController = 0;
+
+ delete axController;
+ axController = 0;
+
+ gtk_widget_destroy(window);
+
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h b/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h
new file mode 100644
index 000000000..dbd1f8a3d
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeGtk_h
+#define DumpRenderTreeGtk_h
+
+#include <webkit/webkitdefines.h>
+#include <JavaScriptCore/JSBase.h>
+#include <glib.h>
+#include <wtf/text/CString.h>
+
+extern WebKitWebFrame* mainFrame;
+extern WebKitWebFrame* topLoadingFrame;
+extern guint waitToDumpWatchdog;
+extern bool waitForPolicy;
+extern GSList* webViewList;
+
+gchar* JSStringCopyUTF8CString(JSStringRef jsString);
+CString getTopLevelPath();
+
+#endif // DumpRenderTreeGtk_h
diff --git a/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp b/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp
new file mode 100644
index 000000000..2586611aa
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "EditingCallbacks.h"
+
+#include "CString.h"
+#include "DumpRenderTree.h"
+#include "GOwnPtr.h"
+#include "LayoutTestController.h"
+#include <gtk/gtk.h>
+#include <webkit/webkit.h>
+
+static CString dumpNodePath(WebKitDOMNode* node)
+{
+ GOwnPtr<gchar> nodeName(webkit_dom_node_get_node_name(node));
+ GString* path = g_string_new(nodeName.get());
+
+ WebKitDOMNode* parent = webkit_dom_node_get_parent_node(node);
+ while (parent) {
+ GOwnPtr<gchar> parentName(webkit_dom_node_get_node_name(parent));
+
+ g_string_append(path, " > ");
+ g_string_append(path, parentName.get());
+ parent = webkit_dom_node_get_parent_node(parent);
+ }
+
+ GOwnPtr<gchar> pathBuffer(g_string_free(path, FALSE));
+ return pathBuffer.get();
+}
+
+static CString dumpRange(WebKitDOMRange* range)
+{
+ if (!range)
+ return "(null)";
+
+ GOwnPtr<GError> error1;
+ GOwnPtr<GError> error2;
+ GOwnPtr<GError> error3;
+ GOwnPtr<GError> error4;
+ GOwnPtr<gchar> dump(g_strdup_printf("range from %li of %s to %li of %s",
+ webkit_dom_range_get_start_offset(range, &error1.outPtr()),
+ dumpNodePath(webkit_dom_range_get_start_container(range, &error2.outPtr())).data(),
+ webkit_dom_range_get_end_offset(range, &error3.outPtr()),
+ dumpNodePath(webkit_dom_range_get_end_container(range, &error4.outPtr())).data()));
+ return dump.get();
+}
+
+static const char* insertActionString(WebKitInsertAction action)
+{
+ switch (action) {
+ case WEBKIT_INSERT_ACTION_TYPED:
+ return "WebViewInsertActionTyped";
+ case WEBKIT_INSERT_ACTION_PASTED:
+ return "WebViewInsertActionPasted";
+ case WEBKIT_INSERT_ACTION_DROPPED:
+ return "WebViewInsertActionDropped";
+ }
+ ASSERT_NOT_REACHED();
+ return "WebViewInsertActionTyped";
+}
+
+static const char* selectionAffinityString(WebKitSelectionAffinity affinity)
+{
+ switch (affinity) {
+ case WEBKIT_SELECTION_AFFINITY_UPSTREAM:
+ return "NSSelectionAffinityUpstream";
+ case WEBKIT_SELECTION_AFFINITY_DOWNSTREAM:
+ return "NSSelectionAffinityDownstream";
+ }
+ ASSERT_NOT_REACHED();
+ return "NSSelectionAffinityUpstream";
+}
+
+gboolean shouldBeginEditing(WebKitWebView* webView, WebKitDOMRange* range)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n", dumpRange(range).data());
+ return TRUE;
+}
+
+gboolean shouldEndEditing(WebKitWebView* webView, WebKitDOMRange* range)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n", dumpRange(range).data());
+ return TRUE;
+}
+
+gboolean shouldInsertNode(WebKitWebView* webView, WebKitDOMNode* node, WebKitDOMRange* range, WebKitInsertAction action)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks()) {
+ printf("EDITING DELEGATE: shouldInsertNode:%s replacingDOMRange:%s givenAction:%s\n",
+ dumpNodePath(node).data(), dumpRange(range).data(), insertActionString(action));
+ }
+ return TRUE;
+}
+
+gboolean shouldInsertText(WebKitWebView* webView, const gchar* text, WebKitDOMRange* range, WebKitInsertAction action)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks()) {
+ printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:%s givenAction:%s\n",
+ text, dumpRange(range).data(), insertActionString(action));
+ }
+ return TRUE;
+}
+
+gboolean shouldDeleteRange(WebKitWebView* webView, WebKitDOMRange* range)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldDeleteDOMRange:%s\n", dumpRange(range).data());
+ return TRUE;
+}
+
+gboolean shouldShowDeleteInterfaceForElement(WebKitWebView* webView, WebKitDOMHTMLElement* element)
+{
+ GOwnPtr<gchar> elementClassName(webkit_dom_html_element_get_class_name(element));
+ return g_str_equal(elementClassName.get(), "needsDeletionUI");
+}
+
+gboolean shouldChangeSelectedRange(WebKitWebView* webView, WebKitDOMRange* fromRange, WebKitDOMRange* toRange, WebKitSelectionAffinity affinity, gboolean stillSelecting)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks()) {
+ printf("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s toDOMRange:%s affinity:%s stillSelecting:%s\n",
+ dumpRange(fromRange).data(), dumpRange(toRange).data(), selectionAffinityString(affinity),
+ stillSelecting ? "TRUE" : "FALSE");
+ }
+ return TRUE;
+}
+
+gboolean shouldApplyStyle(WebKitWebView* webView, WebKitDOMCSSStyleDeclaration* style, WebKitDOMRange* range)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks()) {
+ GOwnPtr<gchar> styleText(webkit_dom_css_style_declaration_get_css_text(style));
+ printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n",
+ styleText.get(), dumpRange(range).data());
+ }
+ return TRUE;
+}
+
+void editingBegan(WebKitWebView*)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n");
+}
+
+void userChangedContents(WebKitWebView*)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n");
+}
+
+void editingEnded(WebKitWebView*)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n");
+}
+
+void selectionChanged(WebKitWebView*)
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n");
+}
+
+void connectEditingCallbacks(WebKitWebView* webView)
+{
+ g_object_connect(G_OBJECT(webView),
+ "signal::should-begin-editing", shouldBeginEditing, 0,
+ "signal::should-end-editing", shouldEndEditing, 0,
+ "signal::should-insert-node", shouldInsertNode, 0,
+ "signal::should-insert-text", shouldInsertText, 0,
+ "signal::should-delete-range", shouldDeleteRange, 0,
+ "signal::should-show-delete-interface-for-element", shouldShowDeleteInterfaceForElement, 0,
+ "signal::should-change-selected-range", shouldChangeSelectedRange, 0,
+ "signal::should-apply-style", shouldApplyStyle, 0,
+ "signal::editing-began", editingBegan, 0,
+ "signal::user-changed-contents", userChangedContents, 0,
+ "signal::editing-ended", editingEnded, 0,
+ "signal::selection-changed", selectionChanged, 0,
+ NULL);
+}
+
diff --git a/Tools/DumpRenderTree/gtk/EditingCallbacks.h b/Tools/DumpRenderTree/gtk/EditingCallbacks.h
new file mode 100644
index 000000000..7a9514917
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/EditingCallbacks.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 EditingCallbacks_h
+#define EditingCallbacks_h
+
+typedef struct _WebKitWebView WebKitWebView;
+void connectEditingCallbacks(WebKitWebView*);
+
+#endif
diff --git a/Tools/DumpRenderTree/gtk/EventSender.cpp b/Tools/DumpRenderTree/gtk/EventSender.cpp
new file mode 100644
index 000000000..250189090
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/EventSender.cpp
@@ -0,0 +1,898 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "EventSender.h"
+
+#include "DumpRenderTree.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include <GOwnPtrGtk.h>
+#include <GRefPtrGtk.h>
+#include <GtkVersioning.h>
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <cstring>
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+#include <webkit/webkitwebframe.h>
+#include <webkit/webkitwebview.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/Platform.h>
+#include <wtf/text/CString.h>
+
+extern "C" {
+ extern GtkMenu* webkit_web_view_get_context_menu(WebKitWebView*);
+}
+
+static bool dragMode;
+static int timeOffset = 0;
+
+static int lastMousePositionX;
+static int lastMousePositionY;
+static int lastClickPositionX;
+static int lastClickPositionY;
+static int lastClickTimeOffset;
+static int lastClickButton;
+static unsigned buttonCurrentlyDown;
+static int clickCount;
+GdkDragContext* currentDragSourceContext;
+
+struct DelayedMessage {
+ GdkEvent* event;
+ gulong delay;
+};
+
+static DelayedMessage msgQueue[1024];
+
+static unsigned endOfQueue;
+static unsigned startOfQueue;
+
+static const float zoomMultiplierRatio = 1.2f;
+
+// Key event location code defined in DOM Level 3.
+enum KeyLocationCode {
+ DOM_KEY_LOCATION_STANDARD = 0x00,
+ DOM_KEY_LOCATION_LEFT = 0x01,
+ DOM_KEY_LOCATION_RIGHT = 0x02,
+ DOM_KEY_LOCATION_NUMPAD = 0x03
+};
+
+static void sendOrQueueEvent(GdkEvent*, bool = true);
+static void dispatchEvent(GdkEvent* event);
+static guint getStateFlags();
+
+static JSValueRef getDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeBoolean(context, dragMode);
+}
+
+static bool setDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+ dragMode = JSValueToBoolean(context, value);
+ return true;
+}
+
+static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount > 0) {
+ msgQueue[endOfQueue].delay = JSValueToNumber(context, arguments[0], exception);
+ timeOffset += msgQueue[endOfQueue].delay;
+ ASSERT(!exception || !*exception);
+ }
+
+ return JSValueMakeUndefined(context);
+}
+
+bool prepareMouseButtonEvent(GdkEvent* event, int eventSenderButtonNumber, guint modifiers)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return false;
+
+ // The logic for mapping EventSender button numbers to GDK button
+ // numbers originates from the Windows EventSender.
+ int gdkButtonNumber = 3;
+ if (eventSenderButtonNumber >= 0 && eventSenderButtonNumber <= 2)
+ gdkButtonNumber = eventSenderButtonNumber + 1;
+
+ // fast/events/mouse-click-events expects the 4th button
+ // to be event->button = 1, so send a middle-button event.
+ else if (eventSenderButtonNumber == 3)
+ gdkButtonNumber = 2;
+
+ event->button.button = gdkButtonNumber;
+ event->button.x = lastMousePositionX;
+ event->button.y = lastMousePositionY;
+ event->button.window = gtk_widget_get_window(GTK_WIDGET(view));
+ g_object_ref(event->button.window);
+ event->button.device = getDefaultGDKPointerDevice(event->button.window);
+ event->button.state = modifiers | getStateFlags();
+ event->button.time = GDK_CURRENT_TIME;
+ event->button.axes = 0;
+
+ int xRoot, yRoot;
+ gdk_window_get_root_coords(gtk_widget_get_window(GTK_WIDGET(view)), lastMousePositionX, lastMousePositionY, &xRoot, &yRoot);
+ event->button.x_root = xRoot;
+ event->button.y_root = yRoot;
+
+ return true;
+}
+
+static JSValueRef getMenuItemTitleCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+ GtkWidget* widget = GTK_WIDGET(JSObjectGetPrivate(object));
+ CString label;
+ if (GTK_IS_SEPARATOR_MENU_ITEM(widget))
+ label = "<separator>";
+ else
+ label = gtk_menu_item_get_label(GTK_MENU_ITEM(widget));
+
+ return JSValueMakeString(context, JSStringCreateWithUTF8CString(label.data()));
+}
+
+static bool setMenuItemTitleCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+ return true;
+}
+
+static JSValueRef menuItemClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ GtkMenuItem* item = GTK_MENU_ITEM(JSObjectGetPrivate(thisObject));
+ gtk_menu_item_activate(item);
+ return JSValueMakeUndefined(context);
+}
+
+static JSStaticFunction staticMenuItemFunctions[] = {
+ { "click", menuItemClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+};
+
+static JSStaticValue staticMenuItemValues[] = {
+ { "title", getMenuItemTitleCallback, setMenuItemTitleCallback, kJSPropertyAttributeNone },
+ { 0, 0, 0, 0 }
+};
+
+static JSClassRef getMenuItemClass()
+{
+ static JSClassRef menuItemClass = 0;
+
+ if (!menuItemClass) {
+ JSClassDefinition classDefinition = {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ classDefinition.staticFunctions = staticMenuItemFunctions;
+ classDefinition.staticValues = staticMenuItemValues;
+
+ menuItemClass = JSClassCreate(&classDefinition);
+ }
+
+ return menuItemClass;
+}
+
+
+static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ GdkEvent* pressEvent = gdk_event_new(GDK_BUTTON_PRESS);
+
+ if (!prepareMouseButtonEvent(pressEvent, 2, 0))
+ return JSObjectMakeArray(context, 0, 0, 0);
+
+ GdkEvent* releaseEvent = gdk_event_copy(pressEvent);
+ sendOrQueueEvent(pressEvent);
+
+ JSValueRef valueRef = JSObjectMakeArray(context, 0, 0, 0);
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ GtkMenu* gtkMenu = webkit_web_view_get_context_menu(view);
+ if (gtkMenu) {
+ GList* items = gtk_container_get_children(GTK_CONTAINER(gtkMenu));
+ JSValueRef arrayValues[g_list_length(items)];
+ int index = 0;
+ for (GList* item = g_list_first(items); item; item = g_list_next(item)) {
+ arrayValues[index] = JSObjectMake(context, getMenuItemClass(), item->data);
+ index++;
+ }
+ if (index)
+ valueRef = JSObjectMakeArray(context, index - 1, arrayValues, 0);
+ }
+
+ releaseEvent->type = GDK_BUTTON_RELEASE;
+ sendOrQueueEvent(releaseEvent);
+ return valueRef;
+}
+
+static gboolean sendClick(gpointer)
+{
+ GdkEvent* pressEvent = gdk_event_new(GDK_BUTTON_PRESS);
+
+ if (!prepareMouseButtonEvent(pressEvent, 1, 0)) {
+ gdk_event_free(pressEvent);
+ return FALSE;
+ }
+
+ GdkEvent* releaseEvent = gdk_event_copy(pressEvent);
+ dispatchEvent(pressEvent);
+ releaseEvent->type = GDK_BUTTON_RELEASE;
+ dispatchEvent(releaseEvent);
+
+ return FALSE;
+}
+
+static JSValueRef scheduleAsynchronousClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ g_idle_add(sendClick, 0);
+ return JSValueMakeUndefined(context);
+}
+
+static void updateClickCount(int button)
+{
+ if (lastClickPositionX != lastMousePositionX
+ || lastClickPositionY != lastMousePositionY
+ || lastClickButton != button
+ || timeOffset - lastClickTimeOffset >= 1)
+ clickCount = 1;
+ else
+ clickCount++;
+}
+
+static guint gdkModifierFromJSValue(JSContextRef context, const JSValueRef value)
+{
+ JSStringRef string = JSValueToStringCopy(context, value, 0);
+ guint gdkModifier = 0;
+ if (JSStringIsEqualToUTF8CString(string, "ctrlKey")
+ || JSStringIsEqualToUTF8CString(string, "addSelectionKey"))
+ gdkModifier = GDK_CONTROL_MASK;
+ else if (JSStringIsEqualToUTF8CString(string, "shiftKey")
+ || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey"))
+ gdkModifier = GDK_SHIFT_MASK;
+ else if (JSStringIsEqualToUTF8CString(string, "altKey"))
+ gdkModifier = GDK_MOD1_MASK;
+
+ // Currently the metaKey as defined in WebCore/platform/gtk/PlatformMouseEventGtk.cpp
+ // is GDK_META_MASK. This code must be kept in sync with that file.
+ else if (JSStringIsEqualToUTF8CString(string, "metaKey"))
+ gdkModifier = GDK_META_MASK;
+
+ JSStringRelease(string);
+ return gdkModifier;
+}
+
+static guint gdkModifersFromJSValue(JSContextRef context, const JSValueRef modifiers)
+{
+ // The value may either be a string with a single modifier or an array of modifiers.
+ if (JSValueIsString(context, modifiers))
+ return gdkModifierFromJSValue(context, modifiers);
+
+ JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0);
+ if (!modifiersArray)
+ return 0;
+
+ guint gdkModifiers = 0;
+ int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, JSStringCreateWithUTF8CString("length"), 0), 0);
+ for (int i = 0; i < modifiersCount; ++i)
+ gdkModifiers |= gdkModifierFromJSValue(context, JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0));
+ return gdkModifiers;
+}
+
+static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int button = 0;
+ if (argumentCount == 1) {
+ button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+ }
+ guint modifiers = argumentCount >= 2 ? gdkModifersFromJSValue(context, arguments[1]) : 0;
+
+ GdkEvent* event = gdk_event_new(GDK_BUTTON_PRESS);
+ if (!prepareMouseButtonEvent(event, button, modifiers))
+ return JSValueMakeUndefined(context);
+
+ // If the same mouse button is already in the down position don't send another event as it may confuse Xvfb.
+ if (buttonCurrentlyDown == event->button.button)
+ return JSValueMakeUndefined(context);
+
+ buttonCurrentlyDown = event->button.button;
+
+ // Normally GDK will send both GDK_BUTTON_PRESS and GDK_2BUTTON_PRESS for
+ // the second button press during double-clicks. WebKit GTK+ selectively
+ // ignores the first GDK_BUTTON_PRESS of that pair using gdk_event_peek.
+ // Since our events aren't ever going onto the GDK event queue, WebKit won't
+ // be able to filter out the first GDK_BUTTON_PRESS, so we just don't send
+ // it here. Eventually this code should probably figure out a way to get all
+ // appropriate events onto the event queue and this work-around should be
+ // removed.
+ updateClickCount(event->button.button);
+ if (clickCount == 2)
+ event->type = GDK_2BUTTON_PRESS;
+ else if (clickCount == 3)
+ event->type = GDK_3BUTTON_PRESS;
+
+ sendOrQueueEvent(event);
+ return JSValueMakeUndefined(context);
+}
+
+static guint getStateFlags()
+{
+ if (buttonCurrentlyDown == 1)
+ return GDK_BUTTON1_MASK;
+ if (buttonCurrentlyDown == 2)
+ return GDK_BUTTON2_MASK;
+ if (buttonCurrentlyDown == 3)
+ return GDK_BUTTON3_MASK;
+ return 0;
+}
+
+static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int button = 0;
+ if (argumentCount == 1) {
+ button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+ }
+ guint modifiers = argumentCount >= 2 ? gdkModifersFromJSValue(context, arguments[1]) : 0;
+
+ GdkEvent* event = gdk_event_new(GDK_BUTTON_RELEASE);
+ if (!prepareMouseButtonEvent(event, button, modifiers))
+ return JSValueMakeUndefined(context);
+
+ lastClickPositionX = lastMousePositionX;
+ lastClickPositionY = lastMousePositionY;
+ lastClickButton = buttonCurrentlyDown;
+ lastClickTimeOffset = timeOffset;
+ buttonCurrentlyDown = 0;
+
+ sendOrQueueEvent(event);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ lastMousePositionX = (int)JSValueToNumber(context, arguments[0], exception);
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+ lastMousePositionY = (int)JSValueToNumber(context, arguments[1], exception);
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY);
+ event->motion.x = lastMousePositionX;
+ event->motion.y = lastMousePositionY;
+
+ event->motion.time = GDK_CURRENT_TIME;
+ event->motion.window = gtk_widget_get_window(GTK_WIDGET(view));
+ g_object_ref(event->motion.window);
+ event->button.device = getDefaultGDKPointerDevice(event->motion.window);
+
+ guint modifiers = argumentCount >= 3 ? gdkModifersFromJSValue(context, arguments[2]) : 0;
+ event->motion.state = modifiers | getStateFlags();
+ event->motion.axes = 0;
+
+ int xRoot, yRoot;
+ gdk_window_get_root_coords(gtk_widget_get_window(GTK_WIDGET(view)), lastMousePositionX, lastMousePositionY, &xRoot, &yRoot);
+ event->motion.x_root = xRoot;
+ event->motion.y_root = yRoot;
+
+ sendOrQueueEvent(event, false);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef mouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ int horizontal = (int)JSValueToNumber(context, arguments[0], exception);
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+ int vertical = (int)JSValueToNumber(context, arguments[1], exception);
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ // GTK+ doesn't support multiple direction scrolls in the same event!
+ g_return_val_if_fail((!vertical || !horizontal), JSValueMakeUndefined(context));
+
+ GdkEvent* event = gdk_event_new(GDK_SCROLL);
+ event->scroll.x = lastMousePositionX;
+ event->scroll.y = lastMousePositionY;
+ event->scroll.time = GDK_CURRENT_TIME;
+ event->scroll.window = gtk_widget_get_window(GTK_WIDGET(view));
+ g_object_ref(event->scroll.window);
+
+ if (horizontal < 0)
+ event->scroll.direction = GDK_SCROLL_RIGHT;
+ else if (horizontal > 0)
+ event->scroll.direction = GDK_SCROLL_LEFT;
+ else if (vertical < 0)
+ event->scroll.direction = GDK_SCROLL_DOWN;
+ else if (vertical > 0)
+ event->scroll.direction = GDK_SCROLL_UP;
+ else
+ g_assert_not_reached();
+
+ sendOrQueueEvent(event);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef continuousMouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // GTK doesn't support continuous scroll events.
+ return JSValueMakeUndefined(context);
+}
+
+static void dragWithFilesDragDataGetCallback(GtkWidget*, GdkDragContext*, GtkSelectionData *data, guint, guint, gpointer userData)
+{
+ gtk_selection_data_set_uris(data, static_cast<gchar**>(userData));
+}
+
+static void dragWithFilesDragEndCallback(GtkWidget* widget, GdkDragContext*, gpointer userData)
+{
+ g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<void*>(dragWithFilesDragEndCallback), userData);
+ g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<void*>(dragWithFilesDragDataGetCallback), userData);
+ g_strfreev(static_cast<gchar**>(userData));
+}
+
+static JSValueRef beginDragWithFilesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSObjectRef filesArray = JSValueToObject(context, arguments[0], exception);
+ ASSERT(!exception || !*exception);
+
+ const gchar* mainFrameURI = webkit_web_frame_get_uri(mainFrame);
+ GRefPtr<GFile> testFile(adoptGRef(g_file_new_for_uri(mainFrameURI)));
+ GRefPtr<GFile> parentDirectory(g_file_get_parent(testFile.get()));
+ if (!parentDirectory)
+ return JSValueMakeUndefined(context);
+
+ // If this is an HTTP test, we still need to pass a local file path
+ // to WebCore. Even though the file doesn't exist, this should be fine
+ // for most tests.
+ GOwnPtr<gchar> scheme(g_file_get_uri_scheme(parentDirectory.get()));
+ if (g_str_equal(scheme.get(), "http") || g_str_equal(scheme.get(), "https")) {
+ GOwnPtr<gchar> currentDirectory(g_get_current_dir());
+ parentDirectory = g_file_new_for_path(currentDirectory.get());
+ }
+
+ JSStringRef lengthProperty = JSStringCreateWithUTF8CString("length");
+ int filesArrayLength = JSValueToNumber(context, JSObjectGetProperty(context, filesArray, lengthProperty, 0), 0);
+ JSStringRelease(lengthProperty);
+
+ gchar** draggedFilesURIList = g_new0(gchar*, filesArrayLength + 1);
+ for (int i = 0; i < filesArrayLength; ++i) {
+ JSStringRef filenameString = JSValueToStringCopy(context,
+ JSObjectGetPropertyAtIndex(context, filesArray, i, 0), 0);
+ size_t bufferSize = JSStringGetMaximumUTF8CStringSize(filenameString);
+ GOwnPtr<gchar> filenameBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
+ JSStringGetUTF8CString(filenameString, filenameBuffer.get(), bufferSize);
+ JSStringRelease(filenameString);
+
+ GRefPtr<GFile> dragFile(g_file_get_child(parentDirectory.get(), filenameBuffer.get()));
+ draggedFilesURIList[i] = g_file_get_uri(dragFile.get());
+ }
+
+ GtkWidget* view = GTK_WIDGET(webkit_web_frame_get_web_view(mainFrame));
+ g_object_connect(G_OBJECT(view),
+ "signal::drag-end", dragWithFilesDragEndCallback, draggedFilesURIList,
+ "signal::drag-data-get", dragWithFilesDragDataGetCallback, draggedFilesURIList,
+ NULL);
+
+ GdkEvent event;
+ GdkWindow* viewGDKWindow = gtk_widget_get_window(view);
+ memset(&event, 0, sizeof(event));
+ event.type = GDK_MOTION_NOTIFY;
+ event.motion.x = lastMousePositionX;
+ event.motion.y = lastMousePositionY;
+ event.motion.time = GDK_CURRENT_TIME;
+ event.motion.window = viewGDKWindow;
+ event.motion.device = getDefaultGDKPointerDevice(viewGDKWindow);
+ event.motion.state = GDK_BUTTON1_MASK;
+
+ int xRoot, yRoot;
+ gdk_window_get_root_coords(viewGDKWindow, lastMousePositionX, lastMousePositionY, &xRoot, &yRoot);
+ event.motion.x_root = xRoot;
+ event.motion.y_root = yRoot;
+
+ GtkTargetList* targetList = gtk_target_list_new(0, 0);
+ gtk_target_list_add_uri_targets(targetList, 0);
+ gtk_drag_begin(view, targetList, GDK_ACTION_COPY, 1, &event);
+ gtk_target_list_unref(targetList);
+
+ return JSValueMakeUndefined(context);
+}
+
+static void sendOrQueueEvent(GdkEvent* event, bool shouldReplaySavedEvents)
+{
+ // Mouse move events are queued if the previous event was queued or if a
+ // delay was set up by leapForward().
+ if ((dragMode && buttonCurrentlyDown) || endOfQueue != startOfQueue || msgQueue[endOfQueue].delay) {
+ msgQueue[endOfQueue++].event = event;
+
+ if (shouldReplaySavedEvents)
+ replaySavedEvents();
+
+ return;
+ }
+
+ dispatchEvent(event);
+}
+
+static void dispatchEvent(GdkEvent* event)
+{
+ DumpRenderTreeSupportGtk::layoutFrame(mainFrame);
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view) {
+ gdk_event_free(event);
+ return;
+ }
+
+ gtk_main_do_event(event);
+
+ if (!currentDragSourceContext) {
+ gdk_event_free(event);
+ return;
+ }
+
+ if (event->type == GDK_MOTION_NOTIFY) {
+ // WebKit has called gtk_drag_start(), but because the main loop isn't
+ // running GDK internals don't know that the drag has started yet. Pump
+ // the main loop a little bit so that GDK is in the correct state.
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ // Simulate a drag motion on the top-level GDK window.
+ GtkWidget* parentWidget = gtk_widget_get_parent(GTK_WIDGET(view));
+ GdkWindow* parentWidgetWindow = gtk_widget_get_window(parentWidget);
+ gdk_drag_motion(currentDragSourceContext, parentWidgetWindow, GDK_DRAG_PROTO_XDND,
+ event->motion.x_root, event->motion.y_root,
+ gdk_drag_context_get_selected_action(currentDragSourceContext),
+ gdk_drag_context_get_actions(currentDragSourceContext),
+ GDK_CURRENT_TIME);
+
+ } else if (currentDragSourceContext && event->type == GDK_BUTTON_RELEASE) {
+ // We've released the mouse button, we should just be able to spin the
+ // event loop here and have GTK+ send the appropriate notifications for
+ // the end of the drag.
+ while (gtk_events_pending())
+ gtk_main_iteration();
+ }
+
+ gdk_event_free(event);
+}
+
+void replaySavedEvents()
+{
+ // First send all the events that are ready to be sent
+ while (startOfQueue < endOfQueue) {
+ if (msgQueue[startOfQueue].delay) {
+ g_usleep(msgQueue[startOfQueue].delay * 1000);
+ msgQueue[startOfQueue].delay = 0;
+ }
+
+ dispatchEvent(msgQueue[startOfQueue++].event);
+ }
+
+ startOfQueue = 0;
+ endOfQueue = 0;
+}
+
+static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+ guint modifiers = argumentCount >= 2 ? gdkModifersFromJSValue(context, arguments[1]) : 0;
+
+ // handle location argument.
+ int location = DOM_KEY_LOCATION_STANDARD;
+ if (argumentCount > 2)
+ location = (int)JSValueToNumber(context, arguments[2], exception);
+
+ JSStringRef character = JSValueToStringCopy(context, arguments[0], exception);
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+ int gdkKeySym = GDK_VoidSymbol;
+ if (location == DOM_KEY_LOCATION_NUMPAD) {
+ if (JSStringIsEqualToUTF8CString(character, "leftArrow"))
+ gdkKeySym = GDK_KP_Left;
+ else if (JSStringIsEqualToUTF8CString(character, "rightArrow"))
+ gdkKeySym = GDK_KP_Right;
+ else if (JSStringIsEqualToUTF8CString(character, "upArrow"))
+ gdkKeySym = GDK_KP_Up;
+ else if (JSStringIsEqualToUTF8CString(character, "downArrow"))
+ gdkKeySym = GDK_KP_Down;
+ else if (JSStringIsEqualToUTF8CString(character, "pageUp"))
+ gdkKeySym = GDK_KP_Page_Up;
+ else if (JSStringIsEqualToUTF8CString(character, "pageDown"))
+ gdkKeySym = GDK_KP_Page_Down;
+ else if (JSStringIsEqualToUTF8CString(character, "home"))
+ gdkKeySym = GDK_KP_Home;
+ else if (JSStringIsEqualToUTF8CString(character, "end"))
+ gdkKeySym = GDK_KP_End;
+ else if (JSStringIsEqualToUTF8CString(character, "insert"))
+ gdkKeySym = GDK_KP_Insert;
+ else if (JSStringIsEqualToUTF8CString(character, "delete"))
+ gdkKeySym = GDK_KP_Delete;
+ else
+ // If we get some other key specified with the numpad location,
+ // crash here, so we add it sooner rather than later.
+ g_assert_not_reached();
+ } else {
+ if (JSStringIsEqualToUTF8CString(character, "leftArrow"))
+ gdkKeySym = GDK_Left;
+ else if (JSStringIsEqualToUTF8CString(character, "rightArrow"))
+ gdkKeySym = GDK_Right;
+ else if (JSStringIsEqualToUTF8CString(character, "upArrow"))
+ gdkKeySym = GDK_Up;
+ else if (JSStringIsEqualToUTF8CString(character, "downArrow"))
+ gdkKeySym = GDK_Down;
+ else if (JSStringIsEqualToUTF8CString(character, "pageUp"))
+ gdkKeySym = GDK_Page_Up;
+ else if (JSStringIsEqualToUTF8CString(character, "pageDown"))
+ gdkKeySym = GDK_Page_Down;
+ else if (JSStringIsEqualToUTF8CString(character, "home"))
+ gdkKeySym = GDK_Home;
+ else if (JSStringIsEqualToUTF8CString(character, "end"))
+ gdkKeySym = GDK_End;
+ else if (JSStringIsEqualToUTF8CString(character, "insert"))
+ gdkKeySym = GDK_Insert;
+ else if (JSStringIsEqualToUTF8CString(character, "delete"))
+ gdkKeySym = GDK_Delete;
+ else if (JSStringIsEqualToUTF8CString(character, "printScreen"))
+ gdkKeySym = GDK_Print;
+ else if (JSStringIsEqualToUTF8CString(character, "menu"))
+ gdkKeySym = GDK_Menu;
+ else if (JSStringIsEqualToUTF8CString(character, "F1"))
+ gdkKeySym = GDK_F1;
+ else if (JSStringIsEqualToUTF8CString(character, "F2"))
+ gdkKeySym = GDK_F2;
+ else if (JSStringIsEqualToUTF8CString(character, "F3"))
+ gdkKeySym = GDK_F3;
+ else if (JSStringIsEqualToUTF8CString(character, "F4"))
+ gdkKeySym = GDK_F4;
+ else if (JSStringIsEqualToUTF8CString(character, "F5"))
+ gdkKeySym = GDK_F5;
+ else if (JSStringIsEqualToUTF8CString(character, "F6"))
+ gdkKeySym = GDK_F6;
+ else if (JSStringIsEqualToUTF8CString(character, "F7"))
+ gdkKeySym = GDK_F7;
+ else if (JSStringIsEqualToUTF8CString(character, "F8"))
+ gdkKeySym = GDK_F8;
+ else if (JSStringIsEqualToUTF8CString(character, "F9"))
+ gdkKeySym = GDK_F9;
+ else if (JSStringIsEqualToUTF8CString(character, "F10"))
+ gdkKeySym = GDK_F10;
+ else if (JSStringIsEqualToUTF8CString(character, "F11"))
+ gdkKeySym = GDK_F11;
+ else if (JSStringIsEqualToUTF8CString(character, "F12"))
+ gdkKeySym = GDK_F12;
+ else {
+ int charCode = JSStringGetCharactersPtr(character)[0];
+ if (charCode == '\n' || charCode == '\r')
+ gdkKeySym = GDK_Return;
+ else if (charCode == '\t')
+ gdkKeySym = GDK_Tab;
+ else if (charCode == '\x8')
+ gdkKeySym = GDK_BackSpace;
+ else {
+ gdkKeySym = gdk_unicode_to_keyval(charCode);
+ if (WTF::isASCIIUpper(charCode))
+ modifiers |= GDK_SHIFT_MASK;
+ }
+ }
+ }
+ JSStringRelease(character);
+
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ // create and send the event
+ GdkEvent* pressEvent = gdk_event_new(GDK_KEY_PRESS);
+ pressEvent->key.keyval = gdkKeySym;
+ pressEvent->key.state = modifiers;
+ pressEvent->key.window = gtk_widget_get_window(GTK_WIDGET(view));
+ g_object_ref(pressEvent->key.window);
+#ifndef GTK_API_VERSION_2
+ gdk_event_set_device(pressEvent, getDefaultGDKPointerDevice(pressEvent->key.window));
+#endif
+
+ // When synthesizing an event, an invalid hardware_keycode value
+ // can cause it to be badly processed by Gtk+.
+ GdkKeymapKey* keys;
+ gint n_keys;
+ if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), gdkKeySym, &keys, &n_keys)) {
+ pressEvent->key.hardware_keycode = keys[0].keycode;
+ g_free(keys);
+ }
+
+ GdkEvent* releaseEvent = gdk_event_copy(pressEvent);
+ dispatchEvent(pressEvent);
+ releaseEvent->key.type = GDK_KEY_RELEASE;
+ dispatchEvent(releaseEvent);
+
+ return JSValueMakeUndefined(context);
+}
+
+static void zoomIn(gboolean fullContentsZoom)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return;
+
+ webkit_web_view_set_full_content_zoom(view, fullContentsZoom);
+ gfloat currentZoom = webkit_web_view_get_zoom_level(view);
+ webkit_web_view_set_zoom_level(view, currentZoom * zoomMultiplierRatio);
+}
+
+static void zoomOut(gboolean fullContentsZoom)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return;
+
+ webkit_web_view_set_full_content_zoom(view, fullContentsZoom);
+ gfloat currentZoom = webkit_web_view_get_zoom_level(view);
+ webkit_web_view_set_zoom_level(view, currentZoom / zoomMultiplierRatio);
+}
+
+static JSValueRef textZoomInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ zoomIn(FALSE);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef textZoomOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ zoomOut(FALSE);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef zoomPageInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ zoomIn(TRUE);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef zoomPageOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ zoomOut(TRUE);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef scalePageByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 3)
+ return JSValueMakeUndefined(context);
+
+ float scaleFactor = JSValueToNumber(context, arguments[0], exception);
+ float x = JSValueToNumber(context, arguments[1], exception);
+ float y = JSValueToNumber(context, arguments[2], exception);
+
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ DumpRenderTreeSupportGtk::scalePageBy(view, scaleFactor, x, y);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSStaticFunction staticFunctions[] = {
+ { "mouseScrollBy", mouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "continuousMouseScrollBy", continuousMouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "contextClick", contextClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "beginDragWithFiles", beginDragWithFilesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "leapForward", leapForwardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textZoomIn", textZoomInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textZoomOut", textZoomOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "zoomPageIn", zoomPageInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "zoomPageOut", zoomPageOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scheduleAsynchronousClick", scheduleAsynchronousClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "scalePageBy", scalePageByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+
+ { 0, 0, 0 }
+};
+
+static JSStaticValue staticValues[] = {
+ { "dragMode", getDragModeCallback, setDragModeCallback, kJSPropertyAttributeNone },
+ { 0, 0, 0, 0 }
+};
+
+static JSClassRef getClass(JSContextRef context)
+{
+ static JSClassRef eventSenderClass = 0;
+
+ if (!eventSenderClass) {
+ JSClassDefinition classDefinition = {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ classDefinition.staticFunctions = staticFunctions;
+ classDefinition.staticValues = staticValues;
+
+ eventSenderClass = JSClassCreate(&classDefinition);
+ }
+
+ return eventSenderClass;
+}
+
+JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame)
+{
+ if (isTopFrame) {
+ dragMode = true;
+
+ // Fly forward in time one second when the main frame loads. This will
+ // ensure that when a test begins clicking in the same location as
+ // a previous test, those clicks won't be interpreted as continuations
+ // of the previous test's click sequences.
+ timeOffset += 1000;
+
+ lastMousePositionX = lastMousePositionY = 0;
+ lastClickPositionX = lastClickPositionY = 0;
+ lastClickTimeOffset = 0;
+ lastClickButton = 0;
+ buttonCurrentlyDown = 0;
+ clickCount = 0;
+
+ endOfQueue = 0;
+ startOfQueue = 0;
+
+ currentDragSourceContext = 0;
+ }
+
+ return JSObjectMake(context, getClass(context), 0);
+}
+
+void dragBeginCallback(GtkWidget*, GdkDragContext* context, gpointer)
+{
+ currentDragSourceContext = context;
+}
+
+void dragEndCallback(GtkWidget*, GdkDragContext* context, gpointer)
+{
+ currentDragSourceContext = 0;
+}
+
+gboolean dragFailedCallback(GtkWidget*, GdkDragContext* context, gpointer)
+{
+ // Return TRUE here to disable the stupid GTK+ drag failed animation,
+ // which introduces asynchronous behavior into our drags.
+ return TRUE;
+}
diff --git a/Tools/DumpRenderTree/gtk/EventSender.h b/Tools/DumpRenderTree/gtk/EventSender.h
new file mode 100644
index 000000000..f440f0d3d
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/EventSender.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 EventSender_h
+#define EventSender_h
+
+typedef const struct OpaqueJSContext* JSContextRef;
+typedef struct OpaqueJSValue* JSObjectRef;
+
+JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame);
+void replaySavedEvents();
+void dragBeginCallback(GtkWidget*, GdkDragContext*, gpointer);
+void dragEndCallback(GtkWidget*, GdkDragContext*, gpointer);
+gboolean dragFailedCallback(GtkWidget*, GdkDragContext*, gpointer);
+
+#endif
diff --git a/Tools/DumpRenderTree/gtk/GCControllerGtk.cpp b/Tools/DumpRenderTree/gtk/GCControllerGtk.cpp
new file mode 100644
index 000000000..4eb5d6ec9
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/GCControllerGtk.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h"
+
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+
+#include <glib.h>
+#include <webkit/webkit.h>
+
+void GCController::collect() const
+{
+ DumpRenderTreeSupportGtk::gcCollectJavascriptObjects();
+}
+
+void GCController::collectOnAlternateThread(bool waitUntilDone) const
+{
+ DumpRenderTreeSupportGtk::gcCollectJavascriptObjectsOnAlternateThread(waitUntilDone);
+}
+
+size_t GCController::getJSObjectCount() const
+{
+ return DumpRenderTreeSupportGtk::gcCountJavascriptObjects();
+}
diff --git a/Tools/DumpRenderTree/gtk/GNUmakefile.ImageDiff.am b/Tools/DumpRenderTree/gtk/GNUmakefile.ImageDiff.am
new file mode 100644
index 000000000..e7c3aefc0
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/GNUmakefile.ImageDiff.am
@@ -0,0 +1,28 @@
+noinst_PROGRAMS += \
+ Programs/ImageDiff
+
+Programs_ImageDiff_CPPFLAGS = $(global_cppflags)
+
+Programs_ImageDiff_SOURCES = \
+ Tools/DumpRenderTree/gtk/ImageDiff.cpp
+
+Programs_ImageDiff_CXXFLAGS = \
+ $(global_cxxflags) \
+ $(global_cppflags) \
+ $(Programs_ImageDiff_CFLAGS)
+
+Programs_ImageDiff_CFLAGS = \
+ -fno-strict-aliasing \
+ $(global_cflags) \
+ $(GLOBALDEPS_CFLAGS) \
+ $(GTK_CFLAGS)
+
+Programs_ImageDiff_LDADD = \
+ $(GTK_LIBS)
+
+Programs_ImageDiff_LDFLAGS = \
+ -no-fast-install \
+ -no-install
+
+CLEANFILES += \
+ Programs/ImageDiff
diff --git a/Tools/DumpRenderTree/gtk/ImageDiff.cpp b/Tools/DumpRenderTree/gtk/ImageDiff.cpp
new file mode 100644
index 000000000..7e2744a05
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/ImageDiff.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 <algorithm>
+#include <cmath>
+#include <cstdio>
+#include <cstring>
+#include <gdk/gdk.h>
+
+using namespace std;
+
+static double tolerance = 0;
+static GOptionEntry commandLineOptionEntries[] =
+{
+ { "tolerance", 0, 0, G_OPTION_ARG_DOUBLE, &tolerance, "Percentage difference between images before considering them different", "T" },
+ { 0, 0, 0, G_OPTION_ARG_NONE, 0, 0, 0 },
+};
+
+GdkPixbuf* readPixbufFromStdin(long imageSize)
+{
+ unsigned char imageBuffer[2048];
+ GdkPixbufLoader* loader = gdk_pixbuf_loader_new_with_type("png", 0);
+ GError* error = 0;
+
+ while (imageSize > 0) {
+ size_t bytesToRead = min<int>(imageSize, 2048);
+ size_t bytesRead = fread(imageBuffer, 1, bytesToRead, stdin);
+
+ if (!gdk_pixbuf_loader_write(loader, reinterpret_cast<const guchar*>(imageBuffer), bytesRead, &error)) {
+ g_error_free(error);
+ gdk_pixbuf_loader_close(loader, 0);
+ g_object_unref(loader);
+ return 0;
+ }
+
+ imageSize -= static_cast<int>(bytesRead);
+ }
+
+ gdk_pixbuf_loader_close(loader, 0);
+ GdkPixbuf* decodedImage = gdk_pixbuf_loader_get_pixbuf(loader);
+ g_object_ref(decodedImage);
+ return decodedImage;
+}
+
+GdkPixbuf* differenceImageFromDifferenceBuffer(unsigned char* buffer, int width, int height)
+{
+ GdkPixbuf* image = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height);
+ if (!image)
+ return image;
+
+ int rowStride = gdk_pixbuf_get_rowstride(image);
+ unsigned char* diffPixels = gdk_pixbuf_get_pixels(image);
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ unsigned char* diffPixel = diffPixels + (y * rowStride) + (x * 3);
+ diffPixel[0] = diffPixel[1] = diffPixel[2] = *buffer++;
+ }
+ }
+
+ return image;
+}
+
+float calculateDifference(GdkPixbuf* baselineImage, GdkPixbuf* actualImage, GdkPixbuf** differenceImage)
+{
+ int width = gdk_pixbuf_get_width(actualImage);
+ int height = gdk_pixbuf_get_height(actualImage);
+ int numberOfChannels = gdk_pixbuf_get_n_channels(actualImage);
+ if ((width != gdk_pixbuf_get_width(baselineImage))
+ || (height != gdk_pixbuf_get_height(baselineImage))
+ || (numberOfChannels != gdk_pixbuf_get_n_channels(baselineImage))
+ || (gdk_pixbuf_get_has_alpha(actualImage) != gdk_pixbuf_get_has_alpha(baselineImage))) {
+ fprintf(stderr, "Error, test and reference image have different properties.\n");
+ return 100; // Completely different.
+ }
+
+ unsigned char* diffBuffer = static_cast<unsigned char*>(malloc(width * height));
+ float count = 0;
+ float sum = 0;
+ float maxDistance = 0;
+ int actualRowStride = gdk_pixbuf_get_rowstride(actualImage);
+ int baseRowStride = gdk_pixbuf_get_rowstride(baselineImage);
+ unsigned char* actualPixels = gdk_pixbuf_get_pixels(actualImage);
+ unsigned char* basePixels = gdk_pixbuf_get_pixels(baselineImage);
+ unsigned char* currentDiffPixel = diffBuffer;
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ unsigned char* actualPixel = actualPixels + (y * actualRowStride) + (x * numberOfChannels);
+ unsigned char* basePixel = basePixels + (y * baseRowStride) + (x * numberOfChannels);
+
+ float red = (actualPixel[0] - basePixel[0]) / max<float>(255 - basePixel[0], basePixel[0]);
+ float green = (actualPixel[1] - basePixel[1]) / max<float>(255 - basePixel[1], basePixel[1]);
+ float blue = (actualPixel[2] - basePixel[2]) / max<float>(255 - basePixel[2], basePixel[2]);
+ float alpha = (actualPixel[3] - basePixel[3]) / max<float>(255 - basePixel[3], basePixel[3]);
+ float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f;
+
+ *currentDiffPixel++ = (unsigned char)(distance * 255.0f);
+
+ if (distance >= 1.0f / 255.0f) {
+ count += 1.0f;
+ sum += distance;
+ maxDistance = max<float>(maxDistance, distance);
+ }
+ }
+ }
+
+ // Compute the difference as a percentage combining both the number of
+ // different pixels and their difference amount i.e. the average distance
+ // over the entire image
+ float difference = 0;
+ if (count > 0.0f)
+ difference = 100.0f * sum / (height * width);
+ if (difference <= tolerance)
+ difference = 0;
+ else {
+ difference = roundf(difference * 100.0f) / 100.0f;
+ difference = max(difference, 0.01f); // round to 2 decimal places
+ *differenceImage = differenceImageFromDifferenceBuffer(diffBuffer, width, height);
+ }
+
+ free(diffBuffer);
+ return difference;
+}
+
+void printImage(GdkPixbuf* image)
+{
+ char* buffer;
+ gsize bufferSize;
+ GError* error = 0;
+ if (!gdk_pixbuf_save_to_buffer(image, &buffer, &bufferSize, "png", &error, NULL)) {
+ g_error_free(error);
+ return; // Don't bail out, as we can still use the percentage output.
+ }
+
+ printf("Content-Length: %"G_GSIZE_FORMAT"\n", bufferSize);
+ fwrite(buffer, 1, bufferSize, stdout);
+}
+
+void printImageDifferences(GdkPixbuf* baselineImage, GdkPixbuf* actualImage)
+{
+ GdkPixbuf* differenceImage = 0;
+ float difference = calculateDifference(baselineImage, actualImage, &differenceImage);
+ if (difference > 0.0f) {
+ if (differenceImage) {
+ printImage(differenceImage);
+ g_object_unref(differenceImage);
+ }
+ printf("diff: %01.2f%% failed\n", difference);
+ } else {
+ printf("diff: %01.2f%% passed\n", difference);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ gdk_init(&argc, &argv);
+
+ GError* error = 0;
+ GOptionContext* context = g_option_context_new("- compare two image files, printing their percentage difference and the difference image to stdout");
+ g_option_context_add_main_entries(context, commandLineOptionEntries, 0);
+ if (!g_option_context_parse(context, &argc, &argv, &error)) {
+ printf("Option parsing failed: %s\n", error->message);
+ g_error_free(error);
+ return 1;
+ }
+
+ GdkPixbuf* actualImage = 0;
+ GdkPixbuf* baselineImage = 0;
+ char buffer[2048];
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ // Convert the first newline into a NUL character so that strtok doesn't produce it.
+ char* newLineCharacter = strchr(buffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (!strncmp("Content-Length: ", buffer, 16)) {
+ gchar** tokens = g_strsplit(buffer, " ", 0);
+ if (!tokens[1]) {
+ g_strfreev(tokens);
+ printf("Error, image size must be specified..\n");
+ return 1;
+ }
+
+ long imageSize = strtol(tokens[1], 0, 10);
+ g_strfreev(tokens);
+ if (imageSize > 0 && !actualImage) {
+ if (!(actualImage = readPixbufFromStdin(imageSize))) {
+ printf("Error, could not read actual image.\n");
+ return 1;
+ }
+ } else if (imageSize > 0 && !baselineImage) {
+ if (!(baselineImage = readPixbufFromStdin(imageSize))) {
+ printf("Error, could not read baseline image.\n");
+ return 1;
+ }
+ } else {
+ printf("Error, image size must be specified..\n");
+ return 1;
+ }
+ }
+
+ if (actualImage && baselineImage) {
+ printImageDifferences(baselineImage, actualImage);
+ g_object_unref(actualImage);
+ g_object_unref(baselineImage);
+ actualImage = 0;
+ baselineImage = 0;
+ }
+
+ fflush(stdout);
+ }
+
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp b/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
new file mode 100644
index 000000000..7c133fd30
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
@@ -0,0 +1,1038 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Michael Alonzo <jmalonzo@gmail.com>
+ * Copyright (C) 2009,2011 Collabora Ltd.
+ * Copyright (C) 2010 Joone Hur <joone@kldp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "LayoutTestController.h"
+
+#include "DumpRenderTree.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include "WorkQueue.h"
+#include "WorkQueueItem.h"
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <stdio.h>
+#include <glib.h>
+#include <libsoup/soup.h>
+#include <webkit/webkit.h>
+#include <wtf/gobject/GOwnPtr.h>
+
+extern "C" {
+void webkit_web_inspector_execute_script(WebKitWebInspector* inspector, long callId, const gchar* script);
+}
+
+LayoutTestController::~LayoutTestController()
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::addDisallowedURL(JSStringRef url)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::clearBackForwardList()
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
+ WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_current_item(list);
+ g_object_ref(item);
+
+ // We clear the history by setting the back/forward list's capacity to 0
+ // then restoring it back and adding back the current item.
+ gint limit = webkit_web_back_forward_list_get_limit(list);
+ webkit_web_back_forward_list_set_limit(list, 0);
+ webkit_web_back_forward_list_set_limit(list, limit);
+ webkit_web_back_forward_list_add_item(list, item);
+ webkit_web_back_forward_list_go_to_item(list, item);
+ g_object_unref(item);
+}
+
+JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name)
+{
+ // FIXME: implement
+ return 0;
+}
+
+JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name)
+{
+ // FIXME: implement
+ return 0;
+}
+
+void LayoutTestController::dispatchPendingLoadRequests()
+{
+ // FIXME: Implement for testing fix for 6727495
+}
+
+void LayoutTestController::display()
+{
+ displayWebView();
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id)
+{
+ gchar* idGChar = JSStringCopyUTF8CString(id);
+ CString counterValueGChar = DumpRenderTreeSupportGtk::counterValueForElementById(mainFrame, idGChar);
+ g_free(idGChar);
+ if (counterValueGChar.isNull())
+ return 0;
+ JSRetainPtr<JSStringRef> counterValue(Adopt, JSStringCreateWithUTF8CString(counterValueGChar.data()));
+ return counterValue;
+}
+
+void LayoutTestController::keepWebHistory()
+{
+ // FIXME: implement
+}
+
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value)
+{
+ // FIXME: Implement this.
+ return JSValueMakeUndefined(context);
+}
+
+JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping)
+{
+ return DumpRenderTreeSupportGtk::nodesFromRect(context, value, x, y, top, right, bottom, left, ignoreClipping);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ // FIXME: implement
+ JSRetainPtr<JSStringRef> string(Adopt, JSStringCreateWithUTF8CString(""));
+ return string;
+}
+
+int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidth, float pageHeight)
+{
+ gchar* idGChar = JSStringCopyUTF8CString(id);
+ int pageNumber = DumpRenderTreeSupportGtk::pageNumberForElementById(mainFrame, idGChar, pageWidth, pageHeight);
+ g_free(idGChar);
+ return pageNumber;
+}
+
+int LayoutTestController::numberOfPages(float pageWidth, float pageHeight)
+{
+ return DumpRenderTreeSupportGtk::numberOfPagesForFrame(mainFrame, pageWidth, pageHeight);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const
+{
+ JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithUTF8CString(DumpRenderTreeSupportGtk::pageProperty(mainFrame, propertyName, pageNumber).data()));
+ return propertyValue;
+}
+
+bool LayoutTestController::isPageBoxVisible(int pageNumber) const
+{
+ return DumpRenderTreeSupportGtk::isPageBoxVisible(mainFrame, pageNumber);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const
+{
+ JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithUTF8CString(DumpRenderTreeSupportGtk::pageSizeAndMarginsInPixels(mainFrame, pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft).data()));
+ return propertyValue;
+}
+
+size_t LayoutTestController::webHistoryItemCount()
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
+
+ if (!list)
+ return -1;
+
+ // We do not add the current page to the total count as it's not
+ // considered in DRT tests
+ return webkit_web_back_forward_list_get_back_length(list) +
+ webkit_web_back_forward_list_get_forward_length(list);
+}
+
+unsigned LayoutTestController::workerThreadCount() const
+{
+ return DumpRenderTreeSupportGtk::workerThreadCount();
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::platformName() const
+{
+ JSRetainPtr<JSStringRef> platformName(Adopt, JSStringCreateWithUTF8CString("gtk"));
+ return platformName;
+}
+
+void LayoutTestController::notifyDone()
+{
+ if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
+ dump();
+ m_waitToDump = false;
+ waitForPolicy = false;
+}
+
+JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url)
+{
+ GOwnPtr<char> urlCString(JSStringCopyUTF8CString(url));
+ if (!g_str_has_prefix(urlCString.get(), "file:///tmp/LayoutTests/"))
+ return JSStringRetain(url);
+
+ const char* layoutTestsSuffix = urlCString.get() + strlen("file:///tmp/");
+ GOwnPtr<char> testPath(g_build_filename(getTopLevelPath().data(), layoutTestsSuffix, NULL));
+ GOwnPtr<char> testURI(g_filename_to_uri(testPath.get(), 0, 0));
+ return JSStringCreateWithUTF8CString(testURI.get());
+}
+
+void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target)
+{
+ gchar* relativeURL = JSStringCopyUTF8CString(url);
+ SoupURI* baseURI = soup_uri_new(webkit_web_frame_get_uri(mainFrame));
+
+ SoupURI* absoluteURI = soup_uri_new_with_base(baseURI, relativeURL);
+ soup_uri_free(baseURI);
+ g_free(relativeURL);
+
+ gchar* absoluteCString;
+ if (absoluteURI) {
+ absoluteCString = soup_uri_to_string(absoluteURI, FALSE);
+ soup_uri_free(absoluteURI);
+ } else
+ absoluteCString = JSStringCopyUTF8CString(url);
+
+ JSRetainPtr<JSStringRef> absoluteURL(Adopt, JSStringCreateWithUTF8CString(absoluteCString));
+ g_free(absoluteCString);
+
+ WorkQueue::shared()->queue(new LoadItem(absoluteURL.get(), target));
+}
+
+void LayoutTestController::setAcceptsEditing(bool acceptsEditing)
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ webkit_web_view_set_editable(webView, acceptsEditing);
+}
+
+void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
+{
+ SoupSession* session = webkit_get_default_session();
+ SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
+
+ /* If the jar was not created - we create it on demand, i.e, just
+ in case we have HTTP requests - then we must create it here in
+ order to set the proper accept policy */
+ if (!jar) {
+ jar = soup_cookie_jar_new();
+ soup_session_add_feature(session, SOUP_SESSION_FEATURE(jar));
+ g_object_unref(jar);
+ }
+
+ SoupCookieJarAcceptPolicy policy;
+
+ if (alwaysAcceptCookies)
+ policy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
+ else
+ policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
+
+ g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, policy, NULL);
+}
+
+void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::waitForPolicyDelegate()
+{
+ waitForPolicy = true;
+ setWaitToDump(true);
+}
+
+void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains)
+{
+ gchar* sourceOriginGChar = JSStringCopyUTF8CString(sourceOrigin);
+ gchar* protocolGChar = JSStringCopyUTF8CString(protocol);
+ gchar* hostGChar = JSStringCopyUTF8CString(host);
+ DumpRenderTreeSupportGtk::whiteListAccessFromOrigin(sourceOriginGChar, protocolGChar, hostGChar, includeSubdomains);
+ g_free(sourceOriginGChar);
+ g_free(protocolGChar);
+ g_free(hostGChar);
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles)
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
+ g_object_set(G_OBJECT(settings), "tab-key-cycles-through-elements", cycles, NULL);
+}
+
+void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
+{
+ // FIXME: implement
+}
+
+static gchar* userStyleSheet = NULL;
+static gboolean userStyleSheetEnabled = TRUE;
+
+void LayoutTestController::setUserStyleSheetEnabled(bool flag)
+{
+ userStyleSheetEnabled = flag;
+
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
+ if (flag && userStyleSheet)
+ g_object_set(G_OBJECT(settings), "user-stylesheet-uri", userStyleSheet, NULL);
+ else
+ g_object_set(G_OBJECT(settings), "user-stylesheet-uri", "", NULL);
+}
+
+void LayoutTestController::setUserStyleSheetLocation(JSStringRef path)
+{
+ g_free(userStyleSheet);
+ userStyleSheet = JSStringCopyUTF8CString(path);
+ if (userStyleSheetEnabled)
+ setUserStyleSheetEnabled(true);
+}
+
+void LayoutTestController::setValueForUser(JSContextRef context, JSValueRef nodeObject, JSStringRef value)
+{
+ DumpRenderTreeSupportGtk::setValueForUser(context, nodeObject, value);
+}
+
+void LayoutTestController::setViewModeMediaFeature(JSStringRef mode)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ char* viewMode = JSStringCopyUTF8CString(mode);
+
+ if (!g_strcmp0(viewMode, "windowed"))
+ webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_WINDOWED);
+ else if (!g_strcmp0(viewMode, "floating"))
+ webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_FLOATING);
+ else if (!g_strcmp0(viewMode, "fullscreen"))
+ webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_FULLSCREEN);
+ else if (!g_strcmp0(viewMode, "maximized"))
+ webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_MAXIMIZED);
+ else if (!g_strcmp0(viewMode, "minimized"))
+ webkit_web_view_set_view_mode(view, WEBKIT_WEB_VIEW_VIEW_MODE_MINIMIZED);
+
+ g_free(viewMode);
+}
+
+void LayoutTestController::setWindowIsKey(bool windowIsKey)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(bool flag)
+{
+ DumpRenderTreeSupportGtk::setSmartInsertDeleteEnabled(webkit_web_frame_get_web_view(mainFrame), flag);
+}
+
+static gboolean waitToDumpWatchdogFired(void*)
+{
+ waitToDumpWatchdog = 0;
+ gLayoutTestController->waitToDumpWatchdogTimerFired();
+ return FALSE;
+}
+
+void LayoutTestController::setWaitToDump(bool waitUntilDone)
+{
+ static const int timeoutSeconds = 30;
+
+ m_waitToDump = waitUntilDone;
+ if (m_waitToDump && !waitToDumpWatchdog)
+ waitToDumpWatchdog = g_timeout_add_seconds(timeoutSeconds, waitToDumpWatchdogFired, 0);
+}
+
+int LayoutTestController::windowCount()
+{
+ // +1 -> including the main view
+ return g_slist_length(webViewList) + 1;
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "enable-private-browsing", flag, NULL);
+}
+
+void LayoutTestController::setJavaScriptCanAccessClipboard(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "javascript-can-access-clipboard", flag, NULL);
+}
+
+void LayoutTestController::setXSSAuditorEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "enable-xss-auditor", flag, NULL);
+}
+
+void LayoutTestController::setFrameFlatteningEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "enable-frame-flattening", flag, NULL);
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "enable-spatial-navigation", flag, NULL);
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "enable-universal-access-from-file-uris", flag, NULL);
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "enable-file-access-from-file-uris", flag, NULL);
+}
+
+void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setAutofilled(JSContextRef context, JSValueRef nodeObject, bool isAutofilled)
+{
+ DumpRenderTreeSupportGtk::setAutofilled(context, nodeObject, isAutofilled);
+}
+
+void LayoutTestController::disableImageLoading()
+{
+ // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27896
+ // Also need to make sure image loading is re-enabled for each new test.
+}
+
+void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
+{
+ // FIXME: Implement for DeviceOrientation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=30335.
+}
+
+void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
+{
+ WebKitWebView* view = WEBKIT_WEB_VIEW(g_slist_nth_data(webViewList, 0));
+ if (!view)
+ view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ DumpRenderTreeSupportGtk::setMockGeolocationPosition(view, latitude, longitude, accuracy);
+}
+
+void LayoutTestController::setMockGeolocationError(int code, JSStringRef message)
+{
+ WebKitWebView* view = WEBKIT_WEB_VIEW(g_slist_nth_data(webViewList, 0));
+ if (!view)
+ view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ GOwnPtr<gchar> cMessage(JSStringCopyUTF8CString(message));
+ DumpRenderTreeSupportGtk::setMockGeolocationError(view, code, cMessage.get());
+}
+
+void LayoutTestController::setGeolocationPermission(bool allow)
+{
+ setGeolocationPermissionCommon(allow);
+ WebKitWebView* view = WEBKIT_WEB_VIEW(g_slist_nth_data(webViewList, 0));
+ if (!view)
+ view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ DumpRenderTreeSupportGtk::setMockGeolocationPermission(view, allow);
+}
+
+int LayoutTestController::numberOfPendingGeolocationPermissionRequests()
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ return DumpRenderTreeSupportGtk::numberOfPendingGeolocationPermissionRequests(view);
+}
+
+void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::startSpeechInput(JSContextRef inputElement)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::setIconDatabaseEnabled(bool enabled)
+{
+ WebKitIconDatabase* database = webkit_get_icon_database();
+ if (enabled) {
+ GOwnPtr<gchar> iconDatabasePath(g_build_filename(g_get_tmp_dir(), "DumpRenderTree", "icondatabase", NULL));
+ webkit_icon_database_set_path(database, iconDatabasePath.get());
+ } else
+ webkit_icon_database_set_path(database, 0);
+}
+
+void LayoutTestController::setJavaScriptProfilingEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ setDeveloperExtrasEnabled(flag);
+
+ WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
+ g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", flag, NULL);
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag)
+{
+ DumpRenderTreeSupportGtk::setSelectTrailingWhitespaceEnabled(flag);
+}
+
+void LayoutTestController::setPopupBlockingEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "javascript-can-open-windows-automatically", !flag, NULL);
+
+}
+
+void LayoutTestController::setPluginsEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "enable-plugins", flag, NULL);
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef id)
+{
+ // FIXME: implement
+ return false;
+}
+
+void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ gchar* cName = JSStringCopyUTF8CString(name);
+ gchar* cValue = JSStringCopyUTF8CString(value);
+ DumpRenderTreeSupportGtk::executeCoreCommandByName(view, cName, cValue);
+ g_free(cName);
+ g_free(cValue);
+}
+
+bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray)
+{
+ WebKitFindOptions findOptions = 0;
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(webView);
+
+ JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
+ JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
+ if (!JSValueIsNumber(context, lengthValue))
+ return false;
+
+ GOwnPtr<gchar> targetString(JSStringCopyUTF8CString(target));
+
+ size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
+ for (size_t i = 0; i < length; ++i) {
+ JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
+ if (!JSValueIsString(context, value))
+ continue;
+
+ JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0));
+
+ if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
+ findOptions |= WebKit::WebFindOptionsCaseInsensitive;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
+ findOptions |= WebKit::WebFindOptionsAtWordStarts;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
+ findOptions |= WebKit::WebFindOptionsTreatMedialCapitalAsWordStart;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
+ findOptions |= WebKit::WebFindOptionsBackwards;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
+ findOptions |= WebKit::WebFindOptionsWrapAround;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection"))
+ findOptions |= WebKit::WebFindOptionsStartInSelection;
+ }
+
+ return DumpRenderTreeSupportGtk::findString(webView, targetString.get(), findOptions);
+}
+
+bool LayoutTestController::isCommandEnabled(JSStringRef name)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ gchar* cName = JSStringCopyUTF8CString(name);
+ bool result = DumpRenderTreeSupportGtk::isCommandEnabled(view, cName);
+ g_free(cName);
+ return result;
+}
+
+void LayoutTestController::setCacheModel(int cacheModel)
+{
+ // These constants are derived from the Mac cache model enum in Source/WebKit/mac/WebView/WebPreferences.h.
+ switch (cacheModel) {
+ case 0:
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
+ break;
+ case 1:
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
+ break;
+ case 3:
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::clearPersistentUserStyleSheet()
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::clearAllApplicationCaches()
+{
+ // FIXME: Implement to support application cache quotas.
+}
+
+void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota)
+{
+ // FIXME: Implement to support application cache quotas.
+}
+
+void LayoutTestController::clearApplicationCacheForOrigin(OpaqueJSString*)
+{
+ // FIXME: Implement to support deleting all application caches for an origin.
+}
+
+long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef originIdentifier)
+{
+ // FIXME: Implement to support getting disk usage in bytes for an origin.
+ return 0;
+}
+
+JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context)
+{
+ // FIXME: Implement to get origins that contain application caches.
+ return JSValueMakeUndefined(context);
+}
+
+long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef name)
+{
+ // FIXME: implement
+ return 0;
+}
+
+void LayoutTestController::clearAllDatabases()
+{
+ webkit_remove_all_web_databases();
+}
+
+void LayoutTestController::setDatabaseQuota(unsigned long long quota)
+{
+ WebKitSecurityOrigin* origin = webkit_web_frame_get_security_origin(mainFrame);
+ webkit_security_origin_set_web_database_quota(origin, quota);
+}
+
+JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context)
+{
+ // FIXME: implement
+ return JSValueMakeUndefined(context);
+}
+
+void LayoutTestController::deleteAllLocalStorage()
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef originIdentifier)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::observeStorageTrackerNotifications(unsigned number)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::syncLocalStorage()
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool, JSStringRef)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::goBack()
+{
+ // FIXME: implement to enable loader/navigation-while-deferring-loads.html
+}
+
+void LayoutTestController::setDefersLoading(bool)
+{
+ // FIXME: implement to enable loader/navigation-while-deferring-loads.html
+}
+
+void LayoutTestController::setAppCacheMaximumSize(unsigned long long size)
+{
+ webkit_application_cache_set_maximum_size(size);
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
+{
+ gchar* name = JSStringCopyUTF8CString(animationName);
+ gchar* element = JSStringCopyUTF8CString(elementId);
+ bool returnValue = DumpRenderTreeSupportGtk::pauseAnimation(mainFrame, name, time, element);
+ g_free(name);
+ g_free(element);
+ return returnValue;
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId)
+{
+ gchar* name = JSStringCopyUTF8CString(propertyName);
+ gchar* element = JSStringCopyUTF8CString(elementId);
+ bool returnValue = DumpRenderTreeSupportGtk::pauseTransition(mainFrame, name, time, element);
+ g_free(name);
+ g_free(element);
+ return returnValue;
+}
+
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
+{
+ gchar* name = JSStringCopyUTF8CString(animationId);
+ gchar* element = JSStringCopyUTF8CString(elementId);
+ bool returnValue = DumpRenderTreeSupportGtk::pauseSVGAnimation(mainFrame, name, time, element);
+ g_free(name);
+ g_free(element);
+ return returnValue;
+}
+
+unsigned LayoutTestController::numberOfActiveAnimations() const
+{
+ return DumpRenderTreeSupportGtk::numberOfActiveAnimations(mainFrame);
+}
+
+void LayoutTestController::suspendAnimations() const
+{
+ DumpRenderTreeSupportGtk::suspendAnimations(mainFrame);
+}
+
+void LayoutTestController::resumeAnimations() const
+{
+ DumpRenderTreeSupportGtk::resumeAnimations(mainFrame);
+}
+
+void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value)
+{
+ GOwnPtr<gchar> originalName(JSStringCopyUTF8CString(key));
+ GOwnPtr<gchar> valueAsString(JSStringCopyUTF8CString(value));
+
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ // This transformation could be handled by a hash table (and it once was), but
+ // having it prominent, makes it easier for people from other ports to keep the
+ // list up to date.
+ const gchar* propertyName = 0;
+ if (g_str_equal(originalName.get(), "WebKitJavaScriptEnabled"))
+ propertyName = "enable-scripts";
+ else if (g_str_equal(originalName.get(), "WebKitDefaultFontSize"))
+ propertyName = "default-font-size";
+ else if (g_str_equal(originalName.get(), "WebKitEnableCaretBrowsing"))
+ propertyName = "enable-caret-browsing";
+ else if (g_str_equal(originalName.get(), "WebKitUsesPageCachePreferenceKey"))
+ propertyName = "enable-page-cache";
+ else if (g_str_equal(originalName.get(), "WebKitPluginsEnabled"))
+ propertyName = "enable-plugins";
+ else if (g_str_equal(originalName.get(), "WebKitHyperlinkAuditingEnabled"))
+ propertyName = "enable-hyperlink-auditing";
+ else if (g_str_equal(originalName.get(), "WebKitWebGLEnabled"))
+ propertyName = "enable-webgl";
+ else if (g_str_equal(originalName.get(), "WebKitWebAudioEnabled"))
+ propertyName = "enable-webaudio";
+ else if (g_str_equal(originalName.get(), "WebKitTabToLinksPreferenceKey")) {
+ DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(!g_ascii_strcasecmp(valueAsString.get(), "true") || !g_ascii_strcasecmp(valueAsString.get(), "1"));
+ return;
+ } else if (g_str_equal(originalName.get(), "WebKitHixie76WebSocketProtocolEnabled")) {
+ DumpRenderTreeSupportGtk::setHixie76WebSocketProtocolEnabled(webkit_web_frame_get_web_view(mainFrame), !g_ascii_strcasecmp(valueAsString.get(), "true") || !g_ascii_strcasecmp(valueAsString.get(), "1"));
+ return;
+ } else {
+ fprintf(stderr, "LayoutTestController::overridePreference tried to override "
+ "unknown preference '%s'.\n", originalName.get());
+ return;
+ }
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ GParamSpec* pspec = g_object_class_find_property(G_OBJECT_CLASS(
+ WEBKIT_WEB_SETTINGS_GET_CLASS(settings)), propertyName);
+ GValue currentPropertyValue = { 0, { { 0 } } };
+ g_value_init(&currentPropertyValue, pspec->value_type);
+
+ if (G_VALUE_HOLDS_STRING(&currentPropertyValue))
+ g_object_set(settings, propertyName, valueAsString.get(), NULL);
+ else if (G_VALUE_HOLDS_BOOLEAN(&currentPropertyValue))
+ g_object_set(G_OBJECT(settings), propertyName, !g_ascii_strcasecmp(valueAsString.get(), "true")
+ || !g_ascii_strcasecmp(valueAsString.get(), "1"), NULL);
+ else if (G_VALUE_HOLDS_INT(&currentPropertyValue))
+ g_object_set(G_OBJECT(settings), propertyName, atoi(valueAsString.get()), NULL);
+ else if (G_VALUE_HOLDS_FLOAT(&currentPropertyValue)) {
+ gfloat newValue = g_ascii_strtod(valueAsString.get(), 0);
+ g_object_set(G_OBJECT(settings), propertyName, newValue, NULL);
+ } else
+ fprintf(stderr, "LayoutTestController::overridePreference failed to override "
+ "preference '%s'.\n", originalName.get());
+}
+
+void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
+{
+ printf("LayoutTestController::addUserScript not implemented.\n");
+}
+
+void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames)
+{
+ GOwnPtr<gchar> sourceCode(JSStringCopyUTF8CString(source));
+ DumpRenderTreeSupportGtk::addUserStyleSheet(mainFrame, sourceCode.get(), allFrames);
+ // FIXME: needs more investigation why userscripts/user-style-top-frame-only.html fails when allFrames is false.
+
+}
+
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebSettings* webSettings = webkit_web_view_get_settings(webView);
+
+ g_object_set(webSettings, "enable-developer-extras", enabled, NULL);
+}
+
+void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool)
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::showWebInspector()
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
+
+ webkit_web_inspector_show(inspector);
+}
+
+void LayoutTestController::closeWebInspector()
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
+
+ webkit_web_inspector_close(inspector);
+}
+
+void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script)
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
+ char* scriptString = JSStringCopyUTF8CString(script);
+
+ webkit_web_inspector_execute_script(inspector, callId, scriptString);
+ g_free(scriptString);
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::removeAllVisitedLinks()
+{
+ // FIXME: Implement this.
+}
+
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ return DumpRenderTreeSupportGtk::shouldClose(mainFrame);
+}
+
+void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL)
+{
+
+}
+
+void LayoutTestController::apiTestGoToCurrentBackForwardItem()
+{
+
+}
+
+void LayoutTestController::setWebViewEditable(bool)
+{
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const
+{
+ CString markerTextGChar = DumpRenderTreeSupportGtk::markerTextForListItem(mainFrame, context, nodeObject);
+ if (markerTextGChar.isNull())
+ return 0;
+
+ JSRetainPtr<JSStringRef> markerText(Adopt, JSStringCreateWithUTF8CString(markerTextGChar.data()));
+ return markerText;
+}
+
+void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
+{
+}
+
+void LayoutTestController::setEditingBehavior(const char* editingBehavior)
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
+
+ if (!strcmp(editingBehavior, "win"))
+ g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_WINDOWS, NULL);
+ else if (!strcmp(editingBehavior, "mac"))
+ g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_MAC, NULL);
+ else if (!strcmp(editingBehavior, "unix"))
+ g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX, NULL);
+}
+
+void LayoutTestController::abortModal()
+{
+}
+
+bool LayoutTestController::hasSpellingMarker(int from, int length)
+{
+ return DumpRenderTreeSupportGtk::webkitWebFrameSelectionHasSpellingMarker(mainFrame, from, length);
+}
+
+bool LayoutTestController::hasGrammarMarker(int from, int length)
+{
+ return false;
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int deviceDPI, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight)
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(webView);
+ DumpRenderTreeSupportGtk::dumpConfigurationForViewport(webView, deviceDPI, deviceWidth, deviceHeight, availableWidth, availableHeight);
+}
+
+void LayoutTestController::setSerializeHTTPLoads(bool)
+{
+ // FIXME: Implement if needed for https://bugs.webkit.org/show_bug.cgi?id=50758.
+}
+
+void LayoutTestController::setMinimumTimerInterval(double minimumTimerInterval)
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ DumpRenderTreeSupportGtk::setMinimumTimerInterval(webView, minimumTimerInterval);
+}
+
+void LayoutTestController::setTextDirection(JSStringRef direction)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::allowRoundingHacks()
+{
+}
+
+void LayoutTestController::addChromeInputField()
+{
+}
+
+void LayoutTestController::removeChromeInputField()
+{
+}
+
+void LayoutTestController::focusWebView()
+{
+}
+
+void LayoutTestController::setBackingScaleFactor(double)
+{
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title)
+{
+}
diff --git a/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp
new file mode 100644
index 000000000..3eabfd96c
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h"
+#include "GtkVersioning.h"
+#include "PixelDumpSupportCairo.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include <webkit/webkit.h>
+
+PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool drawSelectionRect)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ GtkWidget* viewContainer = gtk_widget_get_parent(GTK_WIDGET(view));
+ gint width, height;
+#ifdef GTK_API_VERSION_2
+ GdkPixmap* pixmap = gtk_widget_get_snapshot(viewContainer, 0);
+ gdk_pixmap_get_size(pixmap, &width, &height);
+#else
+ width = gtk_widget_get_allocated_width(viewContainer);
+ height = gtk_widget_get_allocated_height(viewContainer);
+#endif
+
+ cairo_surface_t* imageSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ cairo_t* context = cairo_create(imageSurface);
+
+#ifdef GTK_API_VERSION_2
+ gdk_cairo_set_source_pixmap(context, pixmap, 0, 0);
+ cairo_paint(context);
+ g_object_unref(pixmap);
+#else
+ gtk_widget_draw(viewContainer, context);
+#endif
+
+ if (drawSelectionRect) {
+ cairo_rectangle_int_t rectangle;
+ DumpRenderTreeSupportGtk::rectangleForSelection(mainFrame, &rectangle);
+
+ cairo_set_line_width(context, 1.0);
+ cairo_rectangle(context, rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+ cairo_set_source_rgba(context, 1.0, 0.0, 0.0, 1.0);
+ cairo_stroke(context);
+ }
+
+ return BitmapContext::createByAdoptingBitmapAndContext(0, context);
+}
diff --git a/Tools/DumpRenderTree/gtk/PlainTextController.cpp b/Tools/DumpRenderTree/gtk/PlainTextController.cpp
new file mode 100644
index 000000000..25e251a75
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/PlainTextController.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "PlainTextController.h"
+
+#include "DumpRenderTree.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include <GOwnPtrGtk.h>
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <webkit/webkit.h>
+
+static JSValueRef plainTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ g_return_val_if_fail(argumentCount == 1, JSValueMakeUndefined(context));
+ WebKitDOMRange* kitRange = DumpRenderTreeSupportGtk::jsValueToDOMRange(context, arguments[0]);
+ g_return_val_if_fail(kitRange, JSValueMakeUndefined(context));
+
+ GOwnPtr<gchar> text(webkit_dom_range_get_text(kitRange));
+ JSRetainPtr<JSStringRef> jsText(Adopt, JSStringCreateWithUTF8CString(text.get()));
+ return JSValueMakeString(context, jsText.get());
+}
+
+JSObjectRef makePlainTextController(JSContextRef context)
+{
+ static JSStaticFunction staticFunctions[] = {
+ { "plainText", plainTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+ };
+
+ static JSClassRef plainTextControllerClass = 0;
+ if (!plainTextControllerClass) {
+ JSClassDefinition classDefinition = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ classDefinition.staticFunctions = staticFunctions;
+ plainTextControllerClass = JSClassCreate(&classDefinition);
+ }
+ return JSObjectMake(context, plainTextControllerClass, 0);
+}
diff --git a/Tools/DumpRenderTree/gtk/PlainTextController.h b/Tools/DumpRenderTree/gtk/PlainTextController.h
new file mode 100644
index 000000000..dadfc1392
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/PlainTextController.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PlainTextController_h
+#define PlainTextController_h
+
+typedef const struct OpaqueJSContext* JSContextRef;
+typedef struct OpaqueJSValue* JSObjectRef;
+
+JSObjectRef makePlainTextController(JSContextRef);
+
+#endif
diff --git a/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp
new file mode 100644
index 000000000..d77cfd5f1
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "SelfScrollingWebKitWebView.h"
+
+#include <webkit/webkit.h>
+
+G_BEGIN_DECLS
+
+#ifdef GTK_API_VERSION_2
+static void sizeRequestMethod(GtkWidget*, GtkRequisition*);
+#else
+static void getPreferredSizeMethod(GtkWidget*, gint* minimum, gint* natural);
+#endif
+
+G_DEFINE_TYPE(SelfScrollingWebKitWebView, self_scrolling_webkit_web_view, WEBKIT_TYPE_WEB_VIEW)
+
+static void self_scrolling_webkit_web_view_class_init(SelfScrollingWebKitWebViewClass* klass)
+{
+ GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(klass);
+#ifdef GTK_API_VERSION_2
+ widgetClass->size_request = sizeRequestMethod;
+#else
+ widgetClass->get_preferred_width = getPreferredSizeMethod;
+ widgetClass->get_preferred_height = getPreferredSizeMethod;
+#endif
+}
+
+static void self_scrolling_webkit_web_view_init(SelfScrollingWebKitWebView* webView)
+{
+}
+
+GtkWidget* self_scrolling_webkit_web_view_new()
+{
+ return GTK_WIDGET(g_object_new(self_scrolling_webkit_web_view_get_type(), "self-scrolling", TRUE, NULL));
+}
+
+#ifdef GTK_API_VERSION_2
+static void sizeRequestMethod(GtkWidget*, GtkRequisition* requisition)
+{
+ requisition->width = 1;
+ requisition->height = 1;
+}
+#else
+static void getPreferredSizeMethod(GtkWidget*, gint* minimum, gint* natural)
+{
+ *minimum = 1;
+ *natural = 1;
+}
+#endif
+
+G_END_DECLS
diff --git a/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h
new file mode 100644
index 000000000..648d38c97
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/SelfScrollingWebKitWebView.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 SelfScrollingWebKitWebView_h
+#define SelfScrollingWebKitWebView_h
+
+#include <webkit/webkit.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SelfScrollingWebKitWebView SelfScrollingWebKitWebView;
+typedef struct _SelfScrollingWebKitWebViewClass SelfScrollingWebKitWebViewClass;
+
+struct _SelfScrollingWebKitWebView {
+ WebKitWebView web_view;
+};
+
+struct _SelfScrollingWebKitWebViewClass {
+ WebKitWebViewClass parent_class;
+};
+
+GtkWidget* self_scrolling_webkit_web_view_new();
+
+G_END_DECLS
+
+#endif // SelfScrollingWebKitWebView_h
diff --git a/Tools/DumpRenderTree/gtk/TextInputController.cpp b/Tools/DumpRenderTree/gtk/TextInputController.cpp
new file mode 100644
index 000000000..eed3bbe54
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/TextInputController.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "TextInputController.h"
+
+#include "DumpRenderTree.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include <GOwnPtrGtk.h>
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <cstring>
+#include <webkit/webkit.h>
+
+static JSValueRef setMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+ if (argumentCount < 3)
+ return JSValueMakeUndefined(context);
+
+ JSStringRef string = JSValueToStringCopy(context, arguments[0], exception);
+ ASSERT(!exception || !*exception);
+
+ size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string);
+ GOwnPtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
+ JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize);
+ JSStringRelease(string);
+
+ int start = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
+ ASSERT(!exception || !*exception);
+
+ int length = static_cast<int>(JSValueToNumber(context, arguments[2], exception));
+ ASSERT(!exception || !*exception);
+
+ DumpRenderTreeSupportGtk::setComposition(view, stringBuffer.get(), start, length);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef hasMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+ return JSValueMakeBoolean(context, DumpRenderTreeSupportGtk::hasComposition(view));
+}
+
+static JSValueRef markedRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ int start, length;
+ if (!DumpRenderTreeSupportGtk::compositionRange(view, &start, &length))
+ return JSValueMakeUndefined(context);
+
+ JSValueRef arrayValues[2];
+ arrayValues[0] = JSValueMakeNumber(context, start);
+ arrayValues[1] = JSValueMakeNumber(context, length);
+ JSObjectRef arrayObject = JSObjectMakeArray(context, 2, arrayValues, exception);
+ ASSERT(!exception || !*exception);
+ return arrayObject;
+}
+
+static JSValueRef insertTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSStringRef string = JSValueToStringCopy(context, arguments[0], exception);
+ ASSERT(!exception || !*exception);
+
+ size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string);
+ GOwnPtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
+ JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize);
+ JSStringRelease(string);
+
+ DumpRenderTreeSupportGtk::confirmComposition(view, stringBuffer.get());
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef unmarkTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ DumpRenderTreeSupportGtk::confirmComposition(view, 0);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef firstRectForCharacterRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ int location = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+ ASSERT(!exception || !*exception);
+
+ int length = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
+ ASSERT(!exception || !*exception);
+
+ cairo_rectangle_int_t rect;
+ if (!DumpRenderTreeSupportGtk::firstRectForCharacterRange(view, location, length, &rect))
+ return JSValueMakeUndefined(context);
+
+ JSValueRef arrayValues[4];
+ arrayValues[0] = JSValueMakeNumber(context, rect.x);
+ arrayValues[1] = JSValueMakeNumber(context, rect.y);
+ arrayValues[2] = JSValueMakeNumber(context, rect.width);
+ arrayValues[3] = JSValueMakeNumber(context, rect.height);
+ JSObjectRef arrayObject = JSObjectMakeArray(context, 4, arrayValues, exception);
+ ASSERT(!exception || !*exception);
+
+ return arrayObject;
+}
+
+static JSValueRef selectedRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ int start, length;
+ if (!DumpRenderTreeSupportGtk::selectedRange(view, &start, &length))
+ return JSValueMakeUndefined(context);
+
+ JSValueRef arrayValues[2];
+ arrayValues[0] = JSValueMakeNumber(context, start);
+ arrayValues[1] = JSValueMakeNumber(context, length);
+ JSObjectRef arrayObject = JSObjectMakeArray(context, 2, arrayValues, exception);
+ ASSERT(!exception || !*exception);
+
+ return arrayObject;
+}
+
+static JSValueRef doCommandCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSStringRef string = JSValueToStringCopy(context, arguments[0], exception);
+ ASSERT(!exception || !*exception);
+
+ size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string);
+ GOwnPtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
+ JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize);
+ JSStringRelease(string);
+
+ DumpRenderTreeSupportGtk::doCommand(view, stringBuffer.get());
+ return JSValueMakeUndefined(context);
+}
+
+static JSStaticFunction staticFunctions[] = {
+ { "setMarkedText", setMarkedTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "hasMarkedText", hasMarkedTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "markedRange", markedRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "insertText", insertTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "unmarkText", unmarkTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "firstRectForCharacterRange", firstRectForCharacterRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "selectedRange", selectedRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "doCommand", doCommandCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+};
+
+static JSClassRef getClass(JSContextRef context)
+{
+ static JSClassRef textInputControllerClass = 0;
+
+ if (!textInputControllerClass) {
+ JSClassDefinition classDefinition = {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ classDefinition.staticFunctions = staticFunctions;
+
+ textInputControllerClass = JSClassCreate(&classDefinition);
+ }
+
+ return textInputControllerClass;
+}
+
+JSObjectRef makeTextInputController(JSContextRef context)
+{
+ return JSObjectMake(context, getClass(context), 0);
+}
diff --git a/Tools/DumpRenderTree/gtk/TextInputController.h b/Tools/DumpRenderTree/gtk/TextInputController.h
new file mode 100644
index 000000000..53793f637
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/TextInputController.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 TextInputController_h
+#define TextInputController_h
+
+typedef const struct OpaqueJSContext* JSContextRef;
+typedef struct OpaqueJSValue* JSObjectRef;
+
+JSObjectRef makeTextInputController(JSContextRef);
+
+#endif
diff --git a/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp b/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp
new file mode 100644
index 000000000..d10b19318
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WorkQueueItem.h"
+
+#include "DumpRenderTree.h"
+
+#include <GOwnPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <webkit/webkit.h>
+#include <string.h>
+
+// Returns a newly allocated UTF-8 character buffer which must be freed with g_free()
+gchar* JSStringCopyUTF8CString(JSStringRef jsString)
+{
+ size_t dataSize = JSStringGetMaximumUTF8CStringSize(jsString);
+ gchar* utf8 = (gchar*)g_malloc(dataSize);
+ JSStringGetUTF8CString(jsString, utf8, dataSize);
+
+ return utf8;
+}
+
+bool LoadItem::invoke() const
+{
+ gchar* targetString = JSStringCopyUTF8CString(m_target.get());
+
+ WebKitWebFrame* targetFrame;
+ if (!strlen(targetString))
+ targetFrame = mainFrame;
+ else
+ targetFrame = webkit_web_frame_find_frame(mainFrame, targetString);
+ g_free(targetString);
+
+ gchar* urlString = JSStringCopyUTF8CString(m_url.get());
+ WebKitNetworkRequest* request = webkit_network_request_new(urlString);
+ g_free(urlString);
+ webkit_web_frame_load_request(targetFrame, request);
+ g_object_unref(request);
+
+ return true;
+}
+
+bool LoadHTMLStringItem::invoke() const
+{
+ GOwnPtr<gchar> content(JSStringCopyUTF8CString(m_content.get()));
+ GOwnPtr<gchar> baseURL(JSStringCopyUTF8CString(m_baseURL.get()));
+
+ if (m_unreachableURL) {
+ GOwnPtr<gchar> unreachableURL(JSStringCopyUTF8CString(m_unreachableURL.get()));
+ webkit_web_frame_load_alternate_string(mainFrame, content.get(), baseURL.get(), unreachableURL.get());
+ return true;
+ }
+ webkit_web_frame_load_string(mainFrame, content.get(), 0, 0, baseURL.get());
+ return true;
+}
+
+bool ReloadItem::invoke() const
+{
+ webkit_web_frame_reload(mainFrame);
+ return true;
+}
+
+bool ScriptItem::invoke() const
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ gchar* scriptString = JSStringCopyUTF8CString(m_script.get());
+ webkit_web_view_execute_script(webView, scriptString);
+ g_free(scriptString);
+ return true;
+}
+
+bool BackForwardItem::invoke() const
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ if (m_howFar == 1)
+ webkit_web_view_go_forward(webView);
+ else if (m_howFar == -1)
+ webkit_web_view_go_back(webView);
+ else {
+ WebKitWebBackForwardList* webBackForwardList = webkit_web_view_get_back_forward_list(webView);
+ WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(webBackForwardList, m_howFar);
+ webkit_web_view_go_to_back_forward_item(webView, item);
+ }
+ return true;
+}
diff --git a/Tools/DumpRenderTree/gtk/fonts/AHEM____.TTF b/Tools/DumpRenderTree/gtk/fonts/AHEM____.TTF
new file mode 100644
index 000000000..ac81cb031
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/fonts/AHEM____.TTF
Binary files differ
diff --git a/Tools/DumpRenderTree/gtk/fonts/FontWithNoValidEncoding.fon b/Tools/DumpRenderTree/gtk/fonts/FontWithNoValidEncoding.fon
new file mode 100644
index 000000000..8fff7d9c1
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/fonts/FontWithNoValidEncoding.fon
Binary files differ
diff --git a/Tools/DumpRenderTree/gtk/fonts/fonts.conf b/Tools/DumpRenderTree/gtk/fonts/fonts.conf
new file mode 100644
index 000000000..3c55e87f3
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/fonts/fonts.conf
@@ -0,0 +1,419 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<fontconfig>
+
+ <!-- Due to patent (http://freetype.sourceforge.net/patents.html)
+ issues hinting gives different results depending on the
+ freetype version of the linux distribution, avoiding hinting
+ gives more consistent results. When all the distributions
+ release freetype the 2.4, which enables by default the
+ hinting method that was patented, we could undo this change
+ and try the hinting again. -->
+ <match target="font">
+ <edit name="hinting" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <!-- This system may have turned off selection of bitmap fonts, but
+ we must turn it on again, because we want to be able to test that
+ bitmap fonts with no valid encodings are *never* selected regardless
+ of the Fontconfig settings. So force Fontconfig to select our cruddy
+ bitmap font -->
+ <selectfont>
+ <acceptfont>
+ <pattern>
+ <patelt name="family">
+ <string>FontWithNoValidEncoding</string>
+ </patelt>
+ </pattern>
+ </acceptfont>
+ </selectfont>
+
+ <!-- The sans-serif font should be Liberation Serif -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Times</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Times New Roman</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+
+ <!-- Until we find good fonts to use for cursive and fantasy
+ just use our serif font. -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>cursive</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>fantasy</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ </match>
+
+ <!-- The sans-serif font should be Liberation Sans -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+ <!-- We need to ensure that layout tests that use "Helvetica" don't
+ fall back to the default serif font -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Helvetica</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Arial</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Lucida Grande</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ </match>
+
+ <!-- The Monospace font should be Liberation Mono -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>monospace</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>mono</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+ <!-- We need to ensure that layout tests that use "Courier", "Courier New",
+ and "Monaco" (all monospace fonts) don't fall back to the default
+ serif font -->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Courier</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Courier New</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>Monaco</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Mono</string>
+ </edit>
+ </match>
+
+ <!-- The following hinting specializations are adapted from those in the
+ Chromium test_shell. We try to duplicate their incredibly thorough
+ testing here -->
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>NonAntiAliasedSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ <edit name="antialias" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SlightHintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintslight</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>NonHintedSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ <!-- These deliberately contradict each other. The 'hinting' preference
+ should take priority -->
+ <edit name="hintstyle" mode="assign">
+ <const>hintfull</const>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>AutohintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="autohint" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintmedium</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>HintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="autohint" mode="assign">
+ <bool>false</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintmedium</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>FullAndAutoHintedSerif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Serif</string>
+ </edit>
+ <edit name="hinting" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="autohint" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="hintstyle" mode="assign">
+ <const>hintfull</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SubpixelEnabledSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ <edit name="rgba" mode="assign">
+ <const>rgb</const>
+ </edit>
+ </match>
+
+ <match target="pattern">
+ <test name="family" compare="eq">
+ <string>SubpixelDisabledSans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>Liberation Sans</string>
+ </edit>
+ <edit name="rgba" mode="assign">
+ <const>none</const>
+ </edit>
+ </match>
+
+ <!-- We need to enable simulated bold to for DejaVu Serif to ensure that we interpret
+ this property correctly in: platform/gtk/fonts/fontconfig-synthetic-bold.html -->
+ <match target="font">
+ <test qual="any" name="family">
+ <string>DejaVu Serif</string>
+ </test>
+ <test name="weight" compare="less_eq">
+ <const>medium</const>
+ </test>
+ <test target="pattern" name="weight" compare="more">
+ <const>medium</const>
+ </test>
+ <edit name="embolden" mode="assign">
+ <bool>true</bool>
+ </edit>
+ <edit name="weight" mode="assign">
+ <const>bold</const>
+ </edit>
+ </match>
+
+ <!-- We need to enable simulated oblique to for DejaVu Serif to ensure that we interpret
+ this property correctly in: platform/gtk/fonts/fontconfig-synthetic-oblique.html -->
+ <match target="font">
+ <test qual="any" name="family">
+ <string>DejaVu Serif</string>
+ </test>
+ <test name="slant">
+ <const>roman</const>
+ </test>
+ <test target="pattern" name="slant" compare="not_eq">
+ <const>roman</const>
+ </test>
+ <edit name="matrix" mode="assign">
+ <times>
+ <name>matrix</name>
+ <matrix><double>1</double><double>0.2</double>
+ <double>0</double><double>1</double>
+ </matrix>
+ </times>
+ </edit>
+ <edit name="slant" mode="assign">
+ <const>oblique</const>
+ </edit>
+ <edit name="embeddedbitmap" mode="assign">
+ <bool>false</bool>
+ </edit>
+ </match>
+
+ <!-- If this font doesn't have a family name we are falling back. The fallback
+ font will certainly be one of the DejaVu fonts that we have in our
+ collection since they have a wide range of characters. Fontconfig might
+ choose DejaVu Sans or DejaVu Serif depending on the system, so we force
+ the use of DejaVu Sans in these situations to maintain consistency. -->
+ <match target="pattern">
+ <test qual="all" name="family" compare="eq">
+ <string></string>
+ </test>
+ <edit name="family" mode="append_last">
+ <string>DejaVu Sans</string>
+ </edit>
+ </match>
+
+ <config>
+ <!-- These are the default Unicode chars that are expected to be blank
+ in fonts. All other blank chars are assumed to be broken and won't
+ appear in the resulting charsets -->
+ <blank>
+ <int>0x0020</int> <!-- SPACE -->
+ <int>0x00A0</int> <!-- NO-BREAK SPACE -->
+ <int>0x00AD</int> <!-- SOFT HYPHEN -->
+ <int>0x034F</int> <!-- COMBINING GRAPHEME JOINER -->
+ <int>0x0600</int> <!-- ARABIC NUMBER SIGN -->
+ <int>0x0601</int> <!-- ARABIC SIGN SANAH -->
+ <int>0x0602</int> <!-- ARABIC FOOTNOTE MARKER -->
+ <int>0x0603</int> <!-- ARABIC SIGN SAFHA -->
+ <int>0x06DD</int> <!-- ARABIC END OF AYAH -->
+ <int>0x070F</int> <!-- SYRIAC ABBREVIATION MARK -->
+ <int>0x115F</int> <!-- HANGUL CHOSEONG FILLER -->
+ <int>0x1160</int> <!-- HANGUL JUNGSEONG FILLER -->
+ <int>0x1680</int> <!-- OGHAM SPACE MARK -->
+ <int>0x17B4</int> <!-- KHMER VOWEL INHERENT AQ -->
+ <int>0x17B5</int> <!-- KHMER VOWEL INHERENT AA -->
+ <int>0x180E</int> <!-- MONGOLIAN VOWEL SEPARATOR -->
+ <int>0x2000</int> <!-- EN QUAD -->
+ <int>0x2001</int> <!-- EM QUAD -->
+ <int>0x2002</int> <!-- EN SPACE -->
+ <int>0x2003</int> <!-- EM SPACE -->
+ <int>0x2004</int> <!-- THREE-PER-EM SPACE -->
+ <int>0x2005</int> <!-- FOUR-PER-EM SPACE -->
+ <int>0x2006</int> <!-- SIX-PER-EM SPACE -->
+ <int>0x2007</int> <!-- FIGURE SPACE -->
+ <int>0x2008</int> <!-- PUNCTUATION SPACE -->
+ <int>0x2009</int> <!-- THIN SPACE -->
+ <int>0x200A</int> <!-- HAIR SPACE -->
+ <int>0x200B</int> <!-- ZERO WIDTH SPACE -->
+ <int>0x200C</int> <!-- ZERO WIDTH NON-JOINER -->
+ <int>0x200D</int> <!-- ZERO WIDTH JOINER -->
+ <int>0x200E</int> <!-- LEFT-TO-RIGHT MARK -->
+ <int>0x200F</int> <!-- RIGHT-TO-LEFT MARK -->
+ <int>0x2028</int> <!-- LINE SEPARATOR -->
+ <int>0x2029</int> <!-- PARAGRAPH SEPARATOR -->
+ <int>0x202A</int> <!-- LEFT-TO-RIGHT EMBEDDING -->
+ <int>0x202B</int> <!-- RIGHT-TO-LEFT EMBEDDING -->
+ <int>0x202C</int> <!-- POP DIRECTIONAL FORMATTING -->
+ <int>0x202D</int> <!-- LEFT-TO-RIGHT OVERRIDE -->
+ <int>0x202E</int> <!-- RIGHT-TO-LEFT OVERRIDE -->
+ <int>0x202F</int> <!-- NARROW NO-BREAK SPACE -->
+ <int>0x205F</int> <!-- MEDIUM MATHEMATICAL SPACE -->
+ <int>0x2060</int> <!-- WORD JOINER -->
+ <int>0x2061</int> <!-- FUNCTION APPLICATION -->
+ <int>0x2062</int> <!-- INVISIBLE TIMES -->
+ <int>0x2063</int> <!-- INVISIBLE SEPARATOR -->
+ <int>0x206A</int> <!-- INHIBIT SYMMETRIC SWAPPING -->
+ <int>0x206B</int> <!-- ACTIVATE SYMMETRIC SWAPPING -->
+ <int>0x206C</int> <!-- INHIBIT ARABIC FORM SHAPING -->
+ <int>0x206D</int> <!-- ACTIVATE ARABIC FORM SHAPING -->
+ <int>0x206E</int> <!-- NATIONAL DIGIT SHAPES -->
+ <int>0x206F</int> <!-- NOMINAL DIGIT SHAPES -->
+ <int>0x3000</int> <!-- IDEOGRAPHIC SPACE -->
+ <int>0x3164</int> <!-- HANGUL FILLER -->
+ <int>0xFEFF</int> <!-- ZERO WIDTH NO-BREAK SPACE -->
+ <int>0xFFA0</int> <!-- HALFWIDTH HANGUL FILLER -->
+ <int>0xFFF9</int> <!-- INTERLINEAR ANNOTATION ANCHOR -->
+ <int>0xFFFA</int> <!-- INTERLINEAR ANNOTATION SEPARATOR -->
+ <int>0xFFFB</int> <!-- INTERLINEAR ANNOTATION TERMINATOR -->
+ </blank>
+ </config>
+</fontconfig>
diff --git a/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm b/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm
new file mode 100644
index 000000000..6fc0dd056
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "DumpRenderTree.h"
+#import "AccessibilityController.h"
+
+#import "AccessibilityNotificationHandler.h"
+#import "AccessibilityUIElement.h"
+#import <AppKit/NSColor.h>
+#import <Foundation/Foundation.h>
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebFramePrivate.h>
+#import <WebKit/WebHTMLView.h>
+
+AccessibilityController::AccessibilityController()
+{
+}
+
+AccessibilityController::~AccessibilityController()
+{
+ // The notification handler should be nil because removeNotificationListener() should have been called in the test.
+ ASSERT(!m_globalNotificationHandler);
+}
+
+AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y)
+{
+ id accessibilityObject = [[[mainFrame frameView] documentView] accessibilityHitTest:NSMakePoint(x, y)];
+ return AccessibilityUIElement(accessibilityObject);
+}
+
+AccessibilityUIElement AccessibilityController::focusedElement()
+{
+ id accessibilityObject = [[mainFrame accessibilityRoot] accessibilityFocusedUIElement];
+ return AccessibilityUIElement(accessibilityObject);
+}
+
+AccessibilityUIElement AccessibilityController::rootElement()
+{
+ // FIXME: we could do some caching here.
+
+ // Layout tests expect that the root element will be the scroll area
+ // containing the web area object. That will be the parent of the accessibilityRoot on WK1.
+
+ id accessibilityObject = [[mainFrame accessibilityRoot] accessibilityAttributeValue:NSAccessibilityParentAttribute];
+ return AccessibilityUIElement(accessibilityObject);
+}
+
+void AccessibilityController::setLogFocusEvents(bool)
+{
+}
+
+void AccessibilityController::setLogScrollingStartEvents(bool)
+{
+}
+
+void AccessibilityController::setLogValueChangeEvents(bool)
+{
+}
+
+void AccessibilityController::setLogAccessibilityEvents(bool)
+{
+}
+
+bool AccessibilityController::addNotificationListener(JSObjectRef functionCallback)
+{
+ if (!functionCallback)
+ return false;
+
+ // Mac programmers should not be adding more than one global notification listener.
+ // Other platforms may be different.
+ if (m_globalNotificationHandler)
+ return false;
+ m_globalNotificationHandler = [[AccessibilityNotificationHandler alloc] init];
+ [m_globalNotificationHandler.get() setCallback:functionCallback];
+ [m_globalNotificationHandler.get() startObserving];
+
+ return true;
+}
+
+void AccessibilityController::removeNotificationListener()
+{
+ // Mac programmers should not be trying to remove a listener that's already removed.
+ ASSERT(m_globalNotificationHandler);
+ m_globalNotificationHandler.clear();
+}
diff --git a/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.h b/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.h
new file mode 100644
index 000000000..19386ceb0
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 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 AccessibilityNotificationHandler_h
+#define AccessibilityNotificationHandler_h
+
+#import <JavaScriptCore/JSObjectRef.h>
+
+@interface AccessibilityNotificationHandler : NSObject {
+ id m_platformElement;
+ JSObjectRef m_notificationFunctionCallback;
+}
+
+- (id)init;
+- (void)setPlatformElement:(id)platformElement;
+- (void)setCallback:(JSObjectRef)callback;
+- (void)startObserving;
+
+@end
+
+#endif // AccessibilityNotificationHandler_h
diff --git a/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.mm b/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.mm
new file mode 100644
index 000000000..13d08c9f4
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/AccessibilityNotificationHandler.mm
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#import "config.h"
+#import "DumpRenderTree.h"
+#import "AccessibilityNotificationHandler.h"
+#import "AccessibilityUIElement.h"
+
+#import <JavaScriptCore/JSRetainPtr.h>
+#import <JavaScriptCore/JSStringRef.h>
+#import <JavaScriptCore/JSStringRefCF.h>
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebTypesInternal.h>
+#import <wtf/RetainPtr.h>
+
+@interface NSObject (WebAccessibilityObjectWrapperAdditions)
++ (void)accessibilitySetShouldRepostNotifications:(BOOL)repost;
+@end
+
+@interface NSString (JSStringRefAdditions)
+- (JSStringRef)createJSStringRef;
+@end
+
+@implementation NSString (JSStringRefAdditions)
+
+- (JSStringRef)createJSStringRef
+{
+ return JSStringCreateWithCFString((CFStringRef)self);
+}
+
+@end
+
+@implementation AccessibilityNotificationHandler
+
+- (id)init
+{
+ if (!(self = [super init]))
+ return nil;
+
+ m_platformElement = nil;
+ return self;
+}
+
+- (void)setPlatformElement:(id)platformElement
+{
+ m_platformElement = platformElement;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback);
+ m_notificationFunctionCallback = 0;
+
+ [super dealloc];
+}
+
+- (void)setCallback:(JSObjectRef)callback
+{
+ if (!callback)
+ return;
+
+ if (m_notificationFunctionCallback)
+ JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback);
+
+ m_notificationFunctionCallback = callback;
+ JSValueProtect([mainFrame globalContext], m_notificationFunctionCallback);
+}
+
+- (void)startObserving
+{
+ // Once we start requesting notifications, it's on for the duration of the program.
+ // This is to avoid any race conditions between tests turning this flag on and off. Instead
+ // AccessibilityNotificationHandler can ignore events it doesn't care about.
+ id webAccessibilityObjectWrapperClass = NSClassFromString(@"WebAccessibilityObjectWrapper");
+ ASSERT(webAccessibilityObjectWrapperClass);
+ [webAccessibilityObjectWrapperClass accessibilitySetShouldRepostNotifications:YES];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_notificationReceived:) name:@"AXDRTNotification" object:nil];
+}
+
+- (void)_notificationReceived:(NSNotification *)notification
+{
+ NSString *notificationName = [[notification userInfo] objectForKey:@"notificationName"];
+ if (!notificationName)
+ return;
+ if (m_platformElement && m_platformElement != [notification object])
+ return;
+
+ JSRetainPtr<JSStringRef> jsNotification(Adopt, [notificationName createJSStringRef]);
+ JSValueRef notificationNameArgument = JSValueMakeString([mainFrame globalContext], jsNotification.get());
+ if (m_platformElement) {
+ // Listener for one element just gets one argument, the notification name.
+ JSObjectCallAsFunction([mainFrame globalContext], m_notificationFunctionCallback, 0, 1, &notificationNameArgument, 0);
+ } else {
+ // A global listener gets the element and the notification name as arguments.
+ JSValueRef arguments[2];
+ arguments[0] = AccessibilityUIElement::makeJSAccessibilityUIElement([mainFrame globalContext], AccessibilityUIElement([notification object]));
+ arguments[1] = notificationNameArgument;
+ JSObjectCallAsFunction([mainFrame globalContext], m_notificationFunctionCallback, 0, 2, arguments, 0);
+ }
+}
+
+@end
+
diff --git a/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm b/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm
new file mode 100644
index 000000000..18ddb85c6
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#import "AccessibilityTextMarker.h"
+#import "DumpRenderTree.h"
+
+// MARK: AccessibilityTextMarker
+
+AccessibilityTextMarker::AccessibilityTextMarker(PlatformTextMarker marker)
+ : m_textMarker(marker)
+{
+}
+
+AccessibilityTextMarker::AccessibilityTextMarker(const AccessibilityTextMarker& marker)
+ : m_textMarker(marker.platformTextMarker())
+{
+}
+
+AccessibilityTextMarker::~AccessibilityTextMarker()
+{
+}
+
+bool AccessibilityTextMarker::isEqual(AccessibilityTextMarker* other)
+{
+ return [(id)platformTextMarker() isEqual:(id)other->platformTextMarker()];
+}
+
+PlatformTextMarker AccessibilityTextMarker::platformTextMarker() const
+{
+ return m_textMarker.get();
+}
+
+// MARK: AccessibilityTextMarkerRange
+
+AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(PlatformTextMarkerRange markerRange)
+ : m_textMarkerRange(markerRange)
+{
+}
+
+AccessibilityTextMarkerRange::AccessibilityTextMarkerRange(const AccessibilityTextMarkerRange& markerRange)
+ : m_textMarkerRange(markerRange.platformTextMarkerRange())
+{
+}
+
+AccessibilityTextMarkerRange::~AccessibilityTextMarkerRange()
+{
+}
+
+bool AccessibilityTextMarkerRange::isEqual(AccessibilityTextMarkerRange* other)
+{
+ return [(id)platformTextMarkerRange() isEqual:(id)other->platformTextMarkerRange()];
+}
+
+PlatformTextMarkerRange AccessibilityTextMarkerRange::platformTextMarkerRange() const
+{
+ return m_textMarkerRange.get();
+}
diff --git a/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm b/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
new file mode 100644
index 000000000..9360ef1e7
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
@@ -0,0 +1,1394 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "DumpRenderTree.h"
+#import "AccessibilityNotificationHandler.h"
+#import "AccessibilityUIElement.h"
+
+#import <Foundation/Foundation.h>
+#import <JavaScriptCore/JSRetainPtr.h>
+#import <JavaScriptCore/JSStringRef.h>
+#import <JavaScriptCore/JSStringRefCF.h>
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebHTMLView.h>
+#import <WebKit/WebTypesInternal.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/Vector.h>
+
+
+#ifndef NSAccessibilityOwnsAttribute
+#define NSAccessibilityOwnsAttribute @"AXOwns"
+#endif
+
+#ifndef NSAccessibilityGrabbedAttribute
+#define NSAccessibilityGrabbedAttribute @"AXGrabbed"
+#endif
+
+#ifndef NSAccessibilityDropEffectsAttribute
+#define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
+#endif
+
+// If an unsupported attribute is passed in, it will raise an accessibility exception. These are usually caught by the Accessibility Runtime to inform
+// the AX client app of the error. However, DRT is the AX client app, so it must catch these exceptions.
+#define BEGIN_AX_OBJC_EXCEPTIONS @try {
+#define END_AX_OBJC_EXCEPTIONS } @catch(NSException *e) { if (![[e name] isEqualToString:NSAccessibilityException]) @throw; }
+
+
+typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
+
+@interface NSObject (WebKitAccessibilityAdditions)
+- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
+- (NSUInteger)accessibilityIndexOfChild:(id)child;
+- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute;
+@end
+
+@interface NSString (JSStringRefAdditions)
++ (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef;
+- (JSStringRef)createJSStringRef;
+@end
+
+@implementation NSString (JSStringRefAdditions)
+
++ (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef
+{
+ if (!jsStringRef)
+ return NULL;
+
+ CFStringRef cfString = JSStringCopyCFString(kCFAllocatorDefault, jsStringRef);
+ return [(NSString *)cfString autorelease];
+}
+
+- (JSStringRef)createJSStringRef
+{
+ return JSStringCreateWithCFString((CFStringRef)self);
+}
+
+@end
+
+AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
+ : m_element(element)
+ , m_notificationHandler(0)
+{
+ // FIXME: ap@webkit.org says ObjC objects need to be CFRetained/CFRelease to be GC-compliant on the mac.
+ [m_element retain];
+}
+
+AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
+ : m_element(other.m_element)
+ , m_notificationHandler(0)
+{
+ [m_element retain];
+}
+
+AccessibilityUIElement::~AccessibilityUIElement()
+{
+ // The notification handler should be nil because removeNotificationListener() should have been called in the test.
+ ASSERT(!m_notificationHandler);
+ [m_element release];
+}
+
+static NSString* descriptionOfValue(id valueObject, id focusedAccessibilityObject)
+{
+ if (!valueObject)
+ return NULL;
+
+ if ([valueObject isKindOfClass:[NSArray class]])
+ return [NSString stringWithFormat:@"<array of size %d>", [(NSArray*)valueObject count]];
+
+ if ([valueObject isKindOfClass:[NSNumber class]])
+ return [(NSNumber*)valueObject stringValue];
+
+ if ([valueObject isKindOfClass:[NSValue class]]) {
+ NSString* type = [NSString stringWithCString:[valueObject objCType] encoding:NSASCIIStringEncoding];
+ NSValue* value = (NSValue*)valueObject;
+ if ([type rangeOfString:@"NSRect"].length > 0)
+ return [NSString stringWithFormat:@"NSRect: %@", NSStringFromRect([value rectValue])];
+ if ([type rangeOfString:@"NSPoint"].length > 0)
+ return [NSString stringWithFormat:@"NSPoint: %@", NSStringFromPoint([value pointValue])];
+ if ([type rangeOfString:@"NSSize"].length > 0)
+ return [NSString stringWithFormat:@"NSSize: %@", NSStringFromSize([value sizeValue])];
+ if ([type rangeOfString:@"NSRange"].length > 0)
+ return [NSString stringWithFormat:@"NSRange: %@", NSStringFromRange([value rangeValue])];
+ }
+
+ // Strip absolute URL paths
+ NSString* description = [valueObject description];
+ NSRange range = [description rangeOfString:@"LayoutTests"];
+ if (range.length)
+ return [description substringFromIndex:range.location];
+
+ // Strip pointer locations
+ if ([description rangeOfString:@"0x"].length) {
+ NSString* role = [focusedAccessibilityObject accessibilityAttributeValue:NSAccessibilityRoleAttribute];
+ NSString* title = [focusedAccessibilityObject accessibilityAttributeValue:NSAccessibilityTitleAttribute];
+ if ([title length])
+ return [NSString stringWithFormat:@"<%@: '%@'>", role, title];
+ return [NSString stringWithFormat:@"<%@>", role];
+ }
+
+ return [valueObject description];
+}
+
+static NSString* attributesOfElement(id accessibilityObject)
+{
+ NSArray* supportedAttributes = [accessibilityObject accessibilityAttributeNames];
+
+ NSMutableString* attributesString = [NSMutableString string];
+ for (NSUInteger i = 0; i < [supportedAttributes count]; ++i) {
+ NSString* attribute = [supportedAttributes objectAtIndex:i];
+
+ // Right now, position provides useless and screen-specific information, so we do not
+ // want to include it for the sake of universally passing tests.
+ if ([attribute isEqualToString:@"AXPosition"])
+ continue;
+
+ // accessibilityAttributeValue: can throw an if an attribute is not returned.
+ // For DumpRenderTree's purpose, we should ignore those exceptions
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id valueObject = [accessibilityObject accessibilityAttributeValue:attribute];
+ NSString* value = descriptionOfValue(valueObject, accessibilityObject);
+ [attributesString appendFormat:@"%@: %@\n", attribute, value];
+ END_AX_OBJC_EXCEPTIONS
+ }
+
+ return attributesString;
+}
+
+static JSStringRef concatenateAttributeAndValue(NSString* attribute, NSString* value)
+{
+ Vector<UniChar> buffer([attribute length]);
+ [attribute getCharacters:buffer.data()];
+ buffer.append(':');
+ buffer.append(' ');
+
+ Vector<UniChar> valueBuffer([value length]);
+ [value getCharacters:valueBuffer.data()];
+ buffer.append(valueBuffer);
+
+ return JSStringCreateWithCharacters(buffer.data(), buffer.size());
+}
+
+static void convertNSArrayToVector(NSArray* array, Vector<AccessibilityUIElement>& elementVector)
+{
+ NSUInteger count = [array count];
+ for (NSUInteger i = 0; i < count; ++i)
+ elementVector.append(AccessibilityUIElement([array objectAtIndex:i]));
+}
+
+static JSStringRef descriptionOfElements(Vector<AccessibilityUIElement>& elementVector)
+{
+ NSMutableString* allElementString = [NSMutableString string];
+ size_t size = elementVector.size();
+ for (size_t i = 0; i < size; ++i) {
+ NSString* attributes = attributesOfElement(elementVector[i].platformUIElement());
+ [allElementString appendFormat:@"%@\n------------\n", attributes];
+ }
+
+ return [allElementString createJSStringRef];
+}
+
+void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elementVector)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* linkedElements = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute];
+ convertNSArrayToVector(linkedElements, elementVector);
+ END_AX_OBJC_EXCEPTIONS
+}
+
+void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>& elementVector)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* linkElements = [m_element accessibilityAttributeValue:@"AXLinkUIElements"];
+ convertNSArrayToVector(linkElements, elementVector);
+ END_AX_OBJC_EXCEPTIONS
+}
+
+void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& elementVector)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* children = [m_element accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
+ convertNSArrayToVector(children, elementVector);
+ END_AX_OBJC_EXCEPTIONS
+}
+
+void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* children = [m_element accessibilityArrayAttributeValues:NSAccessibilityChildrenAttribute index:location maxCount:length];
+ convertNSArrayToVector(children, elementVector);
+ END_AX_OBJC_EXCEPTIONS
+}
+
+int AccessibilityUIElement::childrenCount()
+{
+ Vector<AccessibilityUIElement> children;
+ getChildren(children);
+
+ return children.size();
+}
+
+AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y)
+{
+ id element = [m_element accessibilityHitTest:NSMakePoint(x, y)];
+ if (!element)
+ return nil;
+
+ return AccessibilityUIElement(element);
+}
+
+unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
+{
+ return [m_element accessibilityIndexOfChild:element->platformUIElement()];
+}
+
+AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ Vector<AccessibilityUIElement> children;
+ getChildrenWithRange(children, index, 1);
+
+ if (children.size() == 1)
+ return children[0];
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute];
+ if (index < [objects count])
+ return [objects objectAtIndex:index];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityOwnsAttribute];
+ if (index < [objects count])
+ return [objects objectAtIndex:index];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute];
+ if (index < [objects count])
+ return [objects objectAtIndex:index];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedRowsAttribute];
+ if (index < [rows count])
+ return [rows objectAtIndex:index];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* array = [m_element accessibilityAttributeValue:NSAccessibilitySelectedChildrenAttribute];
+ if (index < [array count])
+ return [array objectAtIndex:index];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+unsigned AccessibilityUIElement::selectedChildrenCount() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ return [m_element accessibilityArrayAttributeCount:NSAccessibilitySelectedChildrenAttribute];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilitySelectedRowsAttribute];
+ if (index < [rows count])
+ return [rows objectAtIndex:index];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::titleUIElement()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityTitleUIElementAttribute];
+ if (accessibilityObject)
+ return AccessibilityUIElement(accessibilityObject);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::parentElement()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityParentAttribute];
+ if (accessibilityObject)
+ return AccessibilityUIElement(accessibilityObject);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedByRowAttribute];
+ if (accessibilityObject)
+ return AccessibilityUIElement(accessibilityObject);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements()
+{
+ Vector<AccessibilityUIElement> linkedElements;
+ getLinkedUIElements(linkedElements);
+ return descriptionOfElements(linkedElements);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfDocumentLinks()
+{
+ Vector<AccessibilityUIElement> linkElements;
+ getDocumentLinks(linkElements);
+ return descriptionOfElements(linkElements);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfChildren()
+{
+ Vector<AccessibilityUIElement> children;
+ getChildren(children);
+ return descriptionOfElements(children);
+}
+
+JSStringRef AccessibilityUIElement::allAttributes()
+{
+ NSString* attributes = attributesOfElement(m_element);
+ return [attributes createJSStringRef];
+}
+
+JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]];
+ if ([value isKindOfClass:[NSString class]])
+ return [value createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id uiElement = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]];
+ return AccessibilityUIElement(uiElement);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+
+double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value doubleValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ return [m_element accessibilityIsAttributeSettable:[NSString stringWithJSStringRef:attribute]];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ return [[m_element accessibilityAttributeNames] containsObject:[NSString stringWithJSStringRef:attribute]];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+JSStringRef AccessibilityUIElement::parameterizedAttributeNames()
+{
+ NSArray* supportedParameterizedAttributes = [m_element accessibilityParameterizedAttributeNames];
+
+ NSMutableString* attributesString = [NSMutableString string];
+ for (NSUInteger i = 0; i < [supportedParameterizedAttributes count]; ++i) {
+ [attributesString appendFormat:@"%@\n", [supportedParameterizedAttributes objectAtIndex:i]];
+ }
+
+ return [attributesString createJSStringRef];
+}
+
+JSStringRef AccessibilityUIElement::role()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSString *role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityRoleAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXRole", role);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::subrole()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilitySubroleAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXSubrole", role);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::roleDescription()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXRoleDescription", role);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::title()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSString* title = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityTitleAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXTitle", title);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::description()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityDescriptionAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXDescription", description);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::orientation() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityOrientationAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXOrientation", description);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::stringValue()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityValueAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXValue", description);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::language()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id description = descriptionOfValue([m_element accessibilityAttributeValue:@"AXLanguage"], m_element);
+ return concatenateAttributeAndValue(@"AXLanguage", description);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::helpText() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityHelpAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXHelp", description);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+double AccessibilityUIElement::x()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute];
+ return static_cast<double>([positionValue pointValue].x);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0.0f;
+}
+
+double AccessibilityUIElement::y()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute];
+ return static_cast<double>([positionValue pointValue].y);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0.0f;
+}
+
+double AccessibilityUIElement::width()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSValue* sizeValue = [m_element accessibilityAttributeValue:NSAccessibilitySizeAttribute];
+ return static_cast<double>([sizeValue sizeValue].width);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0.0f;
+}
+
+double AccessibilityUIElement::height()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSValue* sizeValue = [m_element accessibilityAttributeValue:NSAccessibilitySizeAttribute];
+ return static_cast<double>([sizeValue sizeValue].height);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0.0f;
+}
+
+double AccessibilityUIElement::clickPointX()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSValue* positionValue = [m_element accessibilityAttributeValue:@"AXClickPoint"];
+ return static_cast<double>([positionValue pointValue].x);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0.0f;
+}
+
+double AccessibilityUIElement::clickPointY()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSValue* positionValue = [m_element accessibilityAttributeValue:@"AXClickPoint"];
+ return static_cast<double>([positionValue pointValue].y);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0.0f;
+}
+
+double AccessibilityUIElement::intValue() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityValueAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [(NSNumber*)value doubleValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0.0f;
+}
+
+double AccessibilityUIElement::minValue()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityMinValueAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [(NSNumber*)value doubleValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0.0f;
+}
+
+double AccessibilityUIElement::maxValue()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityMaxValueAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [(NSNumber*)value doubleValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0.0;
+}
+
+JSStringRef AccessibilityUIElement::valueDescription()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSString* valueDescription = [m_element accessibilityAttributeValue:NSAccessibilityValueDescriptionAttribute];
+ if ([valueDescription isKindOfClass:[NSString class]])
+ return [valueDescription createJSStringRef];
+
+ END_AX_OBJC_EXCEPTIONS
+ return 0;
+}
+
+int AccessibilityUIElement::insertionPointLineNumber()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityInsertionPointLineNumberAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [(NSNumber *)value intValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return -1;
+}
+
+bool AccessibilityUIElement::isActionSupported(JSStringRef action)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* actions = [m_element accessibilityActionNames];
+ return [actions containsObject:[NSString stringWithJSStringRef:action]];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+bool AccessibilityUIElement::isEnabled()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityEnabledAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+bool AccessibilityUIElement::isRequired() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:@"AXRequired"];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+bool AccessibilityUIElement::isFocused() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isSelected() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilitySelectedAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+bool AccessibilityUIElement::isExpanded() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityExpandedAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+bool AccessibilityUIElement::isChecked() const
+{
+ // On the Mac, intValue()==1 if a a checkable control is checked.
+ return intValue() == 1;
+}
+
+int AccessibilityUIElement::hierarchicalLevel() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityDisclosureLevelAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value intValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::speak()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:@"AXDRTSpeechAttribute"];
+ if ([value isKindOfClass:[NSString class]])
+ return [value createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+bool AccessibilityUIElement::ariaIsGrabbed() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityGrabbedAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+JSStringRef AccessibilityUIElement::ariaDropEffects() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityDropEffectsAttribute];
+ if (![value isKindOfClass:[NSArray class]])
+ return 0;
+
+ NSMutableString* dropEffects = [NSMutableString string];
+ NSInteger length = [value count];
+ for (NSInteger k = 0; k < length; ++k) {
+ [dropEffects appendString:[value objectAtIndex:k]];
+ if (k < length - 1)
+ [dropEffects appendString:@","];
+ }
+
+ return [dropEffects createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+// parameterized attributes
+int AccessibilityUIElement::lineForIndex(int index)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityLineForIndexParameterizedAttribute forParameter:[NSNumber numberWithInt:index]];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [(NSNumber *)value intValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return -1;
+}
+
+JSStringRef AccessibilityUIElement::rangeForLine(int line)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityRangeForLineParameterizedAttribute forParameter:[NSNumber numberWithInt:line]];
+ if ([value isKindOfClass:[NSValue class]]) {
+ return [NSStringFromRange([value rangeValue]) createJSStringRef];
+ }
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
+{
+ NSRange range = NSMakeRange(location, length);
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityBoundsForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]];
+ NSRect rect = NSMakeRect(0,0,0,0);
+ if ([value isKindOfClass:[NSValue class]])
+ rect = [value rectValue];
+
+ // don't return position information because it is platform dependent
+ NSMutableString* boundsDescription = [NSMutableString stringWithFormat:@"{{%f, %f}, {%f, %f}}",-1.0f,-1.0f,rect.size.width,rect.size.height];
+ return [boundsDescription createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
+{
+ NSRange range = NSMakeRange(location, length);
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id string = [m_element accessibilityAttributeValue:NSAccessibilityStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]];
+ if (![string isKindOfClass:[NSString class]])
+ return 0;
+
+ return [string createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
+{
+ NSRange range = NSMakeRange(location, length);
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSAttributedString* string = [m_element accessibilityAttributeValue:NSAccessibilityAttributedStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]];
+ if (![string isKindOfClass:[NSAttributedString class]])
+ return 0;
+
+ NSString* stringWithAttrs = [string description];
+ return [stringWithAttrs createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
+{
+ NSRange range = NSMakeRange(location, length);
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSAttributedString* string = [m_element accessibilityAttributeValue:NSAccessibilityAttributedStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]];
+ if (![string isKindOfClass:[NSAttributedString class]])
+ return false;
+
+ NSDictionary* attrs = [string attributesAtIndex:0 effectiveRange:nil];
+ if([[attrs objectForKey:NSAccessibilityMisspelledTextAttribute] boolValue])
+ return true;
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(AccessibilityUIElement* startElement, bool isDirectionNext, JSStringRef searchKey, JSStringRef searchText)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSMutableDictionary* parameter = [NSMutableDictionary dictionary];
+ [parameter setObject:(isDirectionNext) ? @"AXDirectionNext" : @"AXDirectionPrevious" forKey:@"AXDirection"];
+ [parameter setObject:[NSNumber numberWithInt:1] forKey:@"AXResultsLimit"];
+ if (startElement && startElement->platformUIElement())
+ [parameter setObject:(id)startElement->platformUIElement() forKey:@"AXStartElement"];
+ if (searchKey)
+ [parameter setObject:[NSString stringWithJSStringRef:searchKey] forKey:@"AXSearchKey"];
+ if (searchText)
+ [parameter setObject:[NSString stringWithJSStringRef:searchText] forKey:@"AXSearchText"];
+
+ id uiElement = [[m_element accessibilityAttributeValue:@"AXUIElementsForSearchPredicate" forParameter:parameter] lastObject];
+ return AccessibilityUIElement(uiElement);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfColumnHeaders()
+{
+ // not yet defined in AppKit... odd
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* columnHeadersArray = [m_element accessibilityAttributeValue:@"AXColumnHeaderUIElements"];
+ Vector<AccessibilityUIElement> columnHeadersVector;
+ convertNSArrayToVector(columnHeadersArray, columnHeadersVector);
+ return descriptionOfElements(columnHeadersVector);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfRowHeaders()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* rowHeadersArray = [m_element accessibilityAttributeValue:@"AXRowHeaderUIElements"];
+ Vector<AccessibilityUIElement> rowHeadersVector;
+ convertNSArrayToVector(rowHeadersArray, rowHeadersVector);
+ return descriptionOfElements(rowHeadersVector);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfColumns()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* columnsArray = [m_element accessibilityAttributeValue:NSAccessibilityColumnsAttribute];
+ Vector<AccessibilityUIElement> columnsVector;
+ convertNSArrayToVector(columnsArray, columnsVector);
+ return descriptionOfElements(columnsVector);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfRows()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* rowsArray = [m_element accessibilityAttributeValue:NSAccessibilityRowsAttribute];
+ Vector<AccessibilityUIElement> rowsVector;
+ convertNSArrayToVector(rowsArray, rowsVector);
+ return descriptionOfElements(rowsVector);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfVisibleCells()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* cellsArray = [m_element accessibilityAttributeValue:@"AXVisibleCells"];
+ Vector<AccessibilityUIElement> cellsVector;
+ convertNSArrayToVector(cellsArray, cellsVector);
+ return descriptionOfElements(cellsVector);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfHeader()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id headerObject = [m_element accessibilityAttributeValue:NSAccessibilityHeaderAttribute];
+ if (!headerObject)
+ return [@"" createJSStringRef];
+
+ Vector<AccessibilityUIElement> headerVector;
+ headerVector.append(headerObject);
+ return descriptionOfElements(headerVector);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+int AccessibilityUIElement::rowCount()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ return [m_element accessibilityArrayAttributeCount:NSAccessibilityRowsAttribute];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+int AccessibilityUIElement::columnCount()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ return [m_element accessibilityArrayAttributeCount:NSAccessibilityColumnsAttribute];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+int AccessibilityUIElement::indexInTable()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSNumber* indexNumber = [m_element accessibilityAttributeValue:NSAccessibilityIndexAttribute];
+ if (indexNumber)
+ return [indexNumber intValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return -1;
+}
+
+JSStringRef AccessibilityUIElement::rowIndexRange()
+{
+ NSRange range = NSMakeRange(0,0);
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSValue* indexRange = [m_element accessibilityAttributeValue:@"AXRowIndexRange"];
+ if (indexRange)
+ range = [indexRange rangeValue];
+ NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length];
+ return [rangeDescription createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::columnIndexRange()
+{
+ NSRange range = NSMakeRange(0,0);
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSNumber* indexRange = [m_element accessibilityAttributeValue:@"AXColumnIndexRange"];
+ if (indexRange)
+ range = [indexRange rangeValue];
+ NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length];
+ return [rangeDescription createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
+{
+ NSArray *colRowArray = [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:col], [NSNumber numberWithUnsignedInt:row], nil];
+ BEGIN_AX_OBJC_EXCEPTIONS
+ return [m_element accessibilityAttributeValue:@"AXCellForColumnAndRow" forParameter:colRowArray];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::horizontalScrollbar() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ return AccessibilityUIElement([m_element accessibilityAttributeValue:NSAccessibilityHorizontalScrollBarAttribute]);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::verticalScrollbar() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ return AccessibilityUIElement([m_element accessibilityAttributeValue:NSAccessibilityVerticalScrollBarAttribute]);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::selectedTextRange()
+{
+ NSRange range = NSMakeRange(NSNotFound, 0);
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSValue *indexRange = [m_element accessibilityAttributeValue:NSAccessibilitySelectedTextRangeAttribute];
+ if (indexRange)
+ range = [indexRange rangeValue];
+ NSMutableString *rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length];
+ return [rangeDescription createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
+{
+ NSRange textRange = NSMakeRange(location, length);
+ NSValue *textRangeValue = [NSValue valueWithRange:textRange];
+ BEGIN_AX_OBJC_EXCEPTIONS
+ [m_element accessibilitySetValue:textRangeValue forAttribute:NSAccessibilitySelectedTextRangeAttribute];
+ END_AX_OBJC_EXCEPTIONS
+}
+
+void AccessibilityUIElement::increment()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ [m_element accessibilityPerformAction:NSAccessibilityIncrementAction];
+ END_AX_OBJC_EXCEPTIONS
+}
+
+void AccessibilityUIElement::decrement()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ [m_element accessibilityPerformAction:NSAccessibilityDecrementAction];
+ END_AX_OBJC_EXCEPTIONS
+}
+
+void AccessibilityUIElement::showMenu()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ [m_element accessibilityPerformAction:NSAccessibilityShowMenuAction];
+ END_AX_OBJC_EXCEPTIONS
+}
+
+void AccessibilityUIElement::press()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ [m_element accessibilityPerformAction:NSAccessibilityPressAction];
+ END_AX_OBJC_EXCEPTIONS
+}
+
+void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* array = [NSArray arrayWithObject:element->platformUIElement()];
+ [m_element accessibilitySetValue:array forAttribute:NSAccessibilitySelectedChildrenAttribute];
+ END_AX_OBJC_EXCEPTIONS
+}
+
+JSStringRef AccessibilityUIElement::accessibilityValue() const
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::documentEncoding()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::documentURI()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::url()
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSURL *url = [m_element accessibilityAttributeValue:NSAccessibilityURLAttribute];
+ return [[url absoluteString] createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return nil;
+}
+
+bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
+{
+ if (!functionCallback)
+ return false;
+
+ // Mac programmers should not be adding more than one notification listener per element.
+ // Other platforms may be different.
+ if (m_notificationHandler)
+ return false;
+ m_notificationHandler = [[AccessibilityNotificationHandler alloc] init];
+ [m_notificationHandler setPlatformElement:platformUIElement()];
+ [m_notificationHandler setCallback:functionCallback];
+ [m_notificationHandler startObserving];
+
+ return true;
+}
+
+void AccessibilityUIElement::removeNotificationListener()
+{
+ // Mac programmers should not be trying to remove a listener that's already removed.
+ ASSERT(m_notificationHandler);
+
+ [m_notificationHandler release];
+ m_notificationHandler = nil;
+}
+
+bool AccessibilityUIElement::isFocusable() const
+{
+ bool result = false;
+ BEGIN_AX_OBJC_EXCEPTIONS
+ result = [m_element accessibilityIsAttributeSettable:NSAccessibilityFocusedAttribute];
+ END_AX_OBJC_EXCEPTIONS
+
+ return result;
+}
+
+bool AccessibilityUIElement::isSelectable() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isMultiSelectable() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isSelectedOptionActive() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isVisible() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isOffScreen() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isCollapsed() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isIgnored() const
+{
+ BOOL result = NO;
+ BEGIN_AX_OBJC_EXCEPTIONS
+ result = [m_element accessibilityIsIgnored];
+ END_AX_OBJC_EXCEPTIONS
+ return result;
+}
+
+bool AccessibilityUIElement::hasPopup() const
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id value = [m_element accessibilityAttributeValue:@"AXHasPopup"];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+void AccessibilityUIElement::takeFocus()
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::takeSelection()
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::addSelection()
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::removeSelection()
+{
+ // FIXME: implement
+}
+
+#if SUPPORTS_AX_TEXTMARKERS
+
+// Text markers
+AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarkerRange = [m_element accessibilityAttributeValue:@"AXTextMarkerRangeForUIElement" forParameter:element->platformUIElement()];
+ return AccessibilityTextMarkerRange(textMarkerRange);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSNumber* lengthValue = [m_element accessibilityAttributeValue:@"AXLengthForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()];
+ return [lengthValue intValue];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSAttributedString* string = [m_element accessibilityAttributeValue:@"AXAttributedStringForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()];
+ if (![string isKindOfClass:[NSAttributedString class]])
+ return false;
+
+ NSDictionary* attrs = [string attributesAtIndex:0 effectiveRange:nil];
+ if ([attrs objectForKey:[NSString stringWithJSStringRef:attribute]])
+ return true;
+ END_AX_OBJC_EXCEPTIONS
+
+ return false;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id previousMarker = [m_element accessibilityAttributeValue:@"AXPreviousTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarker(previousMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id nextMarker = [m_element accessibilityAttributeValue:@"AXNextTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
+ return AccessibilityTextMarker(nextMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textString = [m_element accessibilityAttributeValue:@"AXStringForTextMarkerRange" forParameter:(id)markerRange->platformTextMarkerRange()];
+ return [textString createJSStringRef];
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* textMarkers = [NSArray arrayWithObjects:(id)startMarker->platformTextMarker(), (id)endMarker->platformTextMarker(), nil];
+ id textMarkerRange = [m_element accessibilityAttributeValue:@"AXTextMarkerRangeForUnorderedTextMarkers" forParameter:textMarkers];
+ return AccessibilityTextMarkerRange(textMarkerRange);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarker = [m_element accessibilityAttributeValue:@"AXStartTextMarkerForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()];
+ return AccessibilityTextMarker(textMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarker = [m_element accessibilityAttributeValue:@"AXEndTextMarkerForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()];
+ return AccessibilityTextMarker(textMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityTextMarker AccessibilityUIElement::textMarkerForPoint(int x, int y)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id textMarker = [m_element accessibilityAttributeValue:@"AXTextMarkerForPosition" forParameter:[NSValue valueWithPoint:NSMakePoint(x, y)]];
+ return AccessibilityTextMarker(textMarker);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ id uiElement = [m_element accessibilityAttributeValue:@"AXUIElementForTextMarker" forParameter:(id)marker->platformTextMarker()];
+ return AccessibilityUIElement(uiElement);
+ END_AX_OBJC_EXCEPTIONS
+
+ return 0;
+}
+
+#endif // SUPPORTS_AX_TEXTMARKERS
diff --git a/Tools/DumpRenderTree/mac/AppleScriptController.h b/Tools/DumpRenderTree/mac/AppleScriptController.h
new file mode 100644
index 000000000..c29789c2e
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/AppleScriptController.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class WebView;
+
+@interface AppleScriptController : NSObject
+{
+ WebView *webView;
+}
+- (id)initWithWebView:(WebView *)view;
+@end
diff --git a/Tools/DumpRenderTree/mac/AppleScriptController.m b/Tools/DumpRenderTree/mac/AppleScriptController.m
new file mode 100644
index 000000000..2eab8271e
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/AppleScriptController.m
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "AppleScriptController.h"
+
+#import <WebKit/WebView.h>
+#import <WebKit/WebViewPrivate.h> // for aeDescByEvaluatingJavaScriptFromString, which is pending API review
+
+@implementation AppleScriptController
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
+{
+ if (aSelector == @selector(doJavaScript:))
+ return NO;
+ return YES;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)aSelector
+{
+ if (aSelector == @selector(doJavaScript:))
+ return @"doJavaScript";
+
+ return nil;
+}
+
+- (id)initWithWebView:(WebView *)wv
+{
+ self = [super init];
+ webView = wv;
+ return self;
+}
+
+static id convertAEDescToObject(NSAppleEventDescriptor *aeDesc)
+{
+ id value = nil;
+
+ DescType descType = [aeDesc descriptorType];
+ switch (descType) {
+ case typeUnicodeText:
+ value = [NSString stringWithFormat:@"\"%@\"", [aeDesc stringValue]];
+ break;
+ case typeLongDateTime:
+ if ([[aeDesc data] length] == sizeof(LongDateTime)) {
+ LongDateTime d;
+ [[aeDesc data] getBytes:&d];
+ value = [NSString stringWithFormat:@"%016llX", (unsigned long long)d];
+ }
+ break;
+ case typeAEList:
+ value = [NSMutableString stringWithString:@"("];
+ int numItems = [aeDesc numberOfItems];
+ for (int i = 0; i < numItems; ++i) {
+ if (i != 0)
+ [(NSMutableString*)value appendString:@", "];
+ id obj = convertAEDescToObject([aeDesc descriptorAtIndex:(i + 1)]);
+ [(NSMutableString*)value appendString:[obj description]];
+ }
+ [(NSMutableString*)value appendString:@")"];
+ break;
+ case typeType: {
+ OSType type = [aeDesc typeCodeValue];
+
+ char typeStr[5];
+ typeStr[0] = type >> 24;
+ typeStr[1] = type >> 16;
+ typeStr[2] = type >> 8;
+ typeStr[3] = type;
+ typeStr[4] = 0;
+
+ value = [NSString stringWithFormat:@"'%s'", typeStr];
+ break;
+ }
+ }
+
+ if (!value)
+ value = [aeDesc stringValue];
+ if (!value)
+ value = [aeDesc data];
+
+ return value;
+}
+
+- (NSString *)doJavaScript:(NSString *)aString
+{
+ NSAppleEventDescriptor *aeDesc = [webView aeDescByEvaluatingJavaScriptFromString:aString];
+ if (!aeDesc)
+ return @"(null)";
+
+ DescType descType = [aeDesc descriptorType];
+ char descTypeStr[5];
+ descTypeStr[0] = descType >> 24;
+ descTypeStr[1] = descType >> 16;
+ descTypeStr[2] = descType >> 8;
+ descTypeStr[3] = descType;
+ descTypeStr[4] = 0;
+
+ return [NSString stringWithFormat:@"%@ ('%s')", convertAEDescToObject(aeDesc), descTypeStr];
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/CheckedMalloc.cpp b/Tools/DumpRenderTree/mac/CheckedMalloc.cpp
new file mode 100644
index 000000000..8bd53e546
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/CheckedMalloc.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "CheckedMalloc.h"
+
+#import <mach/mach_init.h>
+#import <mach/mach_vm.h>
+#import <mach/vm_region.h>
+#import <malloc/malloc.h>
+#import <unistd.h>
+
+static void* (*savedMalloc)(malloc_zone_t*, size_t);
+static void* (*savedRealloc)(malloc_zone_t*, void*, size_t);
+
+static void* checkedMalloc(malloc_zone_t* zone, size_t size)
+{
+ if (size >= 0x10000000)
+ return 0;
+ return savedMalloc(zone, size);
+}
+
+static void* checkedRealloc(malloc_zone_t* zone, void* ptr, size_t size)
+{
+ if (size >= 0x10000000)
+ return 0;
+ return savedRealloc(zone, ptr, size);
+}
+
+#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+static vm_prot_t protectionOfRegion(mach_vm_address_t address)
+{
+ mach_vm_size_t regionSize = 0;
+ vm_region_basic_info_64 regionInfo;
+ mach_msg_type_number_t regionInfoCount = VM_REGION_BASIC_INFO_COUNT_64;
+ mach_port_t objectName;
+ if (mach_vm_region(mach_task_self(), &address, &regionSize, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&regionInfo, &regionInfoCount, &objectName))
+ CRASH();
+ return regionInfo.protection;
+}
+#endif
+
+void makeLargeMallocFailSilently()
+{
+ malloc_zone_t* zone = malloc_default_zone();
+
+#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ mach_vm_address_t pageStart = reinterpret_cast<vm_address_t>(zone) & static_cast<vm_size_t>(~(getpagesize() - 1));
+ vm_prot_t initialProtection = protectionOfRegion(pageStart);
+
+ vm_size_t len = reinterpret_cast<vm_address_t>(zone) - pageStart + sizeof(malloc_zone_t);
+ if (mach_vm_protect(mach_task_self(), pageStart, len, 0, initialProtection | VM_PROT_WRITE))
+ CRASH();
+#endif
+
+ savedMalloc = zone->malloc;
+ savedRealloc = zone->realloc;
+ zone->malloc = checkedMalloc;
+ zone->realloc = checkedRealloc;
+
+#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ if (mach_vm_protect(mach_task_self(), pageStart, len, 0, initialProtection))
+ CRASH();
+#endif
+}
diff --git a/Tools/DumpRenderTree/mac/CheckedMalloc.h b/Tools/DumpRenderTree/mac/CheckedMalloc.h
new file mode 100644
index 000000000..c03bd2072
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/CheckedMalloc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+void makeLargeMallocFailSilently();
diff --git a/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig b/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig
new file mode 100644
index 000000000..11fee7169
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig
@@ -0,0 +1,62 @@
+// Copyright (C) 2009 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "CompilerVersion.xcconfig"
+
+HEADER_SEARCH_PATHS = ForwardingHeaders mac/InternalHeaders $(NEXT_ROOT)/usr/local/include/WebCoreTestSupport;
+FRAMEWORK_SEARCH_PATHS = $(SYSTEM_LIBRARY_DIR)/Frameworks/Quartz.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks;
+GCC_PREPROCESSOR_DEFINITIONS = ENABLE_DASHBOARD_SUPPORT WEBKIT_VERSION_MIN_REQUIRED=WEBKIT_VERSION_LATEST;
+DEBUG_INFORMATION_FORMAT = dwarf
+PREBINDING = NO
+GCC_C_LANGUAGE_STANDARD = gnu99
+GCC_OBJC_CALL_CXX_CDTORS = YES
+GCC_PRECOMPILE_PREFIX_HEADER = YES
+GCC_TREAT_WARNINGS_AS_ERRORS = YES
+GCC_WARN_UNUSED_FUNCTION = YES
+GCC_WARN_UNUSED_VARIABLE = YES
+GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO
+WARNING_CFLAGS = -Wall -W -Wno-unused-parameter
+LINKER_DISPLAYS_MANGLED_NAMES = YES;
+
+
+REAL_PLATFORM_NAME = $(REAL_PLATFORM_NAME_$(PLATFORM_NAME));
+REAL_PLATFORM_NAME_ = $(REAL_PLATFORM_NAME_macosx);
+REAL_PLATFORM_NAME_iphoneos = iphoneos;
+REAL_PLATFORM_NAME_iphonesimulator = iphonesimulator;
+REAL_PLATFORM_NAME_macosx = macosx;
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
+
+
+// If the target Mac OS X version does not match the current Mac OS X version then we'll want to build using the target version's SDK.
+SDKROOT = $(SDKROOT_$(MAC_OS_X_VERSION_MAJOR)_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+SDKROOT_1060_1050 = macosx10.5;
+SDKROOT_1070_1050 = macosx10.5;
+SDKROOT_1080_1050 = macosx10.5;
+SDKROOT_1090_1050 = macosx10.5;
+SDKROOT_1070_1060 = macosx10.6;
+SDKROOT_1080_1060 = macosx10.6;
+SDKROOT_1090_1060 = macosx10.6;
+SDKROOT_1080_1070 = macosx10.7;
+SDKROOT_1090_1070 = macosx10.7;
+SDKROOT_1090_1080 = macosx10.8;
diff --git a/Tools/DumpRenderTree/mac/Configurations/CompilerVersion.xcconfig b/Tools/DumpRenderTree/mac/Configurations/CompilerVersion.xcconfig
new file mode 100644
index 000000000..a8c7f75a0
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/Configurations/CompilerVersion.xcconfig
@@ -0,0 +1,84 @@
+// Copyright (C) 2009, 2010, 2011 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+IS_XCODE_0400 = $(IS_XCODE_0400_$(XCODE_VERSION_MINOR));
+IS_XCODE_0400_0400 = YES;
+
+IS_XCODE_0400_OR_0410 = $(IS_XCODE_0400_OR_0410_$(XCODE_VERSION_MINOR));
+IS_XCODE_0400_OR_0410_0400 = YES;
+IS_XCODE_0400_OR_0410_0410 = YES;
+
+// The version of the LLVM Compiler in Xcode 4.0 and earlier have difficulty compiling our code.
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS = $(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_$(XCODE_VERSION_MAJOR));
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_0300 = YES;
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_0400 = $(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_IS_XCODE_0400_$(IS_XCODE_0400));
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_IS_XCODE_0400_YES = YES;
+
+// The version of the LLVM Compiler in Xcode 4.1 and earlier do not generate fast enough code.
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS = $(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_$(XCODE_VERSION_MAJOR));
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_0300 = YES;
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_0400 = $(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_IS_XCODE_0400_OR_0410_$(IS_XCODE_0400_OR_0410));
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_IS_XCODE_0400_OR_0410_YES = YES;
+
+LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS = $(LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_$(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS));
+LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_ = YES;
+LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_YES = NO;
+
+LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS = $(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_$(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS));
+LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_ = YES;
+LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_YES = NO;
+
+
+// Use GCC 4.2 with Xcode 3.1, which includes GCC 4.2 but defaults to GCC 4.0.
+// Note that Xcode versions as new as 3.1.2 use XCODE_VERSION_ACTUAL for the minor version
+// number. Newer versions of Xcode use XCODE_VERSION_MINOR for the minor version, and
+// XCODE_VERSION_ACTUAL for the full version number.
+TARGET_GCC_VERSION = $(TARGET_GCC_VERSION_$(REAL_PLATFORM_NAME));
+TARGET_GCC_VERSION_iphoneos = LLVM_GCC_42;
+TARGET_GCC_VERSION_iphonesimulator = GCC_42;
+TARGET_GCC_VERSION_macosx = $(TARGET_GCC_VERSION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+
+TARGET_GCC_VERSION_macosx_1050 = $(TARGET_GCC_VERSION_macosx_1050_$(XCODE_VERSION_MINOR));
+TARGET_GCC_VERSION_macosx_1050_ = $(TARGET_GCC_VERSION_macosx_1050_$(XCODE_VERSION_ACTUAL));
+TARGET_GCC_VERSION_macosx_1050_0310 = GCC_42;
+TARGET_GCC_VERSION_macosx_1050_0320 = GCC_42;
+
+TARGET_GCC_VERSION_macosx_1060 = $(TARGET_GCC_VERSION_macosx_1060_AND_1070_$(CONFIGURATION));
+TARGET_GCC_VERSION_macosx_1070 = $(TARGET_GCC_VERSION_macosx_1060_AND_1070_$(CONFIGURATION));
+TARGET_GCC_VERSION_macosx_1060_AND_1070_Debug = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS));
+TARGET_GCC_VERSION_macosx_1060_AND_1070_Release = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS));
+TARGET_GCC_VERSION_macosx_1060_AND_1070_Production = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS));
+TARGET_GCC_VERSION_macosx_1060_NON_LLVM_FALLBACK = GCC_42;
+TARGET_GCC_VERSION_macosx_1070_NON_LLVM_FALLBACK = LLVM_GCC_42;
+
+TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_YES = LLVM_COMPILER;
+TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_NO = $(TARGET_GCC_VERSION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)_NON_LLVM_FALLBACK);
+
+TARGET_GCC_VERSION_macosx_1080 = LLVM_COMPILER;
+TARGET_GCC_VERSION_macosx_1090 = LLVM_COMPILER;
+
+GCC_VERSION = $(GCC_VERSION_$(TARGET_GCC_VERSION));
+GCC_VERSION_GCC_40 = 4.0;
+GCC_VERSION_GCC_42 = 4.2;
+GCC_VERSION_LLVM_GCC_42 = com.apple.compilers.llvmgcc42;
+GCC_VERSION_LLVM_COMPILER = com.apple.compilers.llvm.clang.1_0;
diff --git a/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig b/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig
new file mode 100644
index 000000000..b61d48485
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig
@@ -0,0 +1,40 @@
+// Copyright (C) 2009 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "Base.xcconfig"
+
+ARCHS = $(ARCHS_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+ARCHS_1050 = $(NATIVE_ARCH);
+ARCHS_1060 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1070 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1080 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1090 = $(ARCHS_STANDARD_32_64_BIT);
+
+ONLY_ACTIVE_ARCH = YES;
+
+MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR))
+MACOSX_DEPLOYMENT_TARGET_1050 = 10.5;
+MACOSX_DEPLOYMENT_TARGET_1060 = 10.6;
+MACOSX_DEPLOYMENT_TARGET_1070 = 10.7;
+MACOSX_DEPLOYMENT_TARGET_1080 = 10.8;
+MACOSX_DEPLOYMENT_TARGET_1090 = 10.9;
diff --git a/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig b/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig
new file mode 100644
index 000000000..754bfa962
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig
@@ -0,0 +1,28 @@
+// Copyright (C) 2009 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+OTHER_LDFLAGS = -sectcreate __DATA Ahem qt/fonts/AHEM____.TTF -sectcreate __DATA WeightWatcher100 fonts/WebKitWeightWatcher100.ttf -sectcreate __DATA WeightWatcher200 fonts/WebKitWeightWatcher200.ttf -sectcreate __DATA WeightWatcher300 fonts/WebKitWeightWatcher300.ttf -sectcreate __DATA WeightWatcher400 fonts/WebKitWeightWatcher400.ttf -sectcreate __DATA WeightWatcher500 fonts/WebKitWeightWatcher500.ttf -sectcreate __DATA WeightWatcher600 fonts/WebKitWeightWatcher600.ttf -sectcreate __DATA WeightWatcher700 fonts/WebKitWeightWatcher700.ttf -sectcreate __DATA WeightWatcher800 fonts/WebKitWeightWatcher800.ttf -sectcreate __DATA WeightWatcher900 fonts/WebKitWeightWatcher900.ttf
+LD_RUNPATH_SEARCH_PATHS = "@loader_path/.";
+PRODUCT_NAME = DumpRenderTree
+GCC_ENABLE_OBJC_EXCEPTIONS = YES
+GCC_PREFIX_HEADER = DumpRenderTreePrefix.h
diff --git a/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig b/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig
new file mode 100644
index 000000000..35968afcf
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig
@@ -0,0 +1,24 @@
+// Copyright (C) 2009 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+PRODUCT_NAME = ImageDiff
diff --git a/Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig b/Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig
new file mode 100644
index 000000000..22ea4c230
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig
@@ -0,0 +1,29 @@
+// Copyright (C) 2009 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+PRODUCT_NAME = TestNetscapePlugIn
+WRAPPER_EXTENSION = plugin
+INFOPLIST_FILE = TestNetscapePlugIn.subproj/Info.plist
+INSTALL_PATH = "$(USER_LIBRARY_DIR)/Plugins"
+WARNING_CFLAGS = -Wmost -Wno-four-char-constants -Wno-unknown-pragmas
+LIBRARY_STYLE = BUNDLE
diff --git a/Tools/DumpRenderTree/mac/DumpRenderTree.mm b/Tools/DumpRenderTree/mac/DumpRenderTree.mm
new file mode 100644
index 000000000..b25fa2a61
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTree.mm
@@ -0,0 +1,1353 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "DumpRenderTree.h"
+
+#import "AccessibilityController.h"
+#import "CheckedMalloc.h"
+#import "DumpRenderTreeDraggingInfo.h"
+#import "DumpRenderTreePasteboard.h"
+#import "DumpRenderTreeWindow.h"
+#import "EditingDelegate.h"
+#import "EventSendingController.h"
+#import "FrameLoadDelegate.h"
+#import "HistoryDelegate.h"
+#import "JavaScriptThreading.h"
+#import "LayoutTestController.h"
+#import "MockGeolocationProvider.h"
+#import "NavigationController.h"
+#import "ObjCPlugin.h"
+#import "ObjCPluginFunction.h"
+#import "PixelDumpSupport.h"
+#import "PolicyDelegate.h"
+#import "ResourceLoadDelegate.h"
+#import "StorageTrackerDelegate.h"
+#import "UIDelegate.h"
+#import "WebArchiveDumpSupport.h"
+#import "WebCoreTestSupport.h"
+#import "WorkQueue.h"
+#import "WorkQueueItem.h"
+#import <Carbon/Carbon.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <WebCore/FoundationExtras.h>
+#import <WebKit/DOMElement.h>
+#import <WebKit/DOMExtensions.h>
+#import <WebKit/DOMRange.h>
+#import <WebKit/WebArchive.h>
+#import <WebKit/WebBackForwardList.h>
+#import <WebKit/WebCache.h>
+#import <WebKit/WebCoreStatistics.h>
+#import <WebKit/WebDataSourcePrivate.h>
+#import <WebKit/WebDatabaseManagerPrivate.h>
+#import <WebKit/WebDocumentPrivate.h>
+#import <WebKit/WebDeviceOrientationProviderMock.h>
+#import <WebKit/WebEditingDelegate.h>
+#import <WebKit/WebFrameView.h>
+#import <WebKit/WebHistory.h>
+#import <WebKit/WebHistoryItemPrivate.h>
+#import <WebKit/WebInspector.h>
+#import <WebKit/WebKitNSStringExtras.h>
+#import <WebKit/WebPluginDatabase.h>
+#import <WebKit/WebPreferences.h>
+#import <WebKit/WebPreferencesPrivate.h>
+#import <WebKit/WebPreferenceKeysPrivate.h>
+#import <WebKit/WebResourceLoadDelegate.h>
+#import <WebKit/WebStorageManagerPrivate.h>
+#import <WebKit/WebTypesInternal.h>
+#import <WebKit/WebViewPrivate.h>
+#import <getopt.h>
+#import <objc/objc-runtime.h>
+#import <wtf/Assertions.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/Threading.h>
+#import <wtf/OwnPtr.h>
+
+extern "C" {
+#import <mach-o/getsect.h>
+}
+
+using namespace std;
+
+@interface DumpRenderTreeApplication : NSApplication
+@end
+
+@interface DumpRenderTreeEvent : NSEvent
+@end
+
+@interface NSURLRequest (PrivateThingsWeShouldntReallyUse)
++(void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host;
+@end
+
+static void runTest(const string& testPathOrURL);
+
+// Deciding when it's OK to dump out the state is a bit tricky. All these must be true:
+// - There is no load in progress
+// - There is no work queued up (see workQueue var, below)
+// - waitToDump==NO. This means either waitUntilDone was never called, or it was called
+// and notifyDone was called subsequently.
+// Note that the call to notifyDone and the end of the load can happen in either order.
+
+volatile bool done;
+
+NavigationController* gNavigationController = 0;
+RefPtr<LayoutTestController> gLayoutTestController;
+
+WebFrame *mainFrame = 0;
+// This is the topmost frame that is loading, during a given load, or nil when no load is
+// in progress. Usually this is the same as the main frame, but not always. In the case
+// where a frameset is loaded, and then new content is loaded into one of the child frames,
+// that child frame is the "topmost frame that is loading".
+WebFrame *topLoadingFrame = nil; // !nil iff a load is in progress
+
+
+CFMutableSetRef disallowedURLs = 0;
+CFRunLoopTimerRef waitToDumpWatchdog = 0;
+
+// Delegates
+static FrameLoadDelegate *frameLoadDelegate;
+static UIDelegate *uiDelegate;
+static EditingDelegate *editingDelegate;
+static ResourceLoadDelegate *resourceLoadDelegate;
+static HistoryDelegate *historyDelegate;
+PolicyDelegate *policyDelegate;
+StorageTrackerDelegate *storageDelegate;
+
+static int dumpPixels;
+static int threaded;
+static int dumpTree = YES;
+static int forceComplexText;
+static int gcBetweenTests;
+static BOOL printSeparators;
+static RetainPtr<CFStringRef> persistentUserStyleSheetLocation;
+
+static WebHistoryItem *prevTestBFItem = nil; // current b/f item at the end of the previous test
+
+#if __OBJC2__
+static void swizzleAllMethods(Class imposter, Class original)
+{
+ unsigned int imposterMethodCount;
+ Method* imposterMethods = class_copyMethodList(imposter, &imposterMethodCount);
+
+ unsigned int originalMethodCount;
+ Method* originalMethods = class_copyMethodList(original, &originalMethodCount);
+
+ for (unsigned int i = 0; i < imposterMethodCount; i++) {
+ SEL imposterMethodName = method_getName(imposterMethods[i]);
+
+ // Attempt to add the method to the original class. If it fails, the method already exists and we should
+ // instead exchange the implementations.
+ if (class_addMethod(original, imposterMethodName, method_getImplementation(imposterMethods[i]), method_getTypeEncoding(imposterMethods[i])))
+ continue;
+
+ unsigned int j = 0;
+ for (; j < originalMethodCount; j++) {
+ SEL originalMethodName = method_getName(originalMethods[j]);
+ if (sel_isEqual(imposterMethodName, originalMethodName))
+ break;
+ }
+
+ // If class_addMethod failed above then the method must exist on the original class.
+ ASSERT(j < originalMethodCount);
+ method_exchangeImplementations(imposterMethods[i], originalMethods[j]);
+ }
+
+ free(imposterMethods);
+ free(originalMethods);
+}
+#endif
+
+static void poseAsClass(const char* imposter, const char* original)
+{
+ Class imposterClass = objc_getClass(imposter);
+ Class originalClass = objc_getClass(original);
+
+#if !__OBJC2__
+ class_poseAs(imposterClass, originalClass);
+#else
+
+ // Swizzle instance methods
+ swizzleAllMethods(imposterClass, originalClass);
+ // and then class methods
+ swizzleAllMethods(object_getClass(imposterClass), object_getClass(originalClass));
+#endif
+}
+
+void setPersistentUserStyleSheetLocation(CFStringRef url)
+{
+ persistentUserStyleSheetLocation = url;
+}
+
+static bool shouldIgnoreWebCoreNodeLeaks(const string& URLString)
+{
+ static char* const ignoreSet[] = {
+ // Keeping this infrastructure around in case we ever need it again.
+ };
+ static const int ignoreSetCount = sizeof(ignoreSet) / sizeof(char*);
+
+ for (int i = 0; i < ignoreSetCount; i++) {
+ // FIXME: ignore case
+ string curIgnore(ignoreSet[i]);
+ // Match at the end of the URLString
+ if (!URLString.compare(URLString.length() - curIgnore.length(), curIgnore.length(), curIgnore))
+ return true;
+ }
+ return false;
+}
+
+static NSSet *allowedFontFamilySet()
+{
+ static NSSet *fontFamiliySet = [[NSSet setWithObjects:
+ @"Ahem",
+ @"Al Bayan",
+ @"American Typewriter",
+ @"Andale Mono",
+ @"Apple Braille",
+ @"Apple Color Emoji",
+ @"Apple Chancery",
+ @"Apple Garamond BT",
+ @"Apple LiGothic",
+ @"Apple LiSung",
+ @"Apple Symbols",
+ @"AppleGothic",
+ @"AppleMyungjo",
+ @"Arial Black",
+ @"Arial Hebrew",
+ @"Arial Narrow",
+ @"Arial Rounded MT Bold",
+ @"Arial Unicode MS",
+ @"Arial",
+ @"Ayuthaya",
+ @"Baghdad",
+ @"Baskerville",
+ @"BiauKai",
+ @"Big Caslon",
+ @"Brush Script MT",
+ @"Chalkboard",
+ @"Chalkduster",
+ @"Charcoal CY",
+ @"Cochin",
+ @"Comic Sans MS",
+ @"Copperplate",
+ @"Corsiva Hebrew",
+ @"Courier New",
+ @"Courier",
+ @"DecoType Naskh",
+ @"Devanagari MT",
+ @"Didot",
+ @"Euphemia UCAS",
+ @"Futura",
+ @"GB18030 Bitmap",
+ @"Geeza Pro",
+ @"Geneva CY",
+ @"Geneva",
+ @"Georgia",
+ @"Gill Sans",
+ @"Gujarati MT",
+ @"GungSeo",
+ @"Gurmukhi MT",
+ @"HeadLineA",
+ @"Hei",
+ @"Heiti SC",
+ @"Heiti TC",
+ @"Helvetica CY",
+ @"Helvetica Neue",
+ @"Helvetica",
+ @"Herculanum",
+ @"Hiragino Kaku Gothic Pro",
+ @"Hiragino Kaku Gothic ProN",
+ @"Hiragino Kaku Gothic Std",
+ @"Hiragino Kaku Gothic StdN",
+ @"Hiragino Maru Gothic Pro",
+ @"Hiragino Maru Gothic ProN",
+ @"Hiragino Mincho Pro",
+ @"Hiragino Mincho ProN",
+ @"Hiragino Sans GB",
+ @"Hoefler Text",
+ @"Impact",
+ @"InaiMathi",
+ @"Kai",
+ @"Kailasa",
+ @"Kokonor",
+ @"Krungthep",
+ @"KufiStandardGK",
+ @"LiHei Pro",
+ @"LiSong Pro",
+ @"Lucida Grande",
+ @"Marker Felt",
+ @"Menlo",
+ @"Microsoft Sans Serif",
+ @"Monaco",
+ @"Mshtakan",
+ @"Nadeem",
+ @"New Peninim MT",
+ @"Optima",
+ @"Osaka",
+ @"Papyrus",
+ @"PCMyungjo",
+ @"PilGi",
+ @"Plantagenet Cherokee",
+ @"Raanana",
+ @"Sathu",
+ @"Silom",
+ @"Skia",
+ @"STFangsong",
+ @"STHeiti",
+ @"STKaiti",
+ @"STSong",
+ @"Symbol",
+ @"Tahoma",
+ @"Thonburi",
+ @"Times New Roman",
+ @"Times",
+ @"Trebuchet MS",
+ @"Verdana",
+ @"Webdings",
+ @"WebKit WeightWatcher",
+ @"Wingdings 2",
+ @"Wingdings 3",
+ @"Wingdings",
+ @"Zapf Dingbats",
+ @"Zapfino",
+ nil] retain];
+
+ return fontFamiliySet;
+}
+
+static IMP appKitAvailableFontFamiliesIMP;
+static IMP appKitAvailableFontsIMP;
+
+static NSArray *drt_NSFontManager_availableFontFamilies(id self, SEL _cmd)
+{
+ static NSArray *availableFontFamilies;
+ if (availableFontFamilies)
+ return availableFontFamilies;
+
+ NSArray *availableFamilies = appKitAvailableFontFamiliesIMP(self, _cmd);
+
+ NSMutableSet *prunedFamiliesSet = [NSMutableSet setWithArray:availableFamilies];
+ [prunedFamiliesSet intersectSet:allowedFontFamilySet()];
+
+ availableFontFamilies = [[prunedFamiliesSet allObjects] retain];
+ return availableFontFamilies;
+}
+
+static NSArray *drt_NSFontManager_availableFonts(id self, SEL _cmd)
+{
+ static NSArray *availableFonts;
+ if (availableFonts)
+ return availableFonts;
+
+ NSSet *allowedFamilies = allowedFontFamilySet();
+ NSMutableArray *availableFontList = [[NSMutableArray alloc] initWithCapacity:[allowedFamilies count] * 2];
+ for (NSString *fontFamily in allowedFontFamilySet()) {
+ NSArray* fontsForFamily = [[NSFontManager sharedFontManager] availableMembersOfFontFamily:fontFamily];
+ for (NSArray* fontInfo in fontsForFamily) {
+ // Font name is the first entry in the array.
+ [availableFontList addObject:[fontInfo objectAtIndex:0]];
+ }
+ }
+
+ availableFonts = availableFontList;
+ return availableFonts;
+}
+
+static void swizzleNSFontManagerMethods()
+{
+ Method availableFontFamiliesMethod = class_getInstanceMethod(objc_getClass("NSFontManager"), @selector(availableFontFamilies));
+ ASSERT(availableFontFamiliesMethod);
+ if (!availableFontFamiliesMethod) {
+ NSLog(@"Failed to swizzle the \"availableFontFamilies\" method on NSFontManager");
+ return;
+ }
+
+ appKitAvailableFontFamiliesIMP = method_setImplementation(availableFontFamiliesMethod, (IMP)drt_NSFontManager_availableFontFamilies);
+
+ Method availableFontsMethod = class_getInstanceMethod(objc_getClass("NSFontManager"), @selector(availableFonts));
+ ASSERT(availableFontsMethod);
+ if (!availableFontsMethod) {
+ NSLog(@"Failed to swizzle the \"availableFonts\" method on NSFontManager");
+ return;
+ }
+
+ appKitAvailableFontsIMP = method_setImplementation(availableFontsMethod, (IMP)drt_NSFontManager_availableFonts);
+}
+
+static void activateTestingFonts()
+{
+ // Work around <rdar://problem/6698023> by activating fonts from disk
+ // FIXME: This code can be removed once <rdar://problem/6698023> is addressed.
+
+ static const char* fontFileNames[] = {
+ "AHEM____.TTF",
+ "WebKitWeightWatcher100.ttf",
+ "WebKitWeightWatcher200.ttf",
+ "WebKitWeightWatcher300.ttf",
+ "WebKitWeightWatcher400.ttf",
+ "WebKitWeightWatcher500.ttf",
+ "WebKitWeightWatcher600.ttf",
+ "WebKitWeightWatcher700.ttf",
+ "WebKitWeightWatcher800.ttf",
+ "WebKitWeightWatcher900.ttf",
+ 0
+ };
+
+ NSMutableArray *fontURLs = [NSMutableArray array];
+ NSURL *resourcesDirectory = [NSURL URLWithString:@"DumpRenderTree.resources" relativeToURL:[[NSBundle mainBundle] executableURL]];
+ for (unsigned i = 0; fontFileNames[i]; ++i) {
+ NSURL *fontURL = [resourcesDirectory URLByAppendingPathComponent:[NSString stringWithUTF8String:fontFileNames[i]]];
+ [fontURLs addObject:[fontURL absoluteURL]];
+ }
+
+ CFArrayRef errors = 0;
+ if (!CTFontManagerRegisterFontsForURLs((CFArrayRef)fontURLs, kCTFontManagerScopeProcess, &errors)) {
+ NSLog(@"Failed to activate fonts: %@", errors);
+ CFRelease(errors);
+ exit(1);
+ }
+}
+
+static void adjustFonts()
+{
+ swizzleNSFontManagerMethods();
+ activateTestingFonts();
+}
+
+WebView *createWebViewAndOffscreenWindow()
+{
+ NSRect rect = NSMakeRect(0, 0, LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight);
+ WebView *webView = [[WebView alloc] initWithFrame:rect frameName:nil groupName:@"org.webkit.DumpRenderTree"];
+
+ [webView setUIDelegate:uiDelegate];
+ [webView setFrameLoadDelegate:frameLoadDelegate];
+ [webView setEditingDelegate:editingDelegate];
+ [webView setResourceLoadDelegate:resourceLoadDelegate];
+ [webView _setGeolocationProvider:[MockGeolocationProvider shared]];
+ [webView _setDeviceOrientationProvider:[WebDeviceOrientationProviderMock shared]];
+
+ // Register the same schemes that Safari does
+ [WebView registerURLSchemeAsLocal:@"feed"];
+ [WebView registerURLSchemeAsLocal:@"feeds"];
+ [WebView registerURLSchemeAsLocal:@"feedsearch"];
+
+ [webView setContinuousSpellCheckingEnabled:YES];
+ [webView setGrammarCheckingEnabled:YES];
+ [webView setInteractiveFormValidationEnabled:YES];
+ [webView setValidationMessageTimerMagnification:-1];
+
+ // To make things like certain NSViews, dragging, and plug-ins work, put the WebView a window, but put it off-screen so you don't see it.
+ // Put it at -10000, -10000 in "flipped coordinates", since WebCore and the DOM use flipped coordinates.
+ NSRect windowRect = NSOffsetRect(rect, -10000, [(NSScreen *)[[NSScreen screens] objectAtIndex:0] frame].size.height - rect.size.height + 10000);
+ DumpRenderTreeWindow *window = [[DumpRenderTreeWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
+
+ [window setColorSpace:[[NSScreen mainScreen] colorSpace]];
+ [[window contentView] addSubview:webView];
+ [window orderBack:nil];
+ [window setAutodisplay:NO];
+
+ [window startListeningForAcceleratedCompositingChanges];
+
+ // For reasons that are not entirely clear, the following pair of calls makes WebView handle its
+ // dynamic scrollbars properly. Without it, every frame will always have scrollbars.
+ NSBitmapImageRep *imageRep = [webView bitmapImageRepForCachingDisplayInRect:[webView bounds]];
+ [webView cacheDisplayInRect:[webView bounds] toBitmapImageRep:imageRep];
+
+ return webView;
+}
+
+static NSString *libraryPathForDumpRenderTree()
+{
+ //FIXME: This may not be sufficient to prevent interactions/crashes
+ //when running more than one copy of DumpRenderTree.
+ //See https://bugs.webkit.org/show_bug.cgi?id=10906
+ char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
+ if (dumpRenderTreeTemp)
+ return [[NSFileManager defaultManager] stringWithFileSystemRepresentation:dumpRenderTreeTemp length:strlen(dumpRenderTreeTemp)];
+ else
+ return [@"~/Library/Application Support/DumpRenderTree" stringByExpandingTildeInPath];
+}
+
+// Called before each test.
+static void resetDefaultsToConsistentValues()
+{
+ static const int NoFontSmoothing = 0;
+ static const int BlueTintedAppearance = 1;
+
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setInteger:4 forKey:@"AppleAntiAliasingThreshold"]; // smallest font size to CG should perform antialiasing on
+ [defaults setInteger:NoFontSmoothing forKey:@"AppleFontSmoothing"];
+ [defaults setInteger:BlueTintedAppearance forKey:@"AppleAquaColorVariant"];
+ [defaults setObject:@"0.709800 0.835300 1.000000" forKey:@"AppleHighlightColor"];
+ [defaults setObject:@"0.500000 0.500000 0.500000" forKey:@"AppleOtherHighlightColor"];
+ [defaults setObject:[NSArray arrayWithObject:@"en"] forKey:@"AppleLanguages"];
+ [defaults setBool:YES forKey:WebKitEnableFullDocumentTeardownPreferenceKey];
+ [defaults setBool:YES forKey:WebKitFullScreenEnabledPreferenceKey];
+
+ // Scrollbars are drawn either using AppKit (which uses NSUserDefaults) or using HIToolbox (which uses CFPreferences / kCFPreferencesAnyApplication / kCFPreferencesCurrentUser / kCFPreferencesAnyHost)
+ [defaults setObject:@"DoubleMax" forKey:@"AppleScrollBarVariant"];
+ RetainPtr<CFTypeRef> initialValue = CFPreferencesCopyValue(CFSTR("AppleScrollBarVariant"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
+ CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), CFSTR("DoubleMax"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
+#ifndef __LP64__
+ // See <rdar://problem/6347388>.
+ ThemeScrollBarArrowStyle style;
+ GetThemeScrollBarArrowStyle(&style); // Force HIToolbox to read from CFPreferences
+#endif
+
+ [defaults setBool:NO forKey:@"AppleScrollAnimationEnabled"];
+ [defaults setBool:NO forKey:@"NSOverlayScrollersEnabled"];
+ [defaults setObject:@"Always" forKey:@"AppleShowScrollBars"];
+
+ if (initialValue)
+ CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), initialValue.get(), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
+
+ NSString *path = libraryPathForDumpRenderTree();
+ [defaults setObject:[path stringByAppendingPathComponent:@"Databases"] forKey:WebDatabaseDirectoryDefaultsKey];
+ [defaults setObject:[path stringByAppendingPathComponent:@"LocalStorage"] forKey:WebStorageDirectoryDefaultsKey];
+ [defaults setObject:[path stringByAppendingPathComponent:@"LocalCache"] forKey:WebKitLocalCacheDefaultsKey];
+
+ WebPreferences *preferences = [WebPreferences standardPreferences];
+
+ [preferences setAllowUniversalAccessFromFileURLs:YES];
+ [preferences setAllowFileAccessFromFileURLs:YES];
+ [preferences setStandardFontFamily:@"Times"];
+ [preferences setFixedFontFamily:@"Courier"];
+ [preferences setSerifFontFamily:@"Times"];
+ [preferences setSansSerifFontFamily:@"Helvetica"];
+ [preferences setCursiveFontFamily:@"Apple Chancery"];
+ [preferences setFantasyFontFamily:@"Papyrus"];
+ [preferences setPictographFontFamily:@"Apple Color Emoji"];
+ [preferences setDefaultFontSize:16];
+ [preferences setDefaultFixedFontSize:13];
+ [preferences setMinimumFontSize:0];
+ [preferences setJavaEnabled:NO];
+ [preferences setJavaScriptEnabled:YES];
+ [preferences setEditableLinkBehavior:WebKitEditableLinkOnlyLiveWithShiftKey];
+ [preferences setTabsToLinks:NO];
+ [preferences setDOMPasteAllowed:YES];
+ [preferences setShouldPrintBackgrounds:YES];
+ [preferences setCacheModel:WebCacheModelDocumentBrowser];
+ [preferences setXSSAuditorEnabled:NO];
+ [preferences setExperimentalNotificationsEnabled:NO];
+ [preferences setPlugInsEnabled:YES];
+
+ [preferences setPrivateBrowsingEnabled:NO];
+ [preferences setAuthorAndUserStylesEnabled:YES];
+ [preferences setJavaScriptCanOpenWindowsAutomatically:YES];
+ [preferences setJavaScriptCanAccessClipboard:YES];
+ [preferences setOfflineWebApplicationCacheEnabled:YES];
+ [preferences setDeveloperExtrasEnabled:NO];
+ [preferences setLoadsImagesAutomatically:YES];
+ [preferences setLoadsSiteIconsIgnoringImageLoadingPreference:NO];
+ [preferences setFrameFlatteningEnabled:NO];
+ [preferences setSpatialNavigationEnabled:NO];
+ [preferences setEditingBehavior:WebKitEditingMacBehavior];
+ if (persistentUserStyleSheetLocation) {
+ [preferences setUserStyleSheetLocation:[NSURL URLWithString:(NSString *)(persistentUserStyleSheetLocation.get())]];
+ [preferences setUserStyleSheetEnabled:YES];
+ } else
+ [preferences setUserStyleSheetEnabled:NO];
+
+ // The back/forward cache is causing problems due to layouts during transition from one page to another.
+ // So, turn it off for now, but we might want to turn it back on some day.
+ [preferences setUsesPageCache:NO];
+ [preferences setAcceleratedCompositingEnabled:YES];
+#if USE(CA) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ [preferences setCanvasUsesAcceleratedDrawing:YES];
+ [preferences setAcceleratedDrawingEnabled:NO];
+#endif
+ [preferences setWebGLEnabled:NO];
+ [preferences setUsePreHTML5ParserQuirks:NO];
+ [preferences setAsynchronousSpellCheckingEnabled:NO];
+ [preferences setHixie76WebSocketProtocolEnabled:YES];
+
+#if ENABLE(WEB_AUDIO)
+ [preferences setWebAudioEnabled:YES];
+#endif
+
+ [WebPreferences _setCurrentNetworkLoaderSessionCookieAcceptPolicy:NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain];
+
+ LayoutTestController::setSerializeHTTPLoads(false);
+
+ setlocale(LC_ALL, "");
+}
+
+// Called once on DumpRenderTree startup.
+static void setDefaultsToConsistentValuesForTesting()
+{
+ resetDefaultsToConsistentValues();
+
+ NSString *path = libraryPathForDumpRenderTree();
+ NSURLCache *sharedCache =
+ [[NSURLCache alloc] initWithMemoryCapacity:1024 * 1024
+ diskCapacity:0
+ diskPath:[path stringByAppendingPathComponent:@"URLCache"]];
+ [NSURLCache setSharedURLCache:sharedCache];
+ [sharedCache release];
+
+ [WebPreferences _switchNetworkLoaderToNewTestingSession];
+}
+
+static void* runThread(void* arg)
+{
+ static ThreadIdentifier previousId = 0;
+ ThreadIdentifier currentId = currentThread();
+ // Verify 2 successive threads do not get the same Id.
+ ASSERT(previousId != currentId);
+ previousId = currentId;
+ return 0;
+}
+
+static void testThreadIdentifierMap()
+{
+ // Imitate 'foreign' threads that are not created by WTF.
+ pthread_t pthread;
+ pthread_create(&pthread, 0, &runThread, 0);
+ pthread_join(pthread, 0);
+
+ pthread_create(&pthread, 0, &runThread, 0);
+ pthread_join(pthread, 0);
+
+ // Now create another thread using WTF. On OSX, it will have the same pthread handle
+ // but should get a different ThreadIdentifier.
+ createThread(runThread, 0, "DumpRenderTree: test");
+}
+
+static void crashHandler(int sig)
+{
+ char *signalName = strsignal(sig);
+ write(STDERR_FILENO, signalName, strlen(signalName));
+ write(STDERR_FILENO, "\n", 1);
+ restoreMainDisplayColorProfile(0);
+ exit(128 + sig);
+}
+
+static void installSignalHandlers()
+{
+ signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */
+ signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */
+ signal(SIGEMT, crashHandler); /* 7: EMT instruction */
+ signal(SIGFPE, crashHandler); /* 8: floating point exception */
+ signal(SIGBUS, crashHandler); /* 10: bus error */
+ signal(SIGSEGV, crashHandler); /* 11: segmentation violation */
+ signal(SIGSYS, crashHandler); /* 12: bad argument to system call */
+ signal(SIGPIPE, crashHandler); /* 13: write on a pipe with no reader */
+ signal(SIGXCPU, crashHandler); /* 24: exceeded CPU time limit */
+ signal(SIGXFSZ, crashHandler); /* 25: exceeded file size limit */
+}
+
+static void allocateGlobalControllers()
+{
+ // FIXME: We should remove these and move to the ObjC standard [Foo sharedInstance] model
+ gNavigationController = [[NavigationController alloc] init];
+ frameLoadDelegate = [[FrameLoadDelegate alloc] init];
+ uiDelegate = [[UIDelegate alloc] init];
+ editingDelegate = [[EditingDelegate alloc] init];
+ resourceLoadDelegate = [[ResourceLoadDelegate alloc] init];
+ policyDelegate = [[PolicyDelegate alloc] init];
+ historyDelegate = [[HistoryDelegate alloc] init];
+ storageDelegate = [[StorageTrackerDelegate alloc] init];
+}
+
+// ObjC++ doens't seem to let me pass NSObject*& sadly.
+static inline void releaseAndZero(NSObject** object)
+{
+ [*object release];
+ *object = nil;
+}
+
+static void releaseGlobalControllers()
+{
+ releaseAndZero(&gNavigationController);
+ releaseAndZero(&frameLoadDelegate);
+ releaseAndZero(&editingDelegate);
+ releaseAndZero(&resourceLoadDelegate);
+ releaseAndZero(&uiDelegate);
+ releaseAndZero(&policyDelegate);
+ releaseAndZero(&storageDelegate);
+}
+
+static void initializeGlobalsFromCommandLineOptions(int argc, const char *argv[])
+{
+ struct option options[] = {
+ {"notree", no_argument, &dumpTree, NO},
+ {"pixel-tests", no_argument, &dumpPixels, YES},
+ {"tree", no_argument, &dumpTree, YES},
+ {"threaded", no_argument, &threaded, YES},
+ {"complex-text", no_argument, &forceComplexText, YES},
+ {"gc-between-tests", no_argument, &gcBetweenTests, YES},
+ {NULL, 0, NULL, 0}
+ };
+
+ int option;
+ while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) {
+ switch (option) {
+ case '?': // unknown or ambiguous option
+ case ':': // missing argument
+ exit(1);
+ break;
+ }
+ }
+}
+
+static void addTestPluginsToPluginSearchPath(const char* executablePath)
+{
+ NSString *pwd = [[NSString stringWithUTF8String:executablePath] stringByDeletingLastPathComponent];
+ [WebPluginDatabase setAdditionalWebPlugInPaths:[NSArray arrayWithObject:pwd]];
+ [[WebPluginDatabase sharedDatabase] refresh];
+}
+
+static bool useLongRunningServerMode(int argc, const char *argv[])
+{
+ // This assumes you've already called getopt_long
+ return (argc == optind+1 && strcmp(argv[optind], "-") == 0);
+}
+
+static void runTestingServerLoop()
+{
+ // When DumpRenderTree run in server mode, we just wait around for file names
+ // to be passed to us and read each in turn, passing the results back to the client
+ char filenameBuffer[2048];
+ while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
+ char *newLineCharacter = strchr(filenameBuffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (strlen(filenameBuffer) == 0)
+ continue;
+
+ runTest(filenameBuffer);
+ }
+}
+
+static void prepareConsistentTestingEnvironment()
+{
+ poseAsClass("DumpRenderTreePasteboard", "NSPasteboard");
+ poseAsClass("DumpRenderTreeEvent", "NSEvent");
+
+ setDefaultsToConsistentValuesForTesting();
+ adjustFonts();
+
+ if (dumpPixels)
+ setupMainDisplayColorProfile();
+ allocateGlobalControllers();
+
+ makeLargeMallocFailSilently();
+}
+
+void dumpRenderTree(int argc, const char *argv[])
+{
+ initializeGlobalsFromCommandLineOptions(argc, argv);
+ prepareConsistentTestingEnvironment();
+ addTestPluginsToPluginSearchPath(argv[0]);
+ if (dumpPixels)
+ installSignalHandlers();
+
+ if (forceComplexText)
+ [WebView _setAlwaysUsesComplexTextCodePath:YES];
+
+ WebView *webView = createWebViewAndOffscreenWindow();
+ mainFrame = [webView mainFrame];
+
+ [[NSURLCache sharedURLCache] removeAllCachedResponses];
+ [WebCache empty];
+
+ // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL
+ // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1.
+ [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"localhost"];
+ [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"127.0.0.1"];
+
+ // http://webkit.org/b/32689
+ testThreadIdentifierMap();
+
+ if (threaded)
+ startJavaScriptThreads();
+
+ if (useLongRunningServerMode(argc, argv)) {
+ printSeparators = YES;
+ runTestingServerLoop();
+ } else {
+ printSeparators = (optind < argc-1 || (dumpPixels && dumpTree));
+ for (int i = optind; i != argc; ++i)
+ runTest(argv[i]);
+ }
+
+ if (threaded)
+ stopJavaScriptThreads();
+
+ NSWindow *window = [webView window];
+ [webView close];
+ mainFrame = nil;
+
+ // Work around problem where registering drag types leaves an outstanding
+ // "perform selector" on the window, which retains the window. It's a bit
+ // inelegant and perhaps dangerous to just blow them all away, but in practice
+ // it probably won't cause any trouble (and this is just a test tool, after all).
+ [NSObject cancelPreviousPerformRequestsWithTarget:window];
+
+ [window close]; // releases when closed
+ [webView release];
+
+ releaseGlobalControllers();
+
+ [DumpRenderTreePasteboard releaseLocalPasteboards];
+
+ // FIXME: This should be moved onto LayoutTestController and made into a HashSet
+ if (disallowedURLs) {
+ CFRelease(disallowedURLs);
+ disallowedURLs = 0;
+ }
+
+ if (dumpPixels)
+ restoreMainDisplayColorProfile(0);
+}
+
+int main(int argc, const char *argv[])
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [DumpRenderTreeApplication sharedApplication]; // Force AppKit to init itself
+ dumpRenderTree(argc, argv);
+ [WebCoreStatistics garbageCollectJavaScriptObjects];
+ [WebCoreStatistics emptyCache]; // Otherwise SVGImages trigger false positives for Frame/Node counts
+ [pool release];
+ return 0;
+}
+
+static NSInteger compareHistoryItems(id item1, id item2, void *context)
+{
+ return [[item1 target] caseInsensitiveCompare:[item2 target]];
+}
+
+static NSData *dumpAudio()
+{
+ const char *encodedAudioData = gLayoutTestController->encodedAudioData().c_str();
+
+ NSData *data = [NSData dataWithBytes:encodedAudioData length:gLayoutTestController->encodedAudioData().length()];
+ return data;
+}
+
+static void dumpHistoryItem(WebHistoryItem *item, int indent, BOOL current)
+{
+ int start = 0;
+ if (current) {
+ printf("curr->");
+ start = 6;
+ }
+ for (int i = start; i < indent; i++)
+ putchar(' ');
+
+ NSString *urlString = [item URLString];
+ if ([[NSURL URLWithString:urlString] isFileURL]) {
+ NSRange range = [urlString rangeOfString:@"/LayoutTests/"];
+ urlString = [@"(file test):" stringByAppendingString:[urlString substringFromIndex:(range.length + range.location)]];
+ }
+
+ printf("%s", [urlString UTF8String]);
+ NSString *target = [item target];
+ if (target && [target length] > 0)
+ printf(" (in frame \"%s\")", [target UTF8String]);
+ if ([item isTargetItem])
+ printf(" **nav target**");
+ putchar('\n');
+ NSArray *kids = [item children];
+ if (kids) {
+ // must sort to eliminate arbitrary result ordering which defeats reproducible testing
+ kids = [kids sortedArrayUsingFunction:&compareHistoryItems context:nil];
+ for (unsigned i = 0; i < [kids count]; i++)
+ dumpHistoryItem([kids objectAtIndex:i], indent+4, NO);
+ }
+}
+
+static void dumpFrameScrollPosition(WebFrame *f)
+{
+ WebScriptObject* scriptObject = [f windowObject];
+ NSPoint scrollPosition = NSMakePoint(
+ [[scriptObject valueForKey:@"pageXOffset"] floatValue],
+ [[scriptObject valueForKey:@"pageYOffset"] floatValue]);
+ if (ABS(scrollPosition.x) > 0.00000001 || ABS(scrollPosition.y) > 0.00000001) {
+ if ([f parentFrame] != nil)
+ printf("frame '%s' ", [[f name] UTF8String]);
+ printf("scrolled to %.f,%.f\n", scrollPosition.x, scrollPosition.y);
+ }
+
+ if (gLayoutTestController->dumpChildFrameScrollPositions()) {
+ NSArray *kids = [f childFrames];
+ if (kids)
+ for (unsigned i = 0; i < [kids count]; i++)
+ dumpFrameScrollPosition([kids objectAtIndex:i]);
+ }
+}
+
+static NSString *dumpFramesAsText(WebFrame *frame)
+{
+ DOMDocument *document = [frame DOMDocument];
+ DOMElement *documentElement = [document documentElement];
+
+ if (!documentElement)
+ return @"";
+
+ NSMutableString *result = [[[NSMutableString alloc] init] autorelease];
+
+ // Add header for all but the main frame.
+ if ([frame parentFrame])
+ result = [NSMutableString stringWithFormat:@"\n--------\nFrame: '%@'\n--------\n", [frame name]];
+
+ [result appendFormat:@"%@\n", [documentElement innerText]];
+
+ if (gLayoutTestController->dumpChildFramesAsText()) {
+ NSArray *kids = [frame childFrames];
+ if (kids) {
+ for (unsigned i = 0; i < [kids count]; i++)
+ [result appendString:dumpFramesAsText([kids objectAtIndex:i])];
+ }
+ }
+
+ return result;
+}
+
+static NSData *dumpFrameAsPDF(WebFrame *frame)
+{
+ if (!frame)
+ return nil;
+
+ // Sadly we have to dump to a file and then read from that file again
+ // +[NSPrintOperation PDFOperationWithView:insideRect:] requires a rect and prints to a single page
+ // likewise +[NSView dataWithPDFInsideRect:] also prints to a single continuous page
+ // The goal of this function is to test "real" printing across multiple pages.
+ // FIXME: It's possible there might be printing SPI to let us print a multi-page PDF to an NSData object
+ NSString *path = [libraryPathForDumpRenderTree() stringByAppendingPathComponent:@"test.pdf"];
+
+ NSMutableDictionary *printInfoDict = [NSMutableDictionary dictionaryWithDictionary:[[NSPrintInfo sharedPrintInfo] dictionary]];
+ [printInfoDict setObject:NSPrintSaveJob forKey:NSPrintJobDisposition];
+ [printInfoDict setObject:path forKey:NSPrintSavePath];
+
+ NSPrintInfo *printInfo = [[NSPrintInfo alloc] initWithDictionary:printInfoDict];
+ [printInfo setHorizontalPagination:NSAutoPagination];
+ [printInfo setVerticalPagination:NSAutoPagination];
+ [printInfo setVerticallyCentered:NO];
+
+ NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:[frame frameView] printInfo:printInfo];
+ [printOperation setShowPanels:NO];
+ [printOperation runOperation];
+
+ [printInfo release];
+
+ NSData *pdfData = [NSData dataWithContentsOfFile:path];
+ [[NSFileManager defaultManager] removeFileAtPath:path handler:nil];
+
+ return pdfData;
+}
+
+static void dumpBackForwardListForWebView(WebView *view)
+{
+ printf("\n============== Back Forward List ==============\n");
+ WebBackForwardList *bfList = [view backForwardList];
+
+ // Print out all items in the list after prevTestBFItem, which was from the previous test
+ // Gather items from the end of the list, the print them out from oldest to newest
+ NSMutableArray *itemsToPrint = [[NSMutableArray alloc] init];
+ for (int i = [bfList forwardListCount]; i > 0; i--) {
+ WebHistoryItem *item = [bfList itemAtIndex:i];
+ // something is wrong if the item from the last test is in the forward part of the b/f list
+ assert(item != prevTestBFItem);
+ [itemsToPrint addObject:item];
+ }
+
+ assert([bfList currentItem] != prevTestBFItem);
+ [itemsToPrint addObject:[bfList currentItem]];
+ int currentItemIndex = [itemsToPrint count] - 1;
+
+ for (int i = -1; i >= -[bfList backListCount]; i--) {
+ WebHistoryItem *item = [bfList itemAtIndex:i];
+ if (item == prevTestBFItem)
+ break;
+ [itemsToPrint addObject:item];
+ }
+
+ for (int i = [itemsToPrint count]-1; i >= 0; i--)
+ dumpHistoryItem([itemsToPrint objectAtIndex:i], 8, i == currentItemIndex);
+
+ [itemsToPrint release];
+ printf("===============================================\n");
+}
+
+static void sizeWebViewForCurrentTest()
+{
+ // W3C SVG tests expect to be 480x360
+ bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg/W3C-SVG-1.1") != string::npos);
+ if (isSVGW3CTest)
+ [[mainFrame webView] setFrameSize:NSMakeSize(480, 360)];
+ else
+ [[mainFrame webView] setFrameSize:NSMakeSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight)];
+}
+
+static const char *methodNameStringForFailedTest()
+{
+ const char *errorMessage;
+ if (gLayoutTestController->dumpAsText())
+ errorMessage = "[documentElement innerText]";
+ else if (gLayoutTestController->dumpDOMAsWebArchive())
+ errorMessage = "[[mainFrame DOMDocument] webArchive]";
+ else if (gLayoutTestController->dumpSourceAsWebArchive())
+ errorMessage = "[[mainFrame dataSource] webArchive]";
+ else
+ errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";
+
+ return errorMessage;
+}
+
+static void dumpBackForwardListForAllWindows()
+{
+ CFArrayRef openWindows = (CFArrayRef)[DumpRenderTreeWindow openWindows];
+ unsigned count = CFArrayGetCount(openWindows);
+ for (unsigned i = 0; i < count; i++) {
+ NSWindow *window = (NSWindow *)CFArrayGetValueAtIndex(openWindows, i);
+ WebView *webView = [[[window contentView] subviews] objectAtIndex:0];
+ dumpBackForwardListForWebView(webView);
+ }
+}
+
+static void invalidateAnyPreviousWaitToDumpWatchdog()
+{
+ if (waitToDumpWatchdog) {
+ CFRunLoopTimerInvalidate(waitToDumpWatchdog);
+ CFRelease(waitToDumpWatchdog);
+ waitToDumpWatchdog = 0;
+ }
+}
+
+void dump()
+{
+ invalidateAnyPreviousWaitToDumpWatchdog();
+
+ if (dumpTree) {
+ NSString *resultString = nil;
+ NSData *resultData = nil;
+ NSString *resultMimeType = @"text/plain";
+
+ if ([[[mainFrame dataSource] _responseMIMEType] isEqualToString:@"text/plain"]) {
+ gLayoutTestController->setDumpAsText(true);
+ gLayoutTestController->setGeneratePixelResults(false);
+ }
+ if (gLayoutTestController->dumpAsAudio()) {
+ resultData = dumpAudio();
+ resultMimeType = @"audio/wav";
+ } else if (gLayoutTestController->dumpAsText()) {
+ resultString = dumpFramesAsText(mainFrame);
+ } else if (gLayoutTestController->dumpAsPDF()) {
+ resultData = dumpFrameAsPDF(mainFrame);
+ resultMimeType = @"application/pdf";
+ } else if (gLayoutTestController->dumpDOMAsWebArchive()) {
+ WebArchive *webArchive = [[mainFrame DOMDocument] webArchive];
+ resultString = HardAutorelease(createXMLStringFromWebArchiveData((CFDataRef)[webArchive data]));
+ resultMimeType = @"application/x-webarchive";
+ } else if (gLayoutTestController->dumpSourceAsWebArchive()) {
+ WebArchive *webArchive = [[mainFrame dataSource] webArchive];
+ resultString = HardAutorelease(createXMLStringFromWebArchiveData((CFDataRef)[webArchive data]));
+ resultMimeType = @"application/x-webarchive";
+ } else {
+ sizeWebViewForCurrentTest();
+ resultString = [mainFrame renderTreeAsExternalRepresentationForPrinting:gLayoutTestController->isPrinting()];
+ }
+
+ if (resultString && !resultData)
+ resultData = [resultString dataUsingEncoding:NSUTF8StringEncoding];
+
+ printf("Content-Type: %s\n", [resultMimeType UTF8String]);
+
+ if (gLayoutTestController->dumpAsAudio())
+ printf("Content-Transfer-Encoding: base64\n");
+
+ if (resultData) {
+ fwrite([resultData bytes], 1, [resultData length], stdout);
+
+ if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive())
+ dumpFrameScrollPosition(mainFrame);
+
+ if (gLayoutTestController->dumpBackForwardList())
+ dumpBackForwardListForAllWindows();
+ } else
+ printf("ERROR: nil result from %s", methodNameStringForFailedTest());
+
+ // Stop the watchdog thread before we leave this test to make sure it doesn't
+ // fire in between tests causing the next test to fail.
+ // This is a speculative fix for: https://bugs.webkit.org/show_bug.cgi?id=32339
+ invalidateAnyPreviousWaitToDumpWatchdog();
+
+ if (printSeparators) {
+ puts("#EOF"); // terminate the content block
+ fputs("#EOF\n", stderr);
+ }
+ }
+
+ if (dumpPixels && gLayoutTestController->generatePixelResults())
+ // FIXME: when isPrinting is set, dump the image with page separators.
+ dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash());
+
+ puts("#EOF"); // terminate the (possibly empty) pixels block
+
+ fflush(stdout);
+ fflush(stderr);
+
+ done = YES;
+}
+
+static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "loading/");
+}
+
+static bool shouldLogHistoryDelegates(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "globalhistory/");
+}
+
+static bool shouldOpenWebInspector(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "inspector/");
+}
+
+static bool shouldDumpAsText(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "dumpAsText/");
+}
+
+static bool shouldEnableDeveloperExtras(const char* pathOrURL)
+{
+ return true;
+}
+
+static void resetWebViewToConsistentStateBeforeTesting()
+{
+ WebView *webView = [mainFrame webView];
+ [webView setEditable:NO];
+ [(EditingDelegate *)[webView editingDelegate] setAcceptsEditing:YES];
+ [webView makeTextStandardSize:nil];
+ [webView resetPageZoom:nil];
+ [webView _scaleWebView:1.0 atOrigin:NSZeroPoint];
+ [webView _setCustomBackingScaleFactor:0];
+ [webView setTabKeyCyclesThroughElements:YES];
+ [webView setPolicyDelegate:nil];
+ [policyDelegate setPermissive:NO];
+ [policyDelegate setControllerToNotifyDone:0];
+ [frameLoadDelegate resetToConsistentState];
+ [webView _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:NO];
+ [webView _clearMainFrameName];
+ [[webView undoManager] removeAllActions];
+ [WebView _removeAllUserContentFromGroup:[webView groupName]];
+ [[webView window] setAutodisplay:NO];
+ [webView _setMinimumTimerInterval:[WebView _defaultMinimumTimerInterval]];
+ [webView setTracksRepaints:NO];
+
+ resetDefaultsToConsistentValues();
+
+ if (gLayoutTestController) {
+ WebCoreTestSupport::resetInternalsObject([mainFrame globalContext]);
+ // in the case that a test using the chrome input field failed, be sure to clean up for the next test
+ gLayoutTestController->removeChromeInputField();
+ }
+
+ [[mainFrame webView] setSmartInsertDeleteEnabled:YES];
+ [[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:NO];
+
+ [WebView _setUsesTestModeFocusRingColor:YES];
+ [WebView _resetOriginAccessWhitelists];
+ [WebView _setAllowsRoundingHacks:NO];
+
+ [[MockGeolocationProvider shared] stopTimer];
+
+ // Clear the contents of the general pasteboard
+ [[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
+
+ [mainFrame _clearOpener];
+}
+
+static void runTest(const string& testPathOrURL)
+{
+ ASSERT(!testPathOrURL.empty());
+
+ // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows.
+ string pathOrURL(testPathOrURL);
+ string expectedPixelHash;
+
+ size_t separatorPos = pathOrURL.find("'");
+ if (separatorPos != string::npos) {
+ pathOrURL = string(testPathOrURL, 0, separatorPos);
+ expectedPixelHash = string(testPathOrURL, separatorPos + 1);
+ }
+
+ NSString *pathOrURLString = [NSString stringWithUTF8String:pathOrURL.c_str()];
+ if (!pathOrURLString) {
+ fprintf(stderr, "Failed to parse \"%s\" as UTF-8\n", pathOrURL.c_str());
+ return;
+ }
+
+ NSURL *url;
+ if ([pathOrURLString hasPrefix:@"http://"] || [pathOrURLString hasPrefix:@"https://"])
+ url = [NSURL URLWithString:pathOrURLString];
+ else
+ url = [NSURL fileURLWithPath:pathOrURLString];
+ if (!url) {
+ fprintf(stderr, "Failed to parse \"%s\" as a URL\n", pathOrURL.c_str());
+ return;
+ }
+
+ const string testURL([[url absoluteString] UTF8String]);
+
+ resetWebViewToConsistentStateBeforeTesting();
+
+ gLayoutTestController = LayoutTestController::create(testURL, expectedPixelHash);
+ topLoadingFrame = nil;
+ ASSERT(!draggingInfo); // the previous test should have called eventSender.mouseUp to drop!
+ releaseAndZero(&draggingInfo);
+ done = NO;
+
+ gLayoutTestController->setIconDatabaseEnabled(false);
+
+ if (disallowedURLs)
+ CFSetRemoveAllValues(disallowedURLs);
+ if (shouldLogFrameLoadDelegates(pathOrURL.c_str()))
+ gLayoutTestController->setDumpFrameLoadCallbacks(true);
+
+ if (shouldLogHistoryDelegates(pathOrURL.c_str()))
+ [[mainFrame webView] setHistoryDelegate:historyDelegate];
+ else
+ [[mainFrame webView] setHistoryDelegate:nil];
+
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
+ gLayoutTestController->setDeveloperExtrasEnabled(true);
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->showWebInspector();
+ if (shouldDumpAsText(pathOrURL.c_str())) {
+ gLayoutTestController->setDumpAsText(true);
+ gLayoutTestController->setGeneratePixelResults(false);
+ }
+ }
+
+ if ([WebHistory optionalSharedHistory])
+ [WebHistory setOptionalSharedHistory:nil];
+ lastMousePosition = NSZeroPoint;
+ lastClickPosition = NSZeroPoint;
+
+ [prevTestBFItem release];
+ prevTestBFItem = [[[[mainFrame webView] backForwardList] currentItem] retain];
+
+ WorkQueue::shared()->clear();
+ WorkQueue::shared()->setFrozen(false);
+
+ bool ignoreWebCoreNodeLeaks = shouldIgnoreWebCoreNodeLeaks(testURL);
+ if (ignoreWebCoreNodeLeaks)
+ [WebCoreStatistics startIgnoringWebCoreNodeLeaks];
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [mainFrame loadRequest:[NSURLRequest requestWithURL:url]];
+ [pool release];
+
+ while (!done) {
+ pool = [[NSAutoreleasePool alloc] init];
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
+ [pool release];
+ }
+
+ pool = [[NSAutoreleasePool alloc] init];
+ [EventSendingController clearSavedEvents];
+ [[mainFrame webView] setSelectedDOMRange:nil affinity:NSSelectionAffinityDownstream];
+
+ WorkQueue::shared()->clear();
+
+ if (gLayoutTestController->closeRemainingWindowsWhenComplete()) {
+ NSArray* array = [DumpRenderTreeWindow openWindows];
+
+ unsigned count = [array count];
+ for (unsigned i = 0; i < count; i++) {
+ NSWindow *window = [array objectAtIndex:i];
+
+ // Don't try to close the main window
+ if (window == [[mainFrame webView] window])
+ continue;
+
+ WebView *webView = [[[window contentView] subviews] objectAtIndex:0];
+
+ [webView close];
+ [window close];
+ }
+ }
+
+ // If developer extras enabled Web Inspector may have been open by the test.
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
+ gLayoutTestController->closeWebInspector();
+ gLayoutTestController->setDeveloperExtrasEnabled(false);
+ }
+
+ resetWebViewToConsistentStateBeforeTesting();
+
+ [mainFrame loadHTMLString:@"<html></html>" baseURL:[NSURL URLWithString:@"about:blank"]];
+ [mainFrame stopLoading];
+
+ [pool release];
+
+ // We should only have our main window left open when we're done
+ ASSERT(CFArrayGetCount(openWindowsRef) == 1);
+ ASSERT(CFArrayGetValueAtIndex(openWindowsRef, 0) == [[mainFrame webView] window]);
+
+ gLayoutTestController.clear();
+
+ if (ignoreWebCoreNodeLeaks)
+ [WebCoreStatistics stopIgnoringWebCoreNodeLeaks];
+
+ if (gcBetweenTests)
+ [WebCoreStatistics garbageCollectJavaScriptObjects];
+}
+
+void displayWebView()
+{
+ WebView *webView = [mainFrame webView];
+ [webView display];
+
+ [webView setTracksRepaints:YES];
+ [webView resetTrackedRepaints];
+}
+
+@implementation DumpRenderTreeEvent
+
++ (NSPoint)mouseLocation
+{
+ return [[[mainFrame webView] window] convertBaseToScreen:lastMousePosition];
+}
+
+@end
+
+@implementation DumpRenderTreeApplication
+
+- (BOOL)isRunning
+{
+ // <rdar://problem/7686123> Java plug-in freezes unless NSApplication is running
+ return YES;
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h
new file mode 100644
index 000000000..249809c94
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface DumpRenderTreeDraggingInfo : NSObject <NSDraggingInfo> {
+@private
+ NSSize offset;
+ NSImage *draggedImage;
+ NSPasteboard *draggingPasteboard;
+ id draggingSource;
+}
+
+- (id)initWithImage:(NSImage *)image offset:(NSSize)offset pasteboard:(NSPasteboard *)pasteboard source:(id)source;
+
+- (NSWindow *)draggingDestinationWindow;
+- (NSDragOperation)draggingSourceOperationMask;
+- (NSPoint)draggingLocation;
+- (NSPoint)draggedImageLocation;
+- (NSImage *)draggedImage;
+- (NSPasteboard *)draggingPasteboard;
+- (id)draggingSource;
+- (int)draggingSequenceNumber;
+
+- (void)slideDraggedImageTo:(NSPoint)screenPoint;
+- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination;
+@end
+
diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm
new file mode 100644
index 000000000..b729cf406
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "DumpRenderTreeDraggingInfo.h"
+
+#import "DumpRenderTree.h"
+#import "EventSendingController.h"
+#import <WebKit/WebKit.h>
+
+@implementation DumpRenderTreeDraggingInfo
+
+- (id)initWithImage:(NSImage *)anImage offset:(NSSize)o pasteboard:(NSPasteboard *)pboard source:(id)source
+{
+ draggedImage = [anImage retain];
+ draggingPasteboard = [pboard retain];
+ draggingSource = [source retain];
+ offset = o;
+
+ return [super init];
+}
+
+- (void)dealloc
+{
+ [draggedImage release];
+ [draggingPasteboard release];
+ [draggingSource release];
+ [super dealloc];
+}
+
+- (NSWindow *)draggingDestinationWindow
+{
+ return [[mainFrame webView] window];
+}
+
+- (NSDragOperation)draggingSourceOperationMask
+{
+ return [draggingSource draggingSourceOperationMaskForLocal:YES];
+}
+
+- (NSPoint)draggingLocation
+{
+ return lastMousePosition;
+}
+
+- (NSPoint)draggedImageLocation
+{
+ return NSMakePoint(lastMousePosition.x + offset.width, lastMousePosition.y + offset.height);
+}
+
+- (NSImage *)draggedImage
+{
+ return draggedImage;
+}
+
+- (NSPasteboard *)draggingPasteboard
+{
+ return draggingPasteboard;
+}
+
+- (id)draggingSource
+{
+ return draggingSource;
+}
+
+- (int)draggingSequenceNumber
+{
+ NSLog(@"DumpRenderTree doesn't support draggingSequenceNumber");
+ return 0;
+}
+
+- (void)slideDraggedImageTo:(NSPoint)screenPoint
+{
+ NSLog(@"DumpRenderTree doesn't support slideDraggedImageTo:");
+}
+
+- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
+{
+ NSLog(@"DumpRenderTree doesn't support namesOfPromisedFilesDroppedAtDestination:");
+ return nil;
+}
+
+#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+- (NSDraggingFormation)draggingFormation
+{
+ return NSDraggingFormationDefault;
+}
+
+- (void)setDraggingFormation:(NSDraggingFormation)formation
+{
+ // Ignored.
+}
+
+- (BOOL)animatesToDestination
+{
+ return NO;
+}
+
+- (void)setAnimatesToDestination:(BOOL)flag
+{
+ // Ignored.
+}
+
+- (NSInteger)numberOfValidItemsForDrop
+{
+ return 1;
+}
+
+- (void)setNumberOfValidItemsForDrop:(NSInteger)number
+{
+ // Ignored.
+}
+
+- (void)enumerateDraggingItemsWithOptions:(NSEnumerationOptions)enumOpts forView:(NSView *)view classes:(NSArray *)classArray searchOptions:(NSDictionary *)searchOptions usingBlock:(void (^)(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop))block
+{
+ // Ignored.
+}
+#endif // !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+
+@end
+
diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h b/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h
new file mode 100644
index 000000000..901008cc1
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeMac_h
+#define DumpRenderTreeMac_h
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef __OBJC__
+@class DumpRenderTreeDraggingInfo;
+@class NavigationController;
+@class PolicyDelegate;
+@class StorageTrackerDelegate;
+@class WebFrame;
+@class WebScriptWorld;
+@class WebView;
+#else
+class DumpRenderTreeDraggingInfo;
+class NavigationController;
+class PolicyDelegate;
+class StorageTrackerDelegate;
+class WebFrame;
+class WebScriptWorld;
+class WebView;
+#endif
+
+extern CFMutableArrayRef openWindowsRef;
+extern CFMutableSetRef disallowedURLs;
+extern WebFrame* mainFrame;
+extern WebFrame* topLoadingFrame;
+extern DumpRenderTreeDraggingInfo *draggingInfo;
+extern NavigationController* gNavigationController;
+extern PolicyDelegate* policyDelegate;
+extern StorageTrackerDelegate* storageDelegate;
+
+extern const unsigned maxViewHeight;
+extern const unsigned maxViewWidth;
+
+extern CFRunLoopTimerRef waitToDumpWatchdog;
+
+WebView* createWebViewAndOffscreenWindow();
+void setPersistentUserStyleSheetLocation(CFStringRef);
+
+unsigned worldIDForWorld(WebScriptWorld *);
+
+#endif // DumpRenderTreeMac_h
diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h
new file mode 100644
index 000000000..ba2754ba7
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <AppKit/AppKit.h>
+#import <WebKit/WebTypesInternal.h>
+
+@interface DumpRenderTreePasteboard : NSPasteboard
+- (NSInteger)declareType:(NSString *)type owner:(id)newOwner;
++ (void)releaseLocalPasteboards;
+@end
+
diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m
new file mode 100644
index 000000000..b1b3b86c0
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "DumpRenderTreeMac.h"
+#import "DumpRenderTreePasteboard.h"
+
+#import <WebKit/WebTypesInternal.h>
+
+@interface LocalPasteboard : NSPasteboard
+{
+ NSMutableArray *typesArray;
+ NSMutableSet *typesSet;
+ NSMutableDictionary *dataByType;
+ NSInteger changeCount;
+}
+@end
+
+static NSMutableDictionary *localPasteboards;
+
+@implementation DumpRenderTreePasteboard
+
+// Return a local pasteboard so we don't disturb the real pasteboards when running tests.
++ (NSPasteboard *)_pasteboardWithName:(NSString *)name
+{
+ static int number = 0;
+ if (!name)
+ name = [NSString stringWithFormat:@"LocalPasteboard%d", ++number];
+ if (!localPasteboards)
+ localPasteboards = [[NSMutableDictionary alloc] init];
+ LocalPasteboard *pasteboard = [localPasteboards objectForKey:name];
+ if (pasteboard)
+ return pasteboard;
+ pasteboard = [[LocalPasteboard alloc] init];
+ [localPasteboards setObject:pasteboard forKey:name];
+ [pasteboard release];
+ return pasteboard;
+}
+
++ (void)releaseLocalPasteboards
+{
+ [localPasteboards release];
+ localPasteboards = nil;
+}
+
+// Convenience method for JS so that it doesn't have to try and create a NSArray on the objc side instead
+// of the usual WebScriptObject that is passed around
+- (NSInteger)declareType:(NSString *)type owner:(id)newOwner
+{
+ return [self declareTypes:[NSArray arrayWithObject:type] owner:newOwner];
+}
+
+@end
+
+@implementation LocalPasteboard
+
++ (id)alloc
+{
+ return NSAllocateObject(self, 0, 0);
+}
+
+- (id)init
+{
+ typesArray = [[NSMutableArray alloc] init];
+ typesSet = [[NSMutableSet alloc] init];
+ dataByType = [[NSMutableDictionary alloc] init];
+ return self;
+}
+
+- (void)dealloc
+{
+ [typesArray release];
+ [typesSet release];
+ [dataByType release];
+ [super dealloc];
+}
+
+- (NSString *)name
+{
+ return nil;
+}
+
+- (void)releaseGlobally
+{
+}
+
+- (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner
+{
+ [typesArray removeAllObjects];
+ [typesSet removeAllObjects];
+ [dataByType removeAllObjects];
+ return [self addTypes:newTypes owner:newOwner];
+}
+
+- (NSInteger)addTypes:(NSArray *)newTypes owner:(id)newOwner
+{
+ unsigned count = [newTypes count];
+ unsigned i;
+ for (i = 0; i < count; ++i) {
+ NSString *type = [newTypes objectAtIndex:i];
+ NSString *setType = [typesSet member:type];
+ if (!setType) {
+ setType = [type copy];
+ [typesArray addObject:setType];
+ [typesSet addObject:setType];
+ [setType release];
+ }
+ if (newOwner && [newOwner respondsToSelector:@selector(pasteboard:provideDataForType:)])
+ [newOwner pasteboard:self provideDataForType:setType];
+ }
+ return ++changeCount;
+}
+
+- (NSInteger)changeCount
+{
+ return changeCount;
+}
+
+- (NSArray *)types
+{
+ return typesArray;
+}
+
+- (NSString *)availableTypeFromArray:(NSArray *)types
+{
+ unsigned count = [types count];
+ unsigned i;
+ for (i = 0; i < count; ++i) {
+ NSString *type = [types objectAtIndex:i];
+ NSString *setType = [typesSet member:type];
+ if (setType)
+ return setType;
+ }
+ return nil;
+}
+
+- (BOOL)setData:(NSData *)data forType:(NSString *)dataType
+{
+ if (data == nil)
+ data = [NSData data];
+ if (![typesSet containsObject:dataType])
+ return NO;
+ [dataByType setObject:data forKey:dataType];
+ ++changeCount;
+ return YES;
+}
+
+- (NSData *)dataForType:(NSString *)dataType
+{
+ return [dataByType objectForKey:dataType];
+}
+
+- (BOOL)setPropertyList:(id)propertyList forType:(NSString *)dataType
+{
+ CFDataRef data = NULL;
+ if (propertyList)
+ data = CFPropertyListCreateXMLData(NULL, propertyList);
+ BOOL result = [self setData:(NSData *)data forType:dataType];
+ if (data)
+ CFRelease(data);
+ return result;
+}
+
+- (BOOL)setString:(NSString *)string forType:(NSString *)dataType
+{
+ CFDataRef data = NULL;
+ if (string) {
+ if ([string length] == 0)
+ data = CFDataCreate(NULL, NULL, 0);
+ else
+ data = CFStringCreateExternalRepresentation(NULL, (CFStringRef)string, kCFStringEncodingUTF8, 0);
+ }
+ BOOL result = [self setData:(NSData *)data forType:dataType];
+ if (data)
+ CFRelease(data);
+ return result;
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h
new file mode 100644
index 000000000..a229d20e6
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <AppKit/AppKit.h>
+
+@class WebView;
+
+@interface DumpRenderTreeWindow : NSWindow
+{
+}
+
+// I'm not sure why we can't just use [NSApp windows]
++ (NSArray *)openWindows;
+
+- (WebView *)webView;
+
+- (void)startListeningForAcceleratedCompositingChanges;
+
+@end
diff --git a/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm
new file mode 100644
index 000000000..e0cdc6b6e
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTreeWindow.mm
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "DumpRenderTreeWindow.h"
+
+#import "DumpRenderTree.h"
+
+// FIXME: This file is ObjC++ only because of this include. :(
+#import "LayoutTestController.h"
+#import <WebKit/WebViewPrivate.h>
+#import <WebKit/WebTypesInternal.h>
+
+CFMutableArrayRef openWindowsRef = 0;
+
+static CFArrayCallBacks NonRetainingArrayCallbacks = {
+ 0,
+ NULL,
+ NULL,
+ CFCopyDescription,
+ CFEqual
+};
+
+@implementation DumpRenderTreeWindow
+
++ (NSArray *)openWindows
+{
+ return [[(NSArray *)openWindowsRef copy] autorelease];
+}
+
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
+{
+ if (!openWindowsRef)
+ openWindowsRef = CFArrayCreateMutable(NULL, 0, &NonRetainingArrayCallbacks);
+
+ CFArrayAppendValue(openWindowsRef, self);
+
+ return [super initWithContentRect:contentRect styleMask:styleMask backing:bufferingType defer:deferCreation];
+}
+
+- (void)close
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ CFRange arrayRange = CFRangeMake(0, CFArrayGetCount(openWindowsRef));
+ CFIndex i = CFArrayGetFirstIndexOfValue(openWindowsRef, arrayRange, self);
+ if (i != kCFNotFound)
+ CFArrayRemoveValueAtIndex(openWindowsRef, i);
+
+ [super close];
+}
+
+- (BOOL)isKeyWindow
+{
+ return gLayoutTestController ? gLayoutTestController->windowIsKey() : YES;
+}
+
+- (void)keyDown:(NSEvent *)event
+{
+ // Do nothing, avoiding the beep we'd otherwise get from NSResponder,
+ // once we get to the end of the responder chain.
+}
+
+- (WebView *)webView
+{
+ NSView *firstView = nil;
+ if ([[[self contentView] subviews] count] > 0) {
+ firstView = [[[self contentView] subviews] objectAtIndex:0];
+ if ([firstView isKindOfClass:[WebView class]])
+ return static_cast<WebView *>(firstView);
+ }
+ return nil;
+}
+
+- (void)startListeningForAcceleratedCompositingChanges
+{
+ [[self webView] _setPostsAcceleratedCompositingNotifications:YES];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(webViewStartedAcceleratedCompositing:)
+ name:_WebViewDidStartAcceleratedCompositingNotification object:nil];
+}
+
+- (void)webViewStartedAcceleratedCompositing:(NSNotification *)notification
+{
+ // If the WebView has gone into compositing mode, turn on window autodisplay. This is necessary for CA
+ // to update layers and start animations.
+ // We only ever turn autodisplay on here, because we turn it off before every test.
+ if ([[self webView] _isUsingAcceleratedCompositing])
+ [self setAutodisplay:YES];
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/EditingDelegate.h b/Tools/DumpRenderTree/mac/EditingDelegate.h
new file mode 100644
index 000000000..b5563c887
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/EditingDelegate.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface EditingDelegate : NSObject
+{
+ BOOL acceptsEditing;
+}
+
+- (void)setAcceptsEditing:(BOOL)newAcceptsEditing;
+
+@end
diff --git a/Tools/DumpRenderTree/mac/EditingDelegate.mm b/Tools/DumpRenderTree/mac/EditingDelegate.mm
new file mode 100644
index 000000000..02e931ccd
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/EditingDelegate.mm
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "EditingDelegate.h"
+
+#import "DumpRenderTree.h"
+#import "LayoutTestController.h"
+#import <WebKit/WebKit.h>
+
+@interface DOMNode (dumpPath)
+- (NSString *)dumpPath;
+@end
+
+@implementation DOMNode (dumpPath)
+- (NSString *)dumpPath
+{
+ DOMNode *parent = [self parentNode];
+ NSString *str = [NSString stringWithFormat:@"%@", [self nodeName]];
+ if (parent != nil) {
+ str = [str stringByAppendingString:@" > "];
+ str = [str stringByAppendingString:[parent dumpPath]];
+ }
+ return str;
+}
+@end
+
+@interface DOMRange (dump)
+- (NSString *)dump;
+@end
+
+@implementation DOMRange (dump)
+- (NSString *)dump
+{
+ return [NSString stringWithFormat:@"range from %ld of %@ to %ld of %@", [self startOffset], [[self startContainer] dumpPath], [self endOffset], [[self endContainer] dumpPath]];
+}
+@end
+
+@implementation EditingDelegate
+
+- (id)init
+{
+ self = [super init];
+ if (!self)
+ return nil;
+ acceptsEditing = YES;
+ return self;
+}
+
+- (BOOL)webView:(WebView *)webView shouldBeginEditingInDOMRange:(DOMRange *)range
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n", [[range dump] UTF8String]);
+ return acceptsEditing;
+}
+
+- (BOOL)webView:(WebView *)webView shouldEndEditingInDOMRange:(DOMRange *)range
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n", [[range dump] UTF8String]);
+ return acceptsEditing;
+}
+
+- (BOOL)webView:(WebView *)webView shouldInsertNode:(DOMNode *)node replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
+{
+ static const char *insertactionstring[] = {
+ "WebViewInsertActionTyped",
+ "WebViewInsertActionPasted",
+ "WebViewInsertActionDropped",
+ };
+
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldInsertNode:%s replacingDOMRange:%s givenAction:%s\n", [[node dumpPath] UTF8String], [[range dump] UTF8String], insertactionstring[action]);
+ return acceptsEditing;
+}
+
+- (BOOL)webView:(WebView *)webView shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
+{
+ static const char *insertactionstring[] = {
+ "WebViewInsertActionTyped",
+ "WebViewInsertActionPasted",
+ "WebViewInsertActionDropped",
+ };
+
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:%s givenAction:%s\n", [[text description] UTF8String], [[range dump] UTF8String], insertactionstring[action]);
+ return acceptsEditing;
+}
+
+- (BOOL)webView:(WebView *)webView shouldDeleteDOMRange:(DOMRange *)range
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldDeleteDOMRange:%s\n", [[range dump] UTF8String]);
+ return acceptsEditing;
+}
+
+- (BOOL)webView:(WebView *)webView shouldShowDeleteInterfaceForElement:(DOMHTMLElement *)element
+{
+ return [[element className] isEqualToString:@"needsDeletionUI"];
+}
+
+- (BOOL)webView:(WebView *)webView shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag
+{
+ static const char *affinitystring[] = {
+ "NSSelectionAffinityUpstream",
+ "NSSelectionAffinityDownstream"
+ };
+ static const char *boolstring[] = {
+ "FALSE",
+ "TRUE"
+ };
+
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s toDOMRange:%s affinity:%s stillSelecting:%s\n", [[currentRange dump] UTF8String], [[proposedRange dump] UTF8String], affinitystring[selectionAffinity], boolstring[flag]);
+ return acceptsEditing;
+}
+
+- (BOOL)webView:(WebView *)webView shouldApplyStyle:(DOMCSSStyleDeclaration *)style toElementsInDOMRange:(DOMRange *)range
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n", [[style description] UTF8String], [[range dump] UTF8String]);
+ return acceptsEditing;
+}
+
+- (BOOL)webView:(WebView *)webView shouldChangeTypingStyle:(DOMCSSStyleDeclaration *)currentStyle toStyle:(DOMCSSStyleDeclaration *)proposedStyle
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: shouldChangeTypingStyle:%s toStyle:%s\n", [[currentStyle description] UTF8String], [[proposedStyle description] UTF8String]);
+ return acceptsEditing;
+}
+
+- (void)webViewDidBeginEditing:(NSNotification *)notification
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: webViewDidBeginEditing:%s\n", [[notification name] UTF8String]);
+}
+
+- (void)webViewDidChange:(NSNotification *)notification
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: webViewDidChange:%s\n", [[notification name] UTF8String]);
+}
+
+- (void)webViewDidEndEditing:(NSNotification *)notification
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: webViewDidEndEditing:%s\n", [[notification name] UTF8String]);
+}
+
+- (void)webViewDidChangeTypingStyle:(NSNotification *)notification
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: webViewDidChangeTypingStyle:%s\n", [[notification name] UTF8String]);
+}
+
+- (void)webViewDidChangeSelection:(NSNotification *)notification
+{
+ if (!done && gLayoutTestController->dumpEditingCallbacks())
+ printf("EDITING DELEGATE: webViewDidChangeSelection:%s\n", [[notification name] UTF8String]);
+}
+
+- (void)setAcceptsEditing:(BOOL)newAcceptsEditing
+{
+ acceptsEditing = newAcceptsEditing;
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/EventSendingController.h b/Tools/DumpRenderTree/mac/EventSendingController.h
new file mode 100644
index 000000000..944057546
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/EventSendingController.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <WebKit/WebKit.h>
+
+@interface EventSendingController : NSObject <DOMEventListener>
+{
+ BOOL leftMouseButtonDown;
+ BOOL dragMode;
+ int clickCount;
+ NSTimeInterval lastClick;
+ int eventNumber;
+ double timeOffset;
+}
+
++ (void)saveEvent:(NSInvocation *)event;
++ (void)replaySavedEvents;
++ (void)clearSavedEvents;
+
+- (void)scheduleAsynchronousClick;
+
+- (void)enableDOMUIEventLogging:(WebScriptObject *)node;
+
+- (void)handleEvent:(DOMEvent *)event;
+
+@end
+
+extern NSPoint lastMousePosition;
+extern NSPoint lastClickPosition; \ No newline at end of file
diff --git a/Tools/DumpRenderTree/mac/EventSendingController.mm b/Tools/DumpRenderTree/mac/EventSendingController.mm
new file mode 100644
index 000000000..f07a43e87
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/EventSendingController.mm
@@ -0,0 +1,873 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Jonas Witt <jonas.witt@gmail.com>
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "EventSendingController.h"
+
+#import "DumpRenderTree.h"
+#import "DumpRenderTreeDraggingInfo.h"
+#import "DumpRenderTreeFileDraggingSource.h"
+
+#import <Carbon/Carbon.h> // for GetCurrentEventTime()
+#import <WebKit/DOMPrivate.h>
+#import <WebKit/WebKit.h>
+#import <WebKit/WebViewPrivate.h>
+
+extern "C" void _NSNewKillRingSequence();
+
+enum MouseAction {
+ MouseDown,
+ MouseUp,
+ MouseDragged
+};
+
+// Match the DOM spec (sadly the DOM spec does not provide an enum)
+enum MouseButton {
+ LeftMouseButton = 0,
+ MiddleMouseButton = 1,
+ RightMouseButton = 2,
+ NoMouseButton = -1
+};
+
+NSPoint lastMousePosition;
+NSPoint lastClickPosition;
+int lastClickButton = NoMouseButton;
+NSArray *webkitDomEventNames;
+NSMutableArray *savedMouseEvents; // mouse events sent between mouseDown and mouseUp are stored here, and then executed at once.
+BOOL replayingSavedEvents;
+
+@implementation EventSendingController
+
++ (void)initialize
+{
+ webkitDomEventNames = [[NSArray alloc] initWithObjects:
+ @"abort",
+ @"beforecopy",
+ @"beforecut",
+ @"beforepaste",
+ @"blur",
+ @"change",
+ @"click",
+ @"contextmenu",
+ @"copy",
+ @"cut",
+ @"dblclick",
+ @"drag",
+ @"dragend",
+ @"dragenter",
+ @"dragleave",
+ @"dragover",
+ @"dragstart",
+ @"drop",
+ @"error",
+ @"focus",
+ @"input",
+ @"keydown",
+ @"keypress",
+ @"keyup",
+ @"load",
+ @"mousedown",
+ @"mousemove",
+ @"mouseout",
+ @"mouseover",
+ @"mouseup",
+ @"mousewheel",
+ @"beforeunload",
+ @"paste",
+ @"readystatechange",
+ @"reset",
+ @"resize",
+ @"scroll",
+ @"search",
+ @"select",
+ @"selectstart",
+ @"submit",
+ @"textInput",
+ @"textzoomin",
+ @"textzoomout",
+ @"unload",
+ @"zoom",
+ nil];
+}
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
+{
+ if (aSelector == @selector(beginDragWithFiles:)
+ || aSelector == @selector(clearKillRing)
+ || aSelector == @selector(contextClick)
+ || aSelector == @selector(enableDOMUIEventLogging:)
+ || aSelector == @selector(fireKeyboardEventsToElement:)
+ || aSelector == @selector(keyDown:withModifiers:withLocation:)
+ || aSelector == @selector(leapForward:)
+ || aSelector == @selector(mouseDown:withModifiers:)
+ || aSelector == @selector(mouseMoveToX:Y:)
+ || aSelector == @selector(mouseUp:withModifiers:)
+ || aSelector == @selector(scheduleAsynchronousClick)
+ || aSelector == @selector(textZoomIn)
+ || aSelector == @selector(textZoomOut)
+ || aSelector == @selector(zoomPageIn)
+ || aSelector == @selector(zoomPageOut)
+ || aSelector == @selector(scalePageBy:atX:andY:)
+ || aSelector == @selector(mouseScrollByX:andY:)
+ || aSelector == @selector(continuousMouseScrollByX:andY:))
+ return NO;
+ return YES;
+}
+
++ (BOOL)isKeyExcludedFromWebScript:(const char*)name
+{
+ if (strcmp(name, "dragMode") == 0)
+ return NO;
+ return YES;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)aSelector
+{
+ if (aSelector == @selector(beginDragWithFiles:))
+ return @"beginDragWithFiles";
+ if (aSelector == @selector(contextClick))
+ return @"contextClick";
+ if (aSelector == @selector(enableDOMUIEventLogging:))
+ return @"enableDOMUIEventLogging";
+ if (aSelector == @selector(fireKeyboardEventsToElement:))
+ return @"fireKeyboardEventsToElement";
+ if (aSelector == @selector(keyDown:withModifiers:withLocation:))
+ return @"keyDown";
+ if (aSelector == @selector(leapForward:))
+ return @"leapForward";
+ if (aSelector == @selector(mouseDown:withModifiers:))
+ return @"mouseDown";
+ if (aSelector == @selector(mouseUp:withModifiers:))
+ return @"mouseUp";
+ if (aSelector == @selector(mouseMoveToX:Y:))
+ return @"mouseMoveTo";
+ if (aSelector == @selector(setDragMode:))
+ return @"setDragMode";
+ if (aSelector == @selector(mouseScrollByX:andY:))
+ return @"mouseScrollBy";
+ if (aSelector == @selector(continuousMouseScrollByX:andY:))
+ return @"continuousMouseScrollBy";
+ if (aSelector == @selector(scalePageBy:atX:andY:))
+ return @"scalePageBy";
+ return nil;
+}
+
+- (id)init
+{
+ self = [super init];
+ if (self)
+ dragMode = YES;
+ return self;
+}
+
+- (void)dealloc
+{
+ [super dealloc];
+}
+
+- (double)currentEventTime
+{
+ return GetCurrentEventTime() + timeOffset;
+}
+
+- (void)leapForward:(int)milliseconds
+{
+ if (dragMode && leftMouseButtonDown && !replayingSavedEvents) {
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(leapForward:)]];
+ [invocation setTarget:self];
+ [invocation setSelector:@selector(leapForward:)];
+ [invocation setArgument:&milliseconds atIndex:2];
+
+ [EventSendingController saveEvent:invocation];
+
+ return;
+ }
+
+ timeOffset += milliseconds / 1000.0;
+}
+
+- (void)clearKillRing
+{
+ _NSNewKillRingSequence();
+}
+
+static NSEventType eventTypeForMouseButtonAndAction(int button, MouseAction action)
+{
+ switch (button) {
+ case LeftMouseButton:
+ switch (action) {
+ case MouseDown:
+ return NSLeftMouseDown;
+ case MouseUp:
+ return NSLeftMouseUp;
+ case MouseDragged:
+ return NSLeftMouseDragged;
+ }
+ case RightMouseButton:
+ switch (action) {
+ case MouseDown:
+ return NSRightMouseDown;
+ case MouseUp:
+ return NSRightMouseUp;
+ case MouseDragged:
+ return NSRightMouseDragged;
+ }
+ default:
+ switch (action) {
+ case MouseDown:
+ return NSOtherMouseDown;
+ case MouseUp:
+ return NSOtherMouseUp;
+ case MouseDragged:
+ return NSOtherMouseDragged;
+ }
+ }
+ assert(0);
+ return static_cast<NSEventType>(0);
+}
+
+- (void)beginDragWithFiles:(WebScriptObject*)jsFilePaths
+{
+ assert(!draggingInfo);
+ assert([jsFilePaths isKindOfClass:[WebScriptObject class]]);
+
+ NSPasteboard *pboard = [NSPasteboard pasteboardWithUniqueName];
+ [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil];
+
+ NSURL *currentTestURL = [NSURL URLWithString:[[mainFrame webView] mainFrameURL]];
+
+ NSMutableArray *filePaths = [NSMutableArray array];
+ for (unsigned i = 0; [[jsFilePaths webScriptValueAtIndex:i] isKindOfClass:[NSString class]]; i++) {
+ NSString *filePath = (NSString *)[jsFilePaths webScriptValueAtIndex:i];
+ // Have NSURL encode the name so that we handle '?' in file names correctly.
+ NSURL *fileURL = [NSURL fileURLWithPath:filePath];
+ NSURL *absoluteFileURL = [NSURL URLWithString:[fileURL relativeString] relativeToURL:currentTestURL];
+ [filePaths addObject:[absoluteFileURL path]];
+ }
+
+ [pboard setPropertyList:filePaths forType:NSFilenamesPboardType];
+ assert([pboard propertyListForType:NSFilenamesPboardType]); // setPropertyList will silently fail on error, assert that it didn't fail
+
+ // Provide a source, otherwise [DumpRenderTreeDraggingInfo draggingSourceOperationMask] defaults to NSDragOperationNone
+ DumpRenderTreeFileDraggingSource *source = [[[DumpRenderTreeFileDraggingSource alloc] init] autorelease];
+ draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:nil offset:NSZeroSize pasteboard:pboard source:source];
+ [[mainFrame webView] draggingEntered:draggingInfo];
+
+ dragMode = NO; // dragMode saves events and then replays them later. We don't need/want that.
+ leftMouseButtonDown = YES; // Make the rest of eventSender think a drag is in progress
+}
+
+- (void)updateClickCountForButton:(int)buttonNumber
+{
+ if (([self currentEventTime] - lastClick >= 1) ||
+ !NSEqualPoints(lastMousePosition, lastClickPosition) ||
+ lastClickButton != buttonNumber) {
+ clickCount = 1;
+ lastClickButton = buttonNumber;
+ } else
+ clickCount++;
+}
+
+static int buildModifierFlags(const WebScriptObject* modifiers)
+{
+ int flags = 0;
+ if (![modifiers isKindOfClass:[WebScriptObject class]])
+ return flags;
+ for (unsigned i = 0; [[modifiers webScriptValueAtIndex:i] isKindOfClass:[NSString class]]; i++) {
+ NSString* modifierName = (NSString*)[modifiers webScriptValueAtIndex:i];
+ if ([modifierName isEqual:@"ctrlKey"])
+ flags |= NSControlKeyMask;
+ else if ([modifierName isEqual:@"shiftKey"] || [modifierName isEqual:@"rangeSelectionKey"])
+ flags |= NSShiftKeyMask;
+ else if ([modifierName isEqual:@"altKey"])
+ flags |= NSAlternateKeyMask;
+ else if ([modifierName isEqual:@"metaKey"] || [modifierName isEqual:@"addSelectionKey"])
+ flags |= NSCommandKeyMask;
+ }
+ return flags;
+}
+
+- (void)mouseDown:(int)buttonNumber withModifiers:(WebScriptObject*)modifiers
+{
+ [[[mainFrame frameView] documentView] layout];
+ [self updateClickCountForButton:buttonNumber];
+
+ NSEventType eventType = eventTypeForMouseButtonAndAction(buttonNumber, MouseDown);
+ NSEvent *event = [NSEvent mouseEventWithType:eventType
+ location:lastMousePosition
+ modifierFlags:buildModifierFlags(modifiers)
+ timestamp:[self currentEventTime]
+ windowNumber:[[[mainFrame webView] window] windowNumber]
+ context:[NSGraphicsContext currentContext]
+ eventNumber:++eventNumber
+ clickCount:clickCount
+ pressure:0.0];
+
+ NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]];
+ if (subView) {
+ [subView mouseDown:event];
+ if (buttonNumber == LeftMouseButton)
+ leftMouseButtonDown = YES;
+ }
+}
+
+- (void)mouseDown:(int)buttonNumber
+{
+ [self mouseDown:buttonNumber withModifiers:nil];
+}
+
+- (void)textZoomIn
+{
+ [[mainFrame webView] makeTextLarger:self];
+}
+
+- (void)textZoomOut
+{
+ [[mainFrame webView] makeTextSmaller:self];
+}
+
+- (void)zoomPageIn
+{
+ [[mainFrame webView] zoomPageIn:self];
+}
+
+- (void)zoomPageOut
+{
+ [[mainFrame webView] zoomPageOut:self];
+}
+
+- (void)scalePageBy:(float)scale atX:(float)x andY:(float)y
+{
+ [[mainFrame webView] _scaleWebView:scale atOrigin:NSMakePoint(x, y)];
+}
+
+- (void)mouseUp:(int)buttonNumber withModifiers:(WebScriptObject*)modifiers
+{
+ if (dragMode && !replayingSavedEvents) {
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(mouseUp:withModifiers:)]];
+ [invocation setTarget:self];
+ [invocation setSelector:@selector(mouseUp:withModifiers:)];
+ [invocation setArgument:&buttonNumber atIndex:2];
+ [invocation setArgument:&modifiers atIndex:3];
+
+ [EventSendingController saveEvent:invocation];
+ [EventSendingController replaySavedEvents];
+
+ return;
+ }
+
+ [[[mainFrame frameView] documentView] layout];
+ NSEventType eventType = eventTypeForMouseButtonAndAction(buttonNumber, MouseUp);
+ NSEvent *event = [NSEvent mouseEventWithType:eventType
+ location:lastMousePosition
+ modifierFlags:buildModifierFlags(modifiers)
+ timestamp:[self currentEventTime]
+ windowNumber:[[[mainFrame webView] window] windowNumber]
+ context:[NSGraphicsContext currentContext]
+ eventNumber:++eventNumber
+ clickCount:clickCount
+ pressure:0.0];
+
+ NSView *targetView = [[mainFrame webView] hitTest:[event locationInWindow]];
+ // FIXME: Silly hack to teach DRT to respect capturing mouse events outside the WebView.
+ // The right solution is just to use NSApplication's built-in event sending methods,
+ // instead of rolling our own algorithm for selecting an event target.
+ targetView = targetView ? targetView : [[mainFrame frameView] documentView];
+ assert(targetView);
+ [targetView mouseUp:event];
+ if (buttonNumber == LeftMouseButton)
+ leftMouseButtonDown = NO;
+ lastClick = [event timestamp];
+ lastClickPosition = lastMousePosition;
+ if (draggingInfo) {
+ WebView *webView = [mainFrame webView];
+
+ NSDragOperation dragOperation = [webView draggingUpdated:draggingInfo];
+
+ if (dragOperation != NSDragOperationNone)
+ [webView performDragOperation:draggingInfo];
+ else
+ [webView draggingExited:draggingInfo];
+ // Per NSDragging.h: draggingSources may not implement draggedImage:endedAt:operation:
+ if ([[draggingInfo draggingSource] respondsToSelector:@selector(draggedImage:endedAt:operation:)])
+ [[draggingInfo draggingSource] draggedImage:[draggingInfo draggedImage] endedAt:lastMousePosition operation:dragOperation];
+ [draggingInfo release];
+ draggingInfo = nil;
+ }
+}
+
+- (void)mouseUp:(int)buttonNumber
+{
+ [self mouseUp:buttonNumber withModifiers:nil];
+}
+
+- (void)mouseMoveToX:(int)x Y:(int)y
+{
+ if (dragMode && leftMouseButtonDown && !replayingSavedEvents) {
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(mouseMoveToX:Y:)]];
+ [invocation setTarget:self];
+ [invocation setSelector:@selector(mouseMoveToX:Y:)];
+ [invocation setArgument:&x atIndex:2];
+ [invocation setArgument:&y atIndex:3];
+
+ [EventSendingController saveEvent:invocation];
+ return;
+ }
+
+ NSView *view = [mainFrame webView];
+ lastMousePosition = [view convertPoint:NSMakePoint(x, [view frame].size.height - y) toView:nil];
+ NSEvent *event = [NSEvent mouseEventWithType:(leftMouseButtonDown ? NSLeftMouseDragged : NSMouseMoved)
+ location:lastMousePosition
+ modifierFlags:0
+ timestamp:[self currentEventTime]
+ windowNumber:[[view window] windowNumber]
+ context:[NSGraphicsContext currentContext]
+ eventNumber:++eventNumber
+ clickCount:(leftMouseButtonDown ? clickCount : 0)
+ pressure:0.0];
+
+ NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]];
+ if (subView) {
+ if (leftMouseButtonDown) {
+ if (draggingInfo) {
+ // Per NSDragging.h: draggingSources may not implement draggedImage:movedTo:
+ if ([[draggingInfo draggingSource] respondsToSelector:@selector(draggedImage:movedTo:)])
+ [[draggingInfo draggingSource] draggedImage:[draggingInfo draggedImage] movedTo:lastMousePosition];
+ [[mainFrame webView] draggingUpdated:draggingInfo];
+ } else
+ [subView mouseDragged:event];
+ } else
+ [subView mouseMoved:event];
+ }
+}
+
+- (void)mouseScrollByX:(int)x andY:(int)y continuously:(BOOL)c
+{
+ CGScrollEventUnit unit = c?kCGScrollEventUnitPixel:kCGScrollEventUnitLine;
+ CGEventRef cgScrollEvent = CGEventCreateScrollWheelEvent(NULL, unit, 2, y, x);
+
+ // CGEvent locations are in global display coordinates.
+ CGPoint lastGlobalMousePosition = {
+ lastMousePosition.x,
+ [[NSScreen mainScreen] frame].size.height - lastMousePosition.y
+ };
+ CGEventSetLocation(cgScrollEvent, lastGlobalMousePosition);
+
+ NSEvent *scrollEvent = [NSEvent eventWithCGEvent:cgScrollEvent];
+ CFRelease(cgScrollEvent);
+
+ NSView *subView = [[mainFrame webView] hitTest:[scrollEvent locationInWindow]];
+ if (subView)
+ [subView scrollWheel:scrollEvent];
+}
+
+- (void)continuousMouseScrollByX:(int)x andY:(int)y
+{
+ [self mouseScrollByX:x andY:y continuously:YES];
+}
+
+- (void)mouseScrollByX:(int)x andY:(int)y
+{
+ [self mouseScrollByX:x andY:y continuously:NO];
+}
+
+- (NSArray *)contextClick
+{
+ [[[mainFrame frameView] documentView] layout];
+ [self updateClickCountForButton:RightMouseButton];
+
+ NSEvent *event = [NSEvent mouseEventWithType:NSRightMouseDown
+ location:lastMousePosition
+ modifierFlags:0
+ timestamp:[self currentEventTime]
+ windowNumber:[[[mainFrame webView] window] windowNumber]
+ context:[NSGraphicsContext currentContext]
+ eventNumber:++eventNumber
+ clickCount:clickCount
+ pressure:0.0];
+
+ NSView *subView = [[mainFrame webView] hitTest:[event locationInWindow]];
+ NSMutableArray *menuItemStrings = [NSMutableArray array];
+
+ if (subView) {
+ NSMenu* menu = [subView menuForEvent:event];
+
+ for (int i = 0; i < [menu numberOfItems]; ++i) {
+ NSMenuItem* menuItem = [menu itemAtIndex:i];
+ if (!strcmp("Inspect Element", [[menuItem title] UTF8String]))
+ continue;
+
+ if ([menuItem isSeparatorItem])
+ [menuItemStrings addObject:@"<separator>"];
+ else
+ [menuItemStrings addObject:[menuItem title]];
+ }
+ }
+
+ return menuItemStrings;
+}
+
+- (void)scheduleAsynchronousClick
+{
+ [self performSelector:@selector(mouseDown:) withObject:nil afterDelay:0];
+ [self performSelector:@selector(mouseUp:) withObject:nil afterDelay:0];
+}
+
++ (void)saveEvent:(NSInvocation *)event
+{
+ if (!savedMouseEvents)
+ savedMouseEvents = [[NSMutableArray alloc] init];
+ [savedMouseEvents addObject:event];
+}
+
++ (void)replaySavedEvents
+{
+ replayingSavedEvents = YES;
+ while ([savedMouseEvents count]) {
+ // if a drag is initiated, the remaining saved events will be dispatched from our dragging delegate
+ NSInvocation *invocation = [[[savedMouseEvents objectAtIndex:0] retain] autorelease];
+ [savedMouseEvents removeObjectAtIndex:0];
+ [invocation invoke];
+ }
+ replayingSavedEvents = NO;
+}
+
++ (void)clearSavedEvents
+{
+ [savedMouseEvents release];
+ savedMouseEvents = nil;
+}
+
+- (void)keyDown:(NSString *)character withModifiers:(WebScriptObject *)modifiers withLocation:(unsigned long)keyLocation
+{
+ NSString *eventCharacter = character;
+ unsigned short keyCode = 0;
+ if ([character isEqualToString:@"leftArrow"]) {
+ const unichar ch = NSLeftArrowFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x7B;
+ } else if ([character isEqualToString:@"rightArrow"]) {
+ const unichar ch = NSRightArrowFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x7C;
+ } else if ([character isEqualToString:@"upArrow"]) {
+ const unichar ch = NSUpArrowFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x7E;
+ } else if ([character isEqualToString:@"downArrow"]) {
+ const unichar ch = NSDownArrowFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x7D;
+ } else if ([character isEqualToString:@"pageUp"]) {
+ const unichar ch = NSPageUpFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x74;
+ } else if ([character isEqualToString:@"pageDown"]) {
+ const unichar ch = NSPageDownFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x79;
+ } else if ([character isEqualToString:@"home"]) {
+ const unichar ch = NSHomeFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x73;
+ } else if ([character isEqualToString:@"end"]) {
+ const unichar ch = NSEndFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x77;
+ } else if ([character isEqualToString:@"insert"]) {
+ const unichar ch = NSInsertFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x72;
+ } else if ([character isEqualToString:@"delete"]) {
+ const unichar ch = NSDeleteFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x75;
+ } else if ([character isEqualToString:@"printScreen"]) {
+ const unichar ch = NSPrintScreenFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ keyCode = 0x0; // There is no known virtual key code for PrintScreen.
+ }
+
+ // Compare the input string with the function-key names defined by the DOM spec (i.e. "F1",...,"F24").
+ // If the input string is a function-key name, set its key code.
+ for (unsigned i = 1; i <= 24; i++) {
+ if ([character isEqualToString:[NSString stringWithFormat:@"F%u", i]]) {
+ const unichar ch = NSF1FunctionKey + (i - 1);
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ switch (i) {
+ case 1: keyCode = 0x7A; break;
+ case 2: keyCode = 0x78; break;
+ case 3: keyCode = 0x63; break;
+ case 4: keyCode = 0x76; break;
+ case 5: keyCode = 0x60; break;
+ case 6: keyCode = 0x61; break;
+ case 7: keyCode = 0x62; break;
+ case 8: keyCode = 0x64; break;
+ case 9: keyCode = 0x65; break;
+ case 10: keyCode = 0x6D; break;
+ case 11: keyCode = 0x67; break;
+ case 12: keyCode = 0x6F; break;
+ case 13: keyCode = 0x69; break;
+ case 14: keyCode = 0x6B; break;
+ case 15: keyCode = 0x71; break;
+ case 16: keyCode = 0x6A; break;
+ case 17: keyCode = 0x40; break;
+ case 18: keyCode = 0x4F; break;
+ case 19: keyCode = 0x50; break;
+ case 20: keyCode = 0x5A; break;
+ }
+ }
+ }
+
+ // FIXME: No keyCode is set for most keys.
+ if ([character isEqualToString:@"\t"])
+ keyCode = 0x30;
+ else if ([character isEqualToString:@" "])
+ keyCode = 0x31;
+ else if ([character isEqualToString:@"\r"])
+ keyCode = 0x24;
+ else if ([character isEqualToString:@"\n"])
+ keyCode = 0x4C;
+ else if ([character isEqualToString:@"\x8"])
+ keyCode = 0x33;
+ else if ([character isEqualToString:@"7"])
+ keyCode = 0x1A;
+ else if ([character isEqualToString:@"5"])
+ keyCode = 0x17;
+ else if ([character isEqualToString:@"9"])
+ keyCode = 0x19;
+ else if ([character isEqualToString:@"0"])
+ keyCode = 0x1D;
+ else if ([character isEqualToString:@"a"])
+ keyCode = 0x00;
+ else if ([character isEqualToString:@"b"])
+ keyCode = 0x0B;
+ else if ([character isEqualToString:@"d"])
+ keyCode = 0x02;
+ else if ([character isEqualToString:@"e"])
+ keyCode = 0x0E;
+
+ NSString *charactersIgnoringModifiers = eventCharacter;
+
+ int modifierFlags = 0;
+
+ if ([character length] == 1 && [character characterAtIndex:0] >= 'A' && [character characterAtIndex:0] <= 'Z') {
+ modifierFlags |= NSShiftKeyMask;
+ charactersIgnoringModifiers = [character lowercaseString];
+ }
+
+ modifierFlags |= buildModifierFlags(modifiers);
+
+ if (keyLocation == DOM_KEY_LOCATION_NUMPAD)
+ modifierFlags |= NSNumericPadKeyMask;
+
+ [[[mainFrame frameView] documentView] layout];
+
+ NSEvent *event = [NSEvent keyEventWithType:NSKeyDown
+ location:NSMakePoint(5, 5)
+ modifierFlags:modifierFlags
+ timestamp:[self currentEventTime]
+ windowNumber:[[[mainFrame webView] window] windowNumber]
+ context:[NSGraphicsContext currentContext]
+ characters:eventCharacter
+ charactersIgnoringModifiers:charactersIgnoringModifiers
+ isARepeat:NO
+ keyCode:keyCode];
+
+ [[[[mainFrame webView] window] firstResponder] keyDown:event];
+
+ event = [NSEvent keyEventWithType:NSKeyUp
+ location:NSMakePoint(5, 5)
+ modifierFlags:modifierFlags
+ timestamp:[self currentEventTime]
+ windowNumber:[[[mainFrame webView] window] windowNumber]
+ context:[NSGraphicsContext currentContext]
+ characters:eventCharacter
+ charactersIgnoringModifiers:charactersIgnoringModifiers
+ isARepeat:NO
+ keyCode:keyCode];
+
+ [[[[mainFrame webView] window] firstResponder] keyUp:event];
+}
+
+- (void)enableDOMUIEventLogging:(WebScriptObject *)node
+{
+ NSEnumerator *eventEnumerator = [webkitDomEventNames objectEnumerator];
+ id eventName;
+ while ((eventName = [eventEnumerator nextObject])) {
+ [(id<DOMEventTarget>)node addEventListener:eventName listener:self useCapture:NO];
+ }
+}
+
+- (void)handleEvent:(DOMEvent *)event
+{
+ DOMNode *target = [event target];
+
+ printf("event type: %s\n", [[event type] UTF8String]);
+ printf(" target: <%s>\n", [[[target nodeName] lowercaseString] UTF8String]);
+
+ if ([event isKindOfClass:[DOMEvent class]]) {
+ printf(" eventPhase: %d\n", [event eventPhase]);
+ printf(" bubbles: %d\n", [event bubbles] ? 1 : 0);
+ printf(" cancelable: %d\n", [event cancelable] ? 1 : 0);
+ }
+
+ if ([event isKindOfClass:[DOMUIEvent class]]) {
+ printf(" detail: %d\n", [(DOMUIEvent*)event detail]);
+
+ DOMAbstractView *view = [(DOMUIEvent*)event view];
+ if (view) {
+ printf(" view: OK");
+ if ([view document])
+ printf(" (document: OK)");
+ printf("\n");
+ }
+ }
+
+ if ([event isKindOfClass:[DOMKeyboardEvent class]]) {
+ printf(" keyIdentifier: %s\n", [[(DOMKeyboardEvent*)event keyIdentifier] UTF8String]);
+ printf(" keyLocation: %d\n", [(DOMKeyboardEvent*)event keyLocation]);
+ printf(" modifier keys: c:%d s:%d a:%d m:%d\n",
+ [(DOMKeyboardEvent*)event ctrlKey] ? 1 : 0,
+ [(DOMKeyboardEvent*)event shiftKey] ? 1 : 0,
+ [(DOMKeyboardEvent*)event altKey] ? 1 : 0,
+ [(DOMKeyboardEvent*)event metaKey] ? 1 : 0);
+ printf(" keyCode: %d\n", [(DOMKeyboardEvent*)event keyCode]);
+ printf(" charCode: %d\n", [(DOMKeyboardEvent*)event charCode]);
+ }
+
+ if ([event isKindOfClass:[DOMMouseEvent class]]) {
+ printf(" button: %d\n", [(DOMMouseEvent*)event button]);
+ printf(" clientX: %d\n", [(DOMMouseEvent*)event clientX]);
+ printf(" clientY: %d\n", [(DOMMouseEvent*)event clientY]);
+ printf(" screenX: %d\n", [(DOMMouseEvent*)event screenX]);
+ printf(" screenY: %d\n", [(DOMMouseEvent*)event screenY]);
+ printf(" modifier keys: c:%d s:%d a:%d m:%d\n",
+ [(DOMMouseEvent*)event ctrlKey] ? 1 : 0,
+ [(DOMMouseEvent*)event shiftKey] ? 1 : 0,
+ [(DOMMouseEvent*)event altKey] ? 1 : 0,
+ [(DOMMouseEvent*)event metaKey] ? 1 : 0);
+ id relatedTarget = [(DOMMouseEvent*)event relatedTarget];
+ if (relatedTarget) {
+ printf(" relatedTarget: %s", [[[relatedTarget class] description] UTF8String]);
+ if ([relatedTarget isKindOfClass:[DOMNode class]])
+ printf(" (nodeName: %s)", [[(DOMNode*)relatedTarget nodeName] UTF8String]);
+ printf("\n");
+ }
+ }
+
+ if ([event isKindOfClass:[DOMMutationEvent class]]) {
+ printf(" prevValue: %s\n", [[(DOMMutationEvent*)event prevValue] UTF8String]);
+ printf(" newValue: %s\n", [[(DOMMutationEvent*)event newValue] UTF8String]);
+ printf(" attrName: %s\n", [[(DOMMutationEvent*)event attrName] UTF8String]);
+ printf(" attrChange: %d\n", [(DOMMutationEvent*)event attrChange]);
+ DOMNode *relatedNode = [(DOMMutationEvent*)event relatedNode];
+ if (relatedNode) {
+ printf(" relatedNode: %s (nodeName: %s)\n",
+ [[[relatedNode class] description] UTF8String],
+ [[relatedNode nodeName] UTF8String]);
+ }
+ }
+
+ if ([event isKindOfClass:[DOMWheelEvent class]]) {
+ printf(" clientX: %d\n", [(DOMWheelEvent*)event clientX]);
+ printf(" clientY: %d\n", [(DOMWheelEvent*)event clientY]);
+ printf(" screenX: %d\n", [(DOMWheelEvent*)event screenX]);
+ printf(" screenY: %d\n", [(DOMWheelEvent*)event screenY]);
+ printf(" modifier keys: c:%d s:%d a:%d m:%d\n",
+ [(DOMWheelEvent*)event ctrlKey] ? 1 : 0,
+ [(DOMWheelEvent*)event shiftKey] ? 1 : 0,
+ [(DOMWheelEvent*)event altKey] ? 1 : 0,
+ [(DOMWheelEvent*)event metaKey] ? 1 : 0);
+ printf(" isHorizontal: %d\n", [(DOMWheelEvent*)event isHorizontal] ? 1 : 0);
+ printf(" wheelDelta: %d\n", [(DOMWheelEvent*)event wheelDelta]);
+ }
+}
+
+// FIXME: It's not good to have a test hard-wired into this controller like this.
+// Instead we need to get testing framework based on the Objective-C bindings
+// to work well enough that we can test that way instead.
+- (void)fireKeyboardEventsToElement:(WebScriptObject *)element {
+
+ if (![element isKindOfClass:[DOMHTMLElement class]])
+ return;
+
+ DOMHTMLElement *target = (DOMHTMLElement*)element;
+ DOMDocument *document = [target ownerDocument];
+
+ // Keyboard Event 1
+
+ DOMEvent *domEvent = [document createEvent:@"KeyboardEvent"];
+ [(DOMKeyboardEvent*)domEvent initKeyboardEvent:@"keydown"
+ canBubble:YES
+ cancelable:YES
+ view:[document defaultView]
+ keyIdentifier:@"U+000041"
+ keyLocation:0
+ ctrlKey:YES
+ altKey:NO
+ shiftKey:NO
+ metaKey:NO];
+ [target dispatchEvent:domEvent];
+
+ // Keyboard Event 2
+
+ domEvent = [document createEvent:@"KeyboardEvent"];
+ [(DOMKeyboardEvent*)domEvent initKeyboardEvent:@"keypress"
+ canBubble:YES
+ cancelable:YES
+ view:[document defaultView]
+ keyIdentifier:@"U+000045"
+ keyLocation:1
+ ctrlKey:NO
+ altKey:YES
+ shiftKey:NO
+ metaKey:NO];
+ [target dispatchEvent:domEvent];
+
+ // Keyboard Event 3
+
+ domEvent = [document createEvent:@"KeyboardEvent"];
+ [(DOMKeyboardEvent*)domEvent initKeyboardEvent:@"keyup"
+ canBubble:YES
+ cancelable:YES
+ view:[document defaultView]
+ keyIdentifier:@"U+000056"
+ keyLocation:0
+ ctrlKey:NO
+ altKey:NO
+ shiftKey:NO
+ metaKey:NO];
+ [target dispatchEvent:domEvent];
+
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/FrameLoadDelegate.h b/Tools/DumpRenderTree/mac/FrameLoadDelegate.h
new file mode 100644
index 000000000..390a88184
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/FrameLoadDelegate.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+class AccessibilityController;
+class GCController;
+
+@interface FrameLoadDelegate : NSObject
+{
+ AccessibilityController* accessibilityController;
+ GCController* gcController;
+}
+
+- (void)resetToConsistentState;
+
+@end
diff --git a/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm b/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm
new file mode 100644
index 000000000..e453aeaa5
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "DumpRenderTree.h"
+#import "FrameLoadDelegate.h"
+
+#import "AccessibilityController.h"
+#import "AppleScriptController.h"
+#import "EventSendingController.h"
+#import "Foundation/NSNotification.h"
+#import "GCController.h"
+#import "LayoutTestController.h"
+#import "NavigationController.h"
+#import "ObjCController.h"
+#import "ObjCPlugin.h"
+#import "ObjCPluginFunction.h"
+#import "PlainTextController.h"
+#import "TextInputController.h"
+#import "WebCoreTestSupport.h"
+#import "WorkQueue.h"
+#import "WorkQueueItem.h"
+#import <JavaScriptCore/JavaScriptCore.h>
+#import <WebKit/WebFramePrivate.h>
+#import <WebKit/WebHTMLViewPrivate.h>
+#import <WebKit/WebKit.h>
+#import <WebKit/WebNSURLExtras.h>
+#import <WebKit/WebScriptWorld.h>
+#import <WebKit/WebSecurityOriginPrivate.h>
+#import <WebKit/WebViewPrivate.h>
+#import <wtf/Assertions.h>
+
+@interface NSURL (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@interface NSError (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@interface NSURLResponse (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@interface NSURLRequest (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@interface WebFrame (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@implementation WebFrame (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult
+{
+ BOOL isMainFrame = (self == [[self webView] mainFrame]);
+ NSString *name = [self name];
+ if (isMainFrame) {
+ if ([name length])
+ return [NSString stringWithFormat:@"main frame \"%@\"", name];
+ else
+ return @"main frame";
+ } else {
+ if (name)
+ return [NSString stringWithFormat:@"frame \"%@\"", name];
+ else
+ return @"frame (anonymous)";
+ }
+}
+
+- (NSString *)_drt_printFrameUserGestureStatus
+{
+ BOOL isUserGesture = [[self webView] _isProcessingUserGesture];
+ return [NSString stringWithFormat:@"Frame with user gesture \"%@\"", isUserGesture ? @"true" : @"false"];
+}
+@end
+
+@implementation FrameLoadDelegate
+
+- (id)init
+{
+ if ((self = [super init])) {
+ gcController = new GCController;
+ accessibilityController = new AccessibilityController;
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(webViewProgressFinishedNotification:) name:WebViewProgressFinishedNotification object:nil];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ delete gcController;
+ delete accessibilityController;
+ [super dealloc];
+}
+
+// Exec messages in the work queue until they're all done, or one of them starts a new load
+- (void)processWork:(id)dummy
+{
+ // if another load started, then wait for it to complete.
+ if (topLoadingFrame)
+ return;
+
+ // if we finish all the commands, we're ready to dump state
+ if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump())
+ dump();
+}
+
+- (void)resetToConsistentState
+{
+ accessibilityController->resetToConsistentState();
+}
+
+- (void)webView:(WebView *)c locationChangeDone:(NSError *)error forDataSource:(WebDataSource *)dataSource
+{
+ if ([dataSource webFrame] == topLoadingFrame) {
+ topLoadingFrame = nil;
+ WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
+ if (!gLayoutTestController->waitToDump()) {
+ if (WorkQueue::shared()->count())
+ [self performSelector:@selector(processWork:) withObject:nil afterDelay:0];
+ else
+ dump();
+ }
+ }
+}
+
+- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didStartProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ }
+
+ if (!done && gLayoutTestController->dumpUserGestureInFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - in didStartProvisionalLoadForFrame", [frame _drt_printFrameUserGestureStatus]];
+ printf ("%s\n", [string UTF8String]);
+ }
+
+ ASSERT([frame provisionalDataSource]);
+ // Make sure we only set this once per test. If it gets cleared, and then set again, we might
+ // end up doing two dumps for one test.
+ if (!topLoadingFrame && !done)
+ topLoadingFrame = frame;
+
+ if (!done && gLayoutTestController->stopProvisionalFrameLoads()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - stopping load in didStartProvisionalLoadForFrame callback", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ [frame stopLoading];
+ }
+}
+
+- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didCommitLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ }
+
+ ASSERT(![frame provisionalDataSource]);
+ ASSERT([frame dataSource]);
+
+ gLayoutTestController->setWindowIsKey(true);
+ NSView *documentView = [[mainFrame frameView] documentView];
+ [[[mainFrame webView] window] makeFirstResponder:documentView];
+}
+
+- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didFailProvisionalLoadWithError", [frame _drt_descriptionSuitableForTestResult]];
+ printf("%s\n", [string UTF8String]);
+ }
+
+ if ([error domain] == NSURLErrorDomain && ([error code] == NSURLErrorServerCertificateHasUnknownRoot || [error code] == NSURLErrorServerCertificateUntrusted)) {
+ // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL
+ // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1 from within dumpRenderTree.
+ // Those are the only hosts that we use SSL with at present. If we hit this code path then we've found another host that we need
+ // to apply the workaround to.
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
+ ASSERT([frame provisionalDataSource]);
+ [self webView:sender locationChangeDone:error forDataSource:[frame provisionalDataSource]];
+}
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+ ASSERT([frame dataSource]);
+ ASSERT(frame == [[frame dataSource] webFrame]);
+
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ }
+
+ // FIXME: This call to displayIfNeeded can be removed when <rdar://problem/5092361> is fixed.
+ // After that is fixed, we will reenable painting after WebCore is done loading the document,
+ // and this call will no longer be needed.
+ if ([[sender mainFrame] isEqual:frame])
+ [sender displayIfNeeded];
+ [self webView:sender locationChangeDone:nil forDataSource:[frame dataSource]];
+ [gNavigationController webView:sender didFinishLoadForFrame:frame];
+}
+
+- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadWithError", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ }
+
+ ASSERT(![frame provisionalDataSource]);
+ ASSERT([frame dataSource]);
+
+ [self webView:sender locationChangeDone:error forDataSource:[frame dataSource]];
+}
+
+- (void)webView:(WebView *)webView windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"?? - windowScriptObjectAvailable"];
+ printf ("%s\n", [string UTF8String]);
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
+- (void)didClearWindowObjectInStandardWorldForFrame:(WebFrame *)frame
+{
+ // Make New-Style LayoutTestController
+ JSContextRef context = [frame globalContext];
+ JSObjectRef globalObject = JSContextGetGlobalObject(context);
+ JSValueRef exception = 0;
+
+ ASSERT(gLayoutTestController);
+ gLayoutTestController->makeWindowObject(context, globalObject, &exception);
+ ASSERT(!exception);
+
+ gcController->makeWindowObject(context, globalObject, &exception);
+ ASSERT(!exception);
+
+ accessibilityController->makeWindowObject(context, globalObject, &exception);
+ ASSERT(!exception);
+
+ WebCoreTestSupport::injectInternalsObject(context);
+
+ // Make Old-Style controllers
+
+ WebView *webView = [frame webView];
+ WebScriptObject *obj = [frame windowObject];
+ AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:webView];
+ [obj setValue:asc forKey:@"appleScriptController"];
+ [asc release];
+
+ EventSendingController *esc = [[EventSendingController alloc] init];
+ [obj setValue:esc forKey:@"eventSender"];
+ [esc release];
+
+ [obj setValue:gNavigationController forKey:@"navigationController"];
+
+ ObjCController *occ = [[ObjCController alloc] init];
+ [obj setValue:occ forKey:@"objCController"];
+ [occ release];
+
+ ObjCPlugin *plugin = [[ObjCPlugin alloc] init];
+ [obj setValue:plugin forKey:@"objCPlugin"];
+ [plugin release];
+
+ ObjCPluginFunction *pluginFunction = [[ObjCPluginFunction alloc] init];
+ [obj setValue:pluginFunction forKey:@"objCPluginFunction"];
+ [pluginFunction release];
+
+ [obj setValue:[PlainTextController sharedPlainTextController] forKey:@"plainText"];
+
+ TextInputController *tic = [[TextInputController alloc] initWithWebView:webView];
+ [obj setValue:tic forKey:@"textInputController"];
+ [tic release];
+}
+
+- (void)didClearWindowObjectForFrame:(WebFrame *)frame inIsolatedWorld:(WebScriptWorld *)world
+{
+ JSGlobalContextRef ctx = [frame _globalContextForScriptWorld:world];
+ if (!ctx)
+ return;
+
+ JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
+ if (!globalObject)
+ return;
+
+ JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
+}
+
+- (void)webView:(WebView *)sender didClearWindowObjectForFrame:(WebFrame *)frame inScriptWorld:(WebScriptWorld *)world
+{
+ if (world == [WebScriptWorld standardWorld])
+ [self didClearWindowObjectInStandardWorldForFrame:frame];
+ else
+ [self didClearWindowObjectForFrame:frame inIsolatedWorld:world];
+}
+
+- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didReceiveTitle: %@", [frame _drt_descriptionSuitableForTestResult], title];
+ printf ("%s\n", [string UTF8String]);
+ }
+
+ if (gLayoutTestController->dumpTitleChanges())
+ printf("TITLE CHANGED: %s\n", [title UTF8String]);
+}
+
+- (void)webView:(WebView *)sender didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didReceiveServerRedirectForProvisionalLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ }
+}
+
+- (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didChangeLocationWithinPageForFrame", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ }
+}
+
+- (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date forFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - willPerformClientRedirectToURL: %@ ", [frame _drt_descriptionSuitableForTestResult], [URL _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ }
+
+ if (!done && gLayoutTestController->dumpUserGestureInFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - in willPerformClientRedirect", [frame _drt_printFrameUserGestureStatus]];
+ printf ("%s\n", [string UTF8String]);
+ }
+}
+
+- (void)webView:(WebView *)sender didCancelClientRedirectForFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didCancelClientRedirectForFrame", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ }
+}
+
+- (void)webView:(WebView *)sender didFinishDocumentLoadForFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didFinishDocumentLoadForFrame", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ } else if (!done) {
+ unsigned pendingFrameUnloadEvents = [frame _pendingFrameUnloadEventCount];
+ if (pendingFrameUnloadEvents) {
+ NSString *string = [NSString stringWithFormat:@"%@ - has %u onunload handler(s)", [frame _drt_descriptionSuitableForTestResult], pendingFrameUnloadEvents];
+ printf ("%s\n", [string UTF8String]);
+ }
+ }
+}
+
+- (void)webView:(WebView *)sender didHandleOnloadEventsForFrame:(WebFrame *)frame
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didHandleOnloadEventsForFrame", [frame _drt_descriptionSuitableForTestResult]];
+ printf ("%s\n", [string UTF8String]);
+ }
+}
+
+- (void)webViewDidDisplayInsecureContent:(WebView *)sender
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf ("didDisplayInsecureContent\n");
+}
+
+- (void)webView:(WebView *)sender didRunInsecureContent:(WebSecurityOrigin *)origin
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf ("didRunInsecureContent\n");
+}
+
+- (void)webView:(WebView *)sender didDetectXSS:(NSURL *)insecureURL
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf ("didDetectXSS\n");
+}
+
+- (void)webViewProgressFinishedNotification:(NSNotification *)notification
+{
+ if (!done && gLayoutTestController->dumpProgressFinishedCallback())
+ printf ("postProgressFinishedNotification\n");
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/GCControllerMac.mm b/Tools/DumpRenderTree/mac/GCControllerMac.mm
new file mode 100644
index 000000000..de8a61e59
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/GCControllerMac.mm
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "GCController.h"
+
+#import <WebKit/WebCoreStatistics.h>
+
+
+void GCController::collect() const
+{
+ [WebCoreStatistics garbageCollectJavaScriptObjects];
+}
+
+void GCController::collectOnAlternateThread(bool waitUntilDone) const
+{
+ [WebCoreStatistics garbageCollectJavaScriptObjectsOnAlternateThreadForDebugging:waitUntilDone];
+}
+
+size_t GCController::getJSObjectCount() const
+{
+ return [WebCoreStatistics javaScriptObjectsCount];
+}
diff --git a/Tools/DumpRenderTree/mac/HistoryDelegate.h b/Tools/DumpRenderTree/mac/HistoryDelegate.h
new file mode 100644
index 000000000..c56d20368
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/HistoryDelegate.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface HistoryDelegate : NSObject
+{
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/HistoryDelegate.mm b/Tools/DumpRenderTree/mac/HistoryDelegate.mm
new file mode 100644
index 000000000..cbc409327
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/HistoryDelegate.mm
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#import "config.h"
+#import "HistoryDelegate.h"
+
+#import "DumpRenderTree.h"
+#import "LayoutTestController.h"
+
+#import <WebKit/WebNavigationData.h>
+#import <WebKit/WebView.h>
+
+@interface NSURL (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@implementation HistoryDelegate
+
+- (void)webView:(WebView *)webView didNavigateWithNavigationData:(WebNavigationData *)navigationData inFrame:(WebFrame *)webFrame
+{
+ NSURL *url = [navigationData url] ? [NSURL URLWithString:[navigationData url]] : nil;
+ bool hasClientRedirect = [[navigationData clientRedirectSource] length];
+ NSHTTPURLResponse *httpResponse = [[navigationData response] isKindOfClass:[NSHTTPURLResponse class]] ? (NSHTTPURLResponse *)[navigationData response] : nil;
+ bool wasFailure = [navigationData hasSubstituteData] || (httpResponse && [httpResponse statusCode] >= 400);
+
+ printf("WebView navigated to url \"%s\" with title \"%s\" with HTTP equivalent method \"%s\". The navigation was %s and was %s%s.\n",
+ url ? [[url _drt_descriptionSuitableForTestResult] UTF8String] : "<none>",
+ [navigationData title] ? [[navigationData title] UTF8String] : "",
+ [navigationData originalRequest] ? [[[navigationData originalRequest] HTTPMethod] UTF8String] : "",
+ wasFailure ? "a failure" : "successful",
+ hasClientRedirect ? "a client redirect from " : "not a client redirect",
+ hasClientRedirect ? [[navigationData clientRedirectSource] UTF8String] : "");
+}
+
+- (void)webView:(WebView *)webView didPerformClientRedirectFromURL:(NSString *)sourceURL toURL:(NSString *)destinationURL inFrame:(WebFrame *)webFrame
+{
+ NSURL *source = [NSURL URLWithString:sourceURL];
+ NSURL *dest = [NSURL URLWithString:destinationURL];
+ printf("WebView performed a client redirect from \"%s\" to \"%s\".\n", [[source _drt_descriptionSuitableForTestResult] UTF8String], [[dest _drt_descriptionSuitableForTestResult] UTF8String]);
+}
+
+- (void)webView:(WebView *)webView didPerformServerRedirectFromURL:(NSString *)sourceURL toURL:(NSString *)destinationURL inFrame:(WebFrame *)webFrame
+{
+ NSURL *source = [NSURL URLWithString:sourceURL];
+ NSURL *dest = [NSURL URLWithString:destinationURL];
+ printf("WebView performed a server redirect from \"%s\" to \"%s\".\n", [[source _drt_descriptionSuitableForTestResult] UTF8String], [[dest _drt_descriptionSuitableForTestResult] UTF8String]);
+}
+
+- (void)webView:(WebView *)webView updateHistoryTitle:(NSString *)title forURL:(NSString *)url
+{
+ printf("WebView updated the title for history URL \"%s\" to \"%s\".\n", [[[NSURL URLWithString:url]_drt_descriptionSuitableForTestResult] UTF8String], [title UTF8String]);
+}
+
+- (void)populateVisitedLinksForWebView:(WebView *)webView
+{
+ if (gLayoutTestController->dumpVisitedLinksCallback())
+ printf("Asked to populate visited links for WebView \"%s\"\n", [[[NSURL URLWithString:[webView mainFrameURL]] _drt_descriptionSuitableForTestResult] UTF8String]);
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h b/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h
new file mode 100644
index 000000000..ae1371fc6
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h
@@ -0,0 +1 @@
+#include "../../../../Source/WebKit/mac/Misc/WebTypesInternal.h"
diff --git a/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm
new file mode 100644
index 000000000..b7b14a79a
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm
@@ -0,0 +1,1243 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "DumpRenderTree.h"
+#import "LayoutTestController.h"
+
+#import "EditingDelegate.h"
+#import "MockGeolocationProvider.h"
+#import "PolicyDelegate.h"
+#import "StorageTrackerDelegate.h"
+#import "UIDelegate.h"
+#import "WorkQueue.h"
+#import "WorkQueueItem.h"
+#import <Foundation/Foundation.h>
+#import <JavaScriptCore/JSRetainPtr.h>
+#import <JavaScriptCore/JSStringRef.h>
+#import <JavaScriptCore/JSStringRefCF.h>
+#import <WebKit/DOMDocument.h>
+#import <WebKit/DOMElement.h>
+#import <WebKit/WebApplicationCache.h>
+#import <WebKit/WebBackForwardList.h>
+#import <WebKit/WebCoreStatistics.h>
+#import <WebKit/WebDOMOperationsPrivate.h>
+#import <WebKit/WebDataSource.h>
+#import <WebKit/WebDatabaseManagerPrivate.h>
+#import <WebKit/WebDeviceOrientation.h>
+#import <WebKit/WebDeviceOrientationProviderMock.h>
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebFrameViewPrivate.h>
+#import <WebKit/WebGeolocationPosition.h>
+#import <WebKit/WebHTMLRepresentation.h>
+#import <WebKit/WebHTMLViewPrivate.h>
+#import <WebKit/WebHistory.h>
+#import <WebKit/WebHistoryPrivate.h>
+#import <WebKit/WebIconDatabasePrivate.h>
+#import <WebKit/WebInspectorPrivate.h>
+#import <WebKit/WebNSURLExtras.h>
+#import <WebKit/WebKitErrors.h>
+#import <WebKit/WebPreferences.h>
+#import <WebKit/WebPreferencesPrivate.h>
+#import <WebKit/WebQuotaManager.h>
+#import <WebKit/WebScriptWorld.h>
+#import <WebKit/WebSecurityOriginPrivate.h>
+#import <WebKit/WebStorageManagerPrivate.h>
+#import <WebKit/WebTypesInternal.h>
+#import <WebKit/WebView.h>
+#import <WebKit/WebViewPrivate.h>
+#import <WebKit/WebWorkersPrivate.h>
+#import <wtf/CurrentTime.h>
+#import <wtf/HashMap.h>
+#import <wtf/RetainPtr.h>
+
+@interface CommandValidationTarget : NSObject <NSValidatedUserInterfaceItem>
+{
+ SEL _action;
+}
+- (id)initWithAction:(SEL)action;
+@end
+
+@implementation CommandValidationTarget
+
+- (id)initWithAction:(SEL)action
+{
+ self = [super init];
+ if (!self)
+ return nil;
+
+ _action = action;
+ return self;
+}
+
+- (SEL)action
+{
+ return _action;
+}
+
+- (NSInteger)tag
+{
+ return 0;
+}
+
+@end
+
+LayoutTestController::~LayoutTestController()
+{
+}
+
+void LayoutTestController::addDisallowedURL(JSStringRef url)
+{
+ RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url));
+
+ if (!disallowedURLs)
+ disallowedURLs = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL);
+
+ // Canonicalize the URL
+ NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]];
+ request = [NSURLProtocol canonicalRequestForRequest:request];
+
+ CFSetAddValue(disallowedURLs, [request URL]);
+}
+
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ return [[mainFrame webView] shouldClose];
+}
+
+void LayoutTestController::clearAllApplicationCaches()
+{
+ [WebApplicationCache deleteAllApplicationCaches];
+}
+
+long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef url)
+{
+ RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url));
+ WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]];
+ long long usage = [WebApplicationCache diskUsageForOrigin:origin];
+ [origin release];
+ return usage;
+}
+
+void LayoutTestController::syncLocalStorage()
+{
+ [[WebStorageManager sharedWebStorageManager] syncLocalStorage];
+}
+
+long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef url)
+{
+ RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url));
+ WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]];
+ long long usage = [[WebStorageManager sharedWebStorageManager] diskUsageForOrigin:origin];
+ [origin release];
+ return usage;
+}
+
+void LayoutTestController::observeStorageTrackerNotifications(unsigned number)
+{
+ [storageDelegate logNotifications:number controller:this];
+}
+
+void LayoutTestController::clearApplicationCacheForOrigin(JSStringRef url)
+{
+ RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url));
+
+ WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]];
+ [WebApplicationCache deleteCacheForOrigin:origin];
+ [origin release];
+}
+
+JSValueRef originsArrayToJS(JSContextRef context, NSArray *origins)
+{
+ NSUInteger count = [origins count];
+
+ JSValueRef jsOriginsArray[count];
+ for (NSUInteger i = 0; i < count; i++) {
+ NSString *origin = [[origins objectAtIndex:i] databaseIdentifier];
+ JSRetainPtr<JSStringRef> originJS(Adopt, JSStringCreateWithCFString((CFStringRef)origin));
+ jsOriginsArray[i] = JSValueMakeString(context, originJS.get());
+ }
+
+ return JSObjectMakeArray(context, count, jsOriginsArray, NULL);
+}
+
+JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context)
+{
+ return originsArrayToJS(context, [WebApplicationCache originsWithCache]);
+}
+
+void LayoutTestController::clearAllDatabases()
+{
+ [[WebDatabaseManager sharedWebDatabaseManager] deleteAllDatabases];
+}
+
+void LayoutTestController::deleteAllLocalStorage()
+{
+ [[WebStorageManager sharedWebStorageManager] deleteAllOrigins];
+}
+
+JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context)
+{
+ return originsArrayToJS(context, [[WebStorageManager sharedWebStorageManager] origins]);
+}
+
+void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef URL)
+{
+ RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, URL));
+
+ WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:(NSString *)urlCF.get()]];
+ [[WebStorageManager sharedWebStorageManager] deleteOrigin:origin];
+ [origin release];
+}
+
+void LayoutTestController::clearBackForwardList()
+{
+ WebBackForwardList *backForwardList = [[mainFrame webView] backForwardList];
+ WebHistoryItem *item = [[backForwardList currentItem] retain];
+
+ // We clear the history by setting the back/forward list's capacity to 0
+ // then restoring it back and adding back the current item.
+ int capacity = [backForwardList capacity];
+ [backForwardList setCapacity:0];
+ [backForwardList setCapacity:capacity];
+ [backForwardList addItem:item];
+ [backForwardList goToItem:item];
+ [item release];
+}
+
+JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name)
+{
+ RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name));
+ NSString *nameNS = (NSString *)nameCF.get();
+ return JSStringCreateWithCFString((CFStringRef)[nameNS _web_decodeHostName]);
+}
+
+JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name)
+{
+ RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name));
+ NSString *nameNS = (NSString *)nameCF.get();
+ return JSStringCreateWithCFString((CFStringRef)[nameNS _web_encodeHostName]);
+}
+
+void LayoutTestController::display()
+{
+ displayWebView();
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id)
+{
+ RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, id));
+ NSString *idNS = (NSString *)idCF.get();
+
+ DOMElement *element = [[mainFrame DOMDocument] getElementById:idNS];
+ if (!element)
+ return 0;
+
+ JSRetainPtr<JSStringRef> counterValue(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame counterValueForElement:element]));
+ return counterValue;
+}
+
+void LayoutTestController::keepWebHistory()
+{
+ if (![WebHistory optionalSharedHistory]) {
+ WebHistory *history = [[WebHistory alloc] init];
+ [WebHistory setOptionalSharedHistory:history];
+ [history release];
+ }
+}
+
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value)
+{
+ return [[mainFrame webView] _computedStyleIncludingVisitedInfo:context forElement:value];
+}
+
+JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping)
+{
+ return [[mainFrame webView] _nodesFromRect:context forDocument:value x:x y:y top:top right:right bottom:bottom left:left ignoreClipping:ignoreClipping];
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ JSRetainPtr<JSStringRef> string(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame _layerTreeAsText]));
+ return string;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const
+{
+ DOMElement *element = [DOMElement _DOMElementFromJSContext:context value:nodeObject];
+ if (!element)
+ return JSRetainPtr<JSStringRef>();
+
+ JSRetainPtr<JSStringRef> markerText(Adopt, JSStringCreateWithCFString((CFStringRef)[element _markerTextForListItem]));
+ return markerText;
+}
+
+int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels)
+{
+ RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, id));
+ NSString *idNS = (NSString *)idCF.get();
+
+ DOMElement *element = [[mainFrame DOMDocument] getElementById:idNS];
+ if (!element)
+ return -1;
+
+ return [mainFrame pageNumberForElement:element:pageWidthInPixels:pageHeightInPixels];
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const
+{
+ JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame pageProperty:propertyName:pageNumber]));
+ return propertyValue;
+}
+
+bool LayoutTestController::isPageBoxVisible(int pageNumber) const
+{
+ return [mainFrame isPageBoxVisible:pageNumber];
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const
+{
+ JSRetainPtr<JSStringRef> propertyValue(Adopt, JSStringCreateWithCFString((CFStringRef)[mainFrame pageSizeAndMarginsInPixels:pageNumber:width:height:marginTop:marginRight:marginBottom:marginLeft]));
+ return propertyValue;
+}
+
+int LayoutTestController::numberOfPages(float pageWidthInPixels, float pageHeightInPixels)
+{
+ return [mainFrame numberOfPages:pageWidthInPixels:pageHeightInPixels];
+}
+
+int LayoutTestController::numberOfPendingGeolocationPermissionRequests()
+{
+ return [[[mainFrame webView] UIDelegate] numberOfPendingGeolocationPermissionRequests];
+}
+
+size_t LayoutTestController::webHistoryItemCount()
+{
+ return [[[WebHistory optionalSharedHistory] allItems] count];
+}
+
+unsigned LayoutTestController::workerThreadCount() const
+{
+ return [WebWorkersPrivate workerThreadCount];
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::platformName() const
+{
+ JSRetainPtr<JSStringRef> platformName(Adopt, JSStringCreateWithUTF8CString("mac"));
+ return platformName;
+}
+
+void LayoutTestController::notifyDone()
+{
+ if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
+ dump();
+ m_waitToDump = false;
+}
+
+static inline std::string stringFromJSString(JSStringRef jsString)
+{
+ size_t maxBufferSize = JSStringGetMaximumUTF8CStringSize(jsString);
+ char* utf8Buffer = new char[maxBufferSize];
+ size_t bytesWrittenToUTF8Buffer = JSStringGetUTF8CString(jsString, utf8Buffer, maxBufferSize);
+ std::string stdString(utf8Buffer, bytesWrittenToUTF8Buffer - 1); // bytesWrittenToUTF8Buffer includes a trailing \0 which std::string doesn't need.
+ delete[] utf8Buffer;
+ return stdString;
+}
+
+static inline size_t indexOfSeparatorAfterDirectoryName(const std::string& directoryName, const std::string& fullPath)
+{
+ std::string searchKey = "/" + directoryName + "/";
+ size_t indexOfSearchKeyStart = fullPath.rfind(searchKey);
+ if (indexOfSearchKeyStart == std::string::npos) {
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+ // Callers expect the return value not to end in "/", so searchKey.length() - 1.
+ return indexOfSearchKeyStart + searchKey.length() - 1;
+}
+
+static inline std::string resourceRootAbsolutePath(const std::string& testPathOrURL, const std::string& expectedRootName)
+{
+ char* localResourceRootEnv = getenv("LOCAL_RESOURCE_ROOT");
+ if (localResourceRootEnv)
+ return std::string(localResourceRootEnv);
+
+ // This fallback approach works for non-http tests and is useful
+ // in the case when we're running DRT directly from the command line.
+ return testPathOrURL.substr(0, indexOfSeparatorAfterDirectoryName(expectedRootName, testPathOrURL));
+}
+
+JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef localResourceJSString)
+{
+ // The passed in path will be an absolute path to the resource starting
+ // with "/tmp" or "/tmp/LayoutTests", optionally starting with the explicit file:// protocol.
+ // /tmp maps to DUMPRENDERTREE_TEMP, and /tmp/LayoutTests maps to LOCAL_RESOURCE_ROOT.
+ // FIXME: This code should work on all *nix platforms and can be moved into LayoutTestController.cpp.
+ std::string expectedRootName;
+ std::string absolutePathToResourceRoot;
+ std::string localResourceString = stringFromJSString(localResourceJSString);
+
+ if (localResourceString.find("LayoutTests") != std::string::npos) {
+ expectedRootName = "LayoutTests";
+ absolutePathToResourceRoot = resourceRootAbsolutePath(m_testPathOrURL, expectedRootName);
+ } else if (localResourceString.find("tmp") != std::string::npos) {
+ expectedRootName = "tmp";
+ absolutePathToResourceRoot = getenv("DUMPRENDERTREE_TEMP");
+ } else {
+ ASSERT_NOT_REACHED(); // pathToLocalResource was passed a path it doesn't know how to map.
+ }
+ ASSERT(!absolutePathToResourceRoot.empty());
+ size_t indexOfSeparatorAfterRootName = indexOfSeparatorAfterDirectoryName(expectedRootName, localResourceString);
+ std::string absolutePathToLocalResource = absolutePathToResourceRoot + localResourceString.substr(indexOfSeparatorAfterRootName);
+
+ // Note: It's important that we keep the file:// or http tests will get confused.
+ if (localResourceString.find("file://") != std::string::npos) {
+ ASSERT(absolutePathToLocalResource[0] == '/');
+ absolutePathToLocalResource = std::string("file://") + absolutePathToLocalResource;
+ }
+ return JSStringCreateWithUTF8CString(absolutePathToLocalResource.c_str());
+}
+
+void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target)
+{
+ RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url));
+ NSString *urlNS = (NSString *)urlCF.get();
+
+ NSURL *nsurl = [NSURL URLWithString:urlNS relativeToURL:[[[mainFrame dataSource] response] URL]];
+ NSString *nsurlString = [nsurl absoluteString];
+
+ JSRetainPtr<JSStringRef> absoluteURL(Adopt, JSStringCreateWithUTF8CString([nsurlString UTF8String]));
+ WorkQueue::shared()->queue(new LoadItem(absoluteURL.get(), target));
+}
+
+void LayoutTestController::setAcceptsEditing(bool newAcceptsEditing)
+{
+ [(EditingDelegate *)[[mainFrame webView] editingDelegate] setAcceptsEditing:newAcceptsEditing];
+}
+
+void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
+{
+ if (alwaysAcceptCookies == m_alwaysAcceptCookies)
+ return;
+
+ m_alwaysAcceptCookies = alwaysAcceptCookies;
+ NSHTTPCookieAcceptPolicy cookieAcceptPolicy = alwaysAcceptCookies ? NSHTTPCookieAcceptPolicyAlways : NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
+ [WebPreferences _setCurrentNetworkLoaderSessionCookieAcceptPolicy:cookieAcceptPolicy];
+}
+
+void LayoutTestController::setAppCacheMaximumSize(unsigned long long size)
+{
+ [WebApplicationCache setMaximumSize:size];
+}
+
+void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota)
+{
+ WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:@"http://127.0.0.1:8000"]];
+ [[origin applicationCacheQuotaManager] setQuota:quota];
+ [origin release];
+}
+
+void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag)
+{
+ [[[mainFrame webView] preferences] setAuthorAndUserStylesEnabled:flag];
+}
+
+void LayoutTestController::setAutofilled(JSContextRef context, JSValueRef nodeObject, bool autofilled)
+{
+ DOMElement *element = [DOMElement _DOMElementFromJSContext:context value:nodeObject];
+ if (!element || ![element isKindOfClass:[DOMHTMLInputElement class]])
+ return;
+
+ [(DOMHTMLInputElement *)element _setAutofilled:autofilled];
+}
+
+void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive)
+{
+ if (setDelegate) {
+ [policyDelegate setPermissive:permissive];
+ [[mainFrame webView] setPolicyDelegate:policyDelegate];
+ } else
+ [[mainFrame webView] setPolicyDelegate:nil];
+}
+
+void LayoutTestController::setDatabaseQuota(unsigned long long quota)
+{
+ WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:@"file:///"]];
+ [[origin databaseQuotaManager] setQuota:quota];
+ [origin release];
+}
+
+void LayoutTestController::goBack()
+{
+ [[mainFrame webView] goBack];
+}
+
+void LayoutTestController::setDefersLoading(bool defers)
+{
+ [[mainFrame webView] setDefersCallbacks:defers];
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme)
+{
+ RetainPtr<CFStringRef> schemeCFString(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, scheme));
+ [WebView _setDomainRelaxationForbidden:forbidden forURLScheme:(NSString *)schemeCFString.get()];
+}
+
+void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
+{
+ // DumpRenderTree configured the WebView to use WebDeviceOrientationProviderMock.
+ id<WebDeviceOrientationProvider> provider = [[mainFrame webView] _deviceOrientationProvider];
+ WebDeviceOrientationProviderMock *mockProvider = static_cast<WebDeviceOrientationProviderMock*>(provider);
+ WebDeviceOrientation *orientation = [[WebDeviceOrientation alloc] initWithCanProvideAlpha:canProvideAlpha alpha:alpha canProvideBeta:canProvideBeta beta:beta canProvideGamma:canProvideGamma gamma:gamma];
+ [mockProvider setOrientation:orientation];
+ [orientation release];
+}
+
+void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
+{
+ WebGeolocationPosition *position = [[WebGeolocationPosition alloc] initWithTimestamp:currentTime() latitude:latitude longitude:longitude accuracy:accuracy];
+ [[MockGeolocationProvider shared] setPosition:position];
+ [position release];
+}
+
+void LayoutTestController::setMockGeolocationError(int code, JSStringRef message)
+{
+ RetainPtr<CFStringRef> messageCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, message));
+ NSString *messageNS = (NSString *)messageCF.get();
+ NSError *error = [NSError errorWithDomain:WebKitErrorDomain code:code userInfo:[NSDictionary dictionaryWithObject:messageNS forKey:NSLocalizedDescriptionKey]];
+ [[MockGeolocationProvider shared] setError:error];
+}
+
+void LayoutTestController::setGeolocationPermission(bool allow)
+{
+ setGeolocationPermissionCommon(allow);
+ [[[mainFrame webView] UIDelegate] didSetMockGeolocationPermission];
+}
+
+void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::startSpeechInput(JSContextRef inputElement)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled)
+{
+ // FIXME: Workaround <rdar://problem/6480108>
+ static WebIconDatabase *sharedWebIconDatabase = NULL;
+ if (!sharedWebIconDatabase) {
+ if (!iconDatabaseEnabled)
+ return;
+ sharedWebIconDatabase = [WebIconDatabase sharedIconDatabase];
+ if ([sharedWebIconDatabase isEnabled] == iconDatabaseEnabled)
+ return;
+ }
+ [sharedWebIconDatabase setEnabled:iconDatabaseEnabled];
+}
+
+void LayoutTestController::setJavaScriptProfilingEnabled(bool profilingEnabled)
+{
+ setDeveloperExtrasEnabled(profilingEnabled);
+ [[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:profilingEnabled];
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
+{
+ NSView *documentView = [[mainFrame frameView] documentView];
+
+ NSResponder *firstResponder = flag ? documentView : nil;
+ [[[mainFrame webView] window] makeFirstResponder:firstResponder];
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
+{
+ [[[mainFrame webView] preferences] setPrivateBrowsingEnabled:privateBrowsingEnabled];
+}
+
+void LayoutTestController::setXSSAuditorEnabled(bool enabled)
+{
+ [[[mainFrame webView] preferences] setXSSAuditorEnabled:enabled];
+}
+
+void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
+{
+ [[[mainFrame webView] preferences] setFrameFlatteningEnabled:enabled];
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool enabled)
+{
+ [[[mainFrame webView] preferences] setSpatialNavigationEnabled:enabled];
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
+{
+ [[[mainFrame webView] preferences] setAllowUniversalAccessFromFileURLs:enabled];
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled)
+{
+ [[[mainFrame webView] preferences] setAllowFileAccessFromFileURLs:enabled];
+}
+
+void LayoutTestController::setPopupBlockingEnabled(bool popupBlockingEnabled)
+{
+ [[[mainFrame webView] preferences] setJavaScriptCanOpenWindowsAutomatically:!popupBlockingEnabled];
+}
+
+void LayoutTestController::setPluginsEnabled(bool pluginsEnabled)
+{
+ [[[mainFrame webView] preferences] setPlugInsEnabled:pluginsEnabled];
+}
+
+void LayoutTestController::setJavaScriptCanAccessClipboard(bool enabled)
+{
+ [[[mainFrame webView] preferences] setJavaScriptCanAccessClipboard:enabled];
+}
+
+void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles)
+{
+ [[mainFrame webView] setTabKeyCyclesThroughElements:cycles];
+}
+
+void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
+{
+ [[mainFrame webView] _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:flag];
+}
+
+void LayoutTestController::setUserStyleSheetEnabled(bool flag)
+{
+ [[WebPreferences standardPreferences] setUserStyleSheetEnabled:flag];
+}
+
+void LayoutTestController::setUserStyleSheetLocation(JSStringRef path)
+{
+ RetainPtr<CFStringRef> pathCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, path));
+ NSURL *url = [NSURL URLWithString:(NSString *)pathCF.get()];
+ [[WebPreferences standardPreferences] setUserStyleSheetLocation:url];
+}
+
+void LayoutTestController::setValueForUser(JSContextRef context, JSValueRef nodeObject, JSStringRef value)
+{
+ DOMElement *element = [DOMElement _DOMElementFromJSContext:context value:nodeObject];
+ if (!element || ![element isKindOfClass:[DOMHTMLInputElement class]])
+ return;
+
+ RetainPtr<CFStringRef> valueCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, value));
+ [(DOMHTMLInputElement *)element _setValueForUser:(NSString *)valueCF.get()];
+}
+
+void LayoutTestController::setViewModeMediaFeature(JSStringRef mode)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::disableImageLoading()
+{
+ [[WebPreferences standardPreferences] setLoadsImagesAutomatically:NO];
+}
+
+void LayoutTestController::dispatchPendingLoadRequests()
+{
+ [[mainFrame webView] _dispatchPendingLoadRequests];
+}
+
+void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value)
+{
+ RetainPtr<CFStringRef> keyCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, key));
+ NSString *keyNS = (NSString *)keyCF.get();
+
+ RetainPtr<CFStringRef> valueCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, value));
+ NSString *valueNS = (NSString *)valueCF.get();
+
+ [[WebPreferences standardPreferences] _setPreferenceForTestWithValue:valueNS forKey:keyNS];
+}
+
+void LayoutTestController::removeAllVisitedLinks()
+{
+ [WebHistory _removeAllVisitedLinks];
+}
+
+void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
+{
+ RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL));
+ ::setPersistentUserStyleSheetLocation(urlString.get());
+}
+
+void LayoutTestController::clearPersistentUserStyleSheet()
+{
+ ::setPersistentUserStyleSheetLocation(0);
+}
+
+void LayoutTestController::setWindowIsKey(bool windowIsKey)
+{
+ m_windowIsKey = windowIsKey;
+ [[mainFrame webView] _updateActiveState];
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(bool flag)
+{
+ [[mainFrame webView] setSmartInsertDeleteEnabled:flag];
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag)
+{
+ [[mainFrame webView] setSelectTrailingWhitespaceEnabled:flag];
+}
+
+static const CFTimeInterval waitToDumpWatchdogInterval = 30.0;
+
+static void waitUntilDoneWatchdogFired(CFRunLoopTimerRef timer, void* info)
+{
+ gLayoutTestController->waitToDumpWatchdogTimerFired();
+}
+
+void LayoutTestController::setWaitToDump(bool waitUntilDone)
+{
+ m_waitToDump = waitUntilDone;
+ if (m_waitToDump && !waitToDumpWatchdog) {
+ waitToDumpWatchdog = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + waitToDumpWatchdogInterval, 0, 0, 0, waitUntilDoneWatchdogFired, NULL);
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), waitToDumpWatchdog, kCFRunLoopCommonModes);
+ }
+}
+
+int LayoutTestController::windowCount()
+{
+ return CFArrayGetCount(openWindowsRef);
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef jsString)
+{
+ RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, jsString));
+ NSString *idNS = (NSString *)idCF.get();
+
+ DOMElement *element = [[mainFrame DOMDocument] getElementById:idNS];
+ id rep = [[mainFrame dataSource] representation];
+
+ if ([rep class] == [WebHTMLRepresentation class])
+ return [(WebHTMLRepresentation *)rep elementDoesAutoComplete:element];
+
+ return false;
+}
+
+void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
+{
+ RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name));
+ NSString *nameNS = (NSString *)nameCF.get();
+
+ RetainPtr<CFStringRef> valueCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, value));
+ NSString *valueNS = (NSString *)valueCF.get();
+
+ [[mainFrame webView] _executeCoreCommandByName:nameNS value:valueNS];
+}
+
+bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray)
+{
+ WebFindOptions options = 0;
+
+ JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
+ JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
+ if (!JSValueIsNumber(context, lengthValue))
+ return false;
+
+ RetainPtr<CFStringRef> targetCFString(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, target));
+
+ size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
+ for (size_t i = 0; i < length; ++i) {
+ JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
+ if (!JSValueIsString(context, value))
+ continue;
+
+ JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0));
+
+ if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
+ options |= WebFindOptionsCaseInsensitive;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
+ options |= WebFindOptionsAtWordStarts;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
+ options |= WebFindOptionsTreatMedialCapitalAsWordStart;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
+ options |= WebFindOptionsBackwards;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
+ options |= WebFindOptionsWrapAround;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection"))
+ options |= WebFindOptionsStartInSelection;
+ }
+
+ return [[mainFrame webView] findString:(NSString *)targetCFString.get() options:options];
+}
+
+void LayoutTestController::setCacheModel(int cacheModel)
+{
+ [[WebPreferences standardPreferences] setCacheModel:cacheModel];
+}
+
+bool LayoutTestController::isCommandEnabled(JSStringRef name)
+{
+ RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, name));
+ NSString *nameNS = (NSString *)nameCF.get();
+
+ // Accept command strings with capital letters for first letter without trailing colon.
+ if (![nameNS hasSuffix:@":"] && [nameNS length]) {
+ nameNS = [[[[nameNS substringToIndex:1] lowercaseString]
+ stringByAppendingString:[nameNS substringFromIndex:1]]
+ stringByAppendingString:@":"];
+ }
+
+ SEL selector = NSSelectorFromString(nameNS);
+ RetainPtr<CommandValidationTarget> target(AdoptNS, [[CommandValidationTarget alloc] initWithAction:selector]);
+ id validator = [NSApp targetForAction:selector to:[mainFrame webView] from:target.get()];
+ if (!validator)
+ return false;
+ if (![validator respondsToSelector:selector])
+ return false;
+ if (![validator respondsToSelector:@selector(validateUserInterfaceItem:)])
+ return true;
+ return [validator validateUserInterfaceItem:target.get()];
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
+{
+ RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId));
+ NSString *idNS = (NSString *)idCF.get();
+ RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, animationName));
+ NSString *nameNS = (NSString *)nameCF.get();
+
+ return [mainFrame _pauseAnimation:nameNS onNode:[[mainFrame DOMDocument] getElementById:idNS] atTime:time];
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId)
+{
+ RetainPtr<CFStringRef> idCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId));
+ NSString *idNS = (NSString *)idCF.get();
+ RetainPtr<CFStringRef> nameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, propertyName));
+ NSString *nameNS = (NSString *)nameCF.get();
+
+ return [mainFrame _pauseTransitionOfProperty:nameNS onNode:[[mainFrame DOMDocument] getElementById:idNS] atTime:time];
+}
+
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
+{
+ RetainPtr<CFStringRef> animationIDCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, animationId));
+ NSString *animationIDNS = (NSString *)animationIDCF.get();
+ RetainPtr<CFStringRef> elementIDCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId));
+ NSString *elementIDNS = (NSString *)elementIDCF.get();
+
+ return [mainFrame _pauseSVGAnimation:elementIDNS onSMILNode:[[mainFrame DOMDocument] getElementById:animationIDNS] atTime:time];
+}
+
+unsigned LayoutTestController::numberOfActiveAnimations() const
+{
+ return [mainFrame _numberOfActiveAnimations];
+}
+
+void LayoutTestController::suspendAnimations() const
+{
+ return [mainFrame _suspendAnimations];
+}
+
+void LayoutTestController::resumeAnimations() const
+{
+ return [mainFrame _resumeAnimations];
+}
+
+void LayoutTestController::waitForPolicyDelegate()
+{
+ setWaitToDump(true);
+ [policyDelegate setControllerToNotifyDone:this];
+ [[mainFrame webView] setPolicyDelegate:policyDelegate];
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+ RetainPtr<CFStringRef> sourceOriginCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, sourceOrigin));
+ NSString *sourceOriginNS = (NSString *)sourceOriginCF.get();
+ RetainPtr<CFStringRef> protocolCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationProtocol));
+ NSString *destinationProtocolNS = (NSString *)protocolCF.get();
+ RetainPtr<CFStringRef> hostCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationHost));
+ NSString *destinationHostNS = (NSString *)hostCF.get();
+ [WebView _addOriginAccessWhitelistEntryWithSourceOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains];
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+ RetainPtr<CFStringRef> sourceOriginCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, sourceOrigin));
+ NSString *sourceOriginNS = (NSString *)sourceOriginCF.get();
+ RetainPtr<CFStringRef> protocolCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationProtocol));
+ NSString *destinationProtocolNS = (NSString *)protocolCF.get();
+ RetainPtr<CFStringRef> hostCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationHost));
+ NSString *destinationHostNS = (NSString *)hostCF.get();
+ [WebView _removeOriginAccessWhitelistEntryWithSourceOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains];
+}
+
+void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
+{
+ RetainPtr<CFStringRef> sourceCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, source));
+ NSString *sourceNS = (NSString *)sourceCF.get();
+ [WebView _addUserScriptToGroup:@"org.webkit.DumpRenderTree" world:[WebScriptWorld world] source:sourceNS url:nil whitelist:nil blacklist:nil injectionTime:(runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd) injectedFrames:(allFrames ? WebInjectInAllFrames : WebInjectInTopFrameOnly)];
+}
+
+void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames)
+{
+ RetainPtr<CFStringRef> sourceCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, source));
+ NSString *sourceNS = (NSString *)sourceCF.get();
+ [WebView _addUserStyleSheetToGroup:@"org.webkit.DumpRenderTree" world:[WebScriptWorld world] source:sourceNS url:nil whitelist:nil blacklist:nil injectedFrames:(allFrames ? WebInjectInAllFrames : WebInjectInTopFrameOnly)];
+}
+
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
+{
+ [[[mainFrame webView] preferences] setDeveloperExtrasEnabled:enabled];
+}
+
+void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool enabled)
+{
+ [[[mainFrame webView] preferences] setAsynchronousSpellCheckingEnabled:enabled];
+}
+
+void LayoutTestController::showWebInspector()
+{
+ [[[mainFrame webView] inspector] show:nil];
+}
+
+void LayoutTestController::closeWebInspector()
+{
+ [[[mainFrame webView] inspector] close:nil];
+}
+
+void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script)
+{
+ RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, script));
+ NSString *scriptNS = (NSString *)scriptCF.get();
+ [[[mainFrame webView] inspector] evaluateInFrontend:nil callId:callId script:scriptNS];
+}
+
+typedef HashMap<unsigned, RetainPtr<WebScriptWorld> > WorldMap;
+static WorldMap& worldMap()
+{
+ static WorldMap& map = *new WorldMap;
+ return map;
+}
+
+unsigned worldIDForWorld(WebScriptWorld *world)
+{
+ WorldMap::const_iterator end = worldMap().end();
+ for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
+ if (it->second == world)
+ return it->first;
+ }
+
+ return 0;
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
+{
+ RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, script));
+ NSString *scriptNS = (NSString *)scriptCF.get();
+
+ // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
+ // that is created once and cached forever.
+ WebScriptWorld *world;
+ if (!worldID)
+ world = [WebScriptWorld world];
+ else {
+ RetainPtr<WebScriptWorld>& worldSlot = worldMap().add(worldID, 0).first->second;
+ if (!worldSlot)
+ worldSlot.adoptNS([[WebScriptWorld alloc] init]);
+ world = worldSlot.get();
+ }
+
+ [mainFrame _stringByEvaluatingJavaScriptFromString:scriptNS withGlobalObject:globalObject inScriptWorld:world];
+}
+
+void LayoutTestController::allowRoundingHacks()
+{
+ [WebView _setAllowsRoundingHacks:YES];
+}
+
+@interface APITestDelegate : NSObject
+{
+ bool* m_condition;
+}
+@end
+
+@implementation APITestDelegate
+
+- (id)initWithCompletionCondition:(bool*)condition
+{
+ [super init];
+ ASSERT(condition);
+ m_condition = condition;
+ *m_condition = false;
+ return self;
+}
+
+- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+ printf("API Test load failed\n");
+ *m_condition = true;
+}
+
+- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+ printf("API Test load failed provisional\n");
+ *m_condition = true;
+}
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+ printf("API Test load succeeded\n");
+ *m_condition = true;
+}
+
+@end
+
+void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ RetainPtr<CFStringRef> utf8DataCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, utf8Data));
+ RetainPtr<CFStringRef> baseURLCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, baseURL));
+
+ WebView *webView = [[WebView alloc] initWithFrame:NSZeroRect frameName:@"" groupName:@""];
+
+ bool done = false;
+ APITestDelegate *delegate = [[APITestDelegate alloc] initWithCompletionCondition:&done];
+ [webView setFrameLoadDelegate:delegate];
+
+ [[webView mainFrame] loadData:[(NSString *)utf8DataCF.get() dataUsingEncoding:NSUTF8StringEncoding] MIMEType:@"text/html" textEncodingName:@"utf-8" baseURL:[NSURL URLWithString:(NSString *)baseURLCF.get()]];
+
+ while (!done) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
+ [pool release];
+ }
+
+ [webView close];
+ [webView release];
+ [delegate release];
+ [pool release];
+}
+
+void LayoutTestController::apiTestGoToCurrentBackForwardItem()
+{
+ WebView *view = [mainFrame webView];
+ [view goToBackForwardItem:[[view backForwardList] currentItem]];
+}
+
+void LayoutTestController::setWebViewEditable(bool editable)
+{
+ WebView *view = [mainFrame webView];
+ [view setEditable:editable];
+}
+
+static NSString *SynchronousLoaderRunLoopMode = @"DumpRenderTreeSynchronousLoaderRunLoopMode";
+
+#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD)
+@protocol NSURLConnectionDelegate <NSObject>
+@end
+#endif
+
+@interface SynchronousLoader : NSObject <NSURLConnectionDelegate>
+{
+ NSString *m_username;
+ NSString *m_password;
+ BOOL m_isDone;
+}
++ (void)makeRequest:(NSURLRequest *)request withUsername:(NSString *)username password:(NSString *)password;
+@end
+
+@implementation SynchronousLoader : NSObject
+- (void)dealloc
+{
+ [m_username release];
+ [m_password release];
+
+ [super dealloc];
+}
+
+- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
+{
+ return YES;
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+{
+ if ([challenge previousFailureCount] == 0) {
+ RetainPtr<NSURLCredential> credential(AdoptNS, [[NSURLCredential alloc] initWithUser:m_username password:m_password persistence:NSURLCredentialPersistenceForSession]);
+ [[challenge sender] useCredential:credential.get() forAuthenticationChallenge:challenge];
+ return;
+ }
+ [[challenge sender] cancelAuthenticationChallenge:challenge];
+}
+
+- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
+{
+ printf("SynchronousLoader failed: %s\n", [[error description] UTF8String]);
+ m_isDone = YES;
+}
+
+- (void)connectionDidFinishLoading:(NSURLConnection *)connection
+{
+ m_isDone = YES;
+}
+
++ (void)makeRequest:(NSURLRequest *)request withUsername:(NSString *)username password:(NSString *)password
+{
+ ASSERT(![[request URL] user]);
+ ASSERT(![[request URL] password]);
+
+ SynchronousLoader *delegate = [[SynchronousLoader alloc] init];
+ delegate->m_username = [username copy];
+ delegate->m_password = [password copy];
+
+ NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO];
+ [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:SynchronousLoaderRunLoopMode];
+ [connection start];
+
+ while (!delegate->m_isDone)
+ [[NSRunLoop currentRunLoop] runMode:SynchronousLoaderRunLoopMode beforeDate:[NSDate distantFuture]];
+
+ [connection cancel];
+
+ [connection release];
+ [delegate release];
+}
+
+@end
+
+void LayoutTestController::authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password)
+{
+ // See <rdar://problem/7880699>.
+#ifndef BUILDING_ON_LEOPARD
+ RetainPtr<CFStringRef> urlStringCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url));
+ RetainPtr<CFStringRef> usernameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, username));
+ RetainPtr<CFStringRef> passwordCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, password));
+
+ RetainPtr<NSURLRequest> request(AdoptNS, [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:(NSString *)urlStringCF.get()]]);
+
+ [SynchronousLoader makeRequest:request.get() withUsername:(NSString *)usernameCF.get() password:(NSString *)passwordCF.get()];
+#endif
+}
+
+void LayoutTestController::setEditingBehavior(const char* editingBehavior)
+{
+ NSString *editingBehaviorNS = [[NSString alloc] initWithUTF8String:editingBehavior];
+ if ([editingBehaviorNS isEqualToString:@"mac"])
+ [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingMacBehavior];
+ else if ([editingBehaviorNS isEqualToString:@"win"])
+ [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingWinBehavior];
+ else if ([editingBehaviorNS isEqualToString:@"unix"])
+ [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingUnixBehavior];
+ [editingBehaviorNS release];
+}
+
+void LayoutTestController::abortModal()
+{
+ [NSApp abortModal];
+}
+
+bool LayoutTestController::hasSpellingMarker(int from, int length)
+{
+ return [mainFrame hasSpellingMarker:from length:length];
+}
+
+bool LayoutTestController::hasGrammarMarker(int from, int length)
+{
+ return [mainFrame hasGrammarMarker:from length:length];
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int /*deviceDPI*/, int /*deviceWidth*/, int /*deviceHeight*/, int /*availableWidth*/, int /*availableHeight*/)
+{
+
+}
+
+void LayoutTestController::setSerializeHTTPLoads(bool serialize)
+{
+ [WebView _setLoadResourcesSerially:serialize];
+}
+
+void LayoutTestController::setMinimumTimerInterval(double minimumTimerInterval)
+{
+ [[mainFrame webView] _setMinimumTimerInterval:minimumTimerInterval];
+}
+
+void LayoutTestController::setTextDirection(JSStringRef directionName)
+{
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ if (JSStringIsEqualToUTF8CString(directionName, "ltr"))
+ [[mainFrame webView] makeBaseWritingDirectionLeftToRight:0];
+ else if (JSStringIsEqualToUTF8CString(directionName, "rtl"))
+ [[mainFrame webView] makeBaseWritingDirectionRightToLeft:0];
+ else
+ ASSERT_NOT_REACHED();
+#endif
+}
+
+void LayoutTestController::addChromeInputField()
+{
+ NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)];
+ textField.tag = 1;
+ [[[[mainFrame webView] window] contentView] addSubview:textField];
+ [textField release];
+
+ [textField setNextKeyView:[mainFrame webView]];
+ [[mainFrame webView] setNextKeyView:textField];
+}
+
+void LayoutTestController::removeChromeInputField()
+{
+ NSView* textField = [[[[mainFrame webView] window] contentView] viewWithTag:1];
+ if (textField) {
+ [textField removeFromSuperview];
+ focusWebView();
+ }
+}
+
+void LayoutTestController::focusWebView()
+{
+ [[[mainFrame webView] window] makeFirstResponder:[mainFrame webView]];
+}
+
+void LayoutTestController::setBackingScaleFactor(double backingScaleFactor)
+{
+ [[mainFrame webView] _setCustomBackingScaleFactor:backingScaleFactor];
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title)
+{
+ // FIXME: Implement.
+}
diff --git a/Tools/DumpRenderTree/mac/MockGeolocationProvider.h b/Tools/DumpRenderTree/mac/MockGeolocationProvider.h
new file mode 100644
index 000000000..311d1e918
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/MockGeolocationProvider.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MockGeolocationProvider_h
+#define MockGeolocationProvider_h
+
+#import <WebKit/WebViewPrivate.h>
+#import <wtf/HashSet.h>
+
+@interface MockGeolocationProvider : NSObject<WebGeolocationProvider> {
+ WebGeolocationPosition *_lastPosition;
+ NSError *_error;
+ NSTimer *_timer;
+ HashSet<WebView *> _registeredViews;
+}
+
++ (MockGeolocationProvider *)shared;
+
+- (void)setPosition:(WebGeolocationPosition *)position;
+- (void)setError:(NSError *)error;
+
+- (void)stopTimer;
+
+@end
+#endif
diff --git a/Tools/DumpRenderTree/mac/MockGeolocationProvider.mm b/Tools/DumpRenderTree/mac/MockGeolocationProvider.mm
new file mode 100644
index 000000000..e03cae24a
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/MockGeolocationProvider.mm
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "MockGeolocationProvider.h"
+
+
+@implementation MockGeolocationProvider
+
++ (MockGeolocationProvider *)shared
+{
+ static MockGeolocationProvider *provider = [[MockGeolocationProvider alloc] init];
+ return provider;
+}
+
+- (void)dealloc
+{
+ ASSERT(_registeredViews.isEmpty());
+
+ [_lastPosition release];
+ [_error release];
+ [super dealloc];
+}
+
+- (void)setPosition:(WebGeolocationPosition *)position
+{
+ if (_lastPosition != position) {
+ [_lastPosition release];
+ _lastPosition = [position retain];
+ }
+
+ [_error release];
+ _error = 0;
+
+ if (!_timer)
+ _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO];
+}
+
+- (void)setError:(NSError *)error
+{
+ if (_error != error) {
+ [_error release];
+ _error = [error retain];
+ }
+
+ [_lastPosition release];
+ _lastPosition = 0;
+
+ if (!_timer)
+ _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO];
+}
+
+- (void)registerWebView:(WebView *)webView
+{
+ _registeredViews.add(webView);
+
+ if (!_timer)
+ _timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO];
+}
+
+- (void)unregisterWebView:(WebView *)webView
+{
+ _registeredViews.remove(webView);
+}
+
+- (WebGeolocationPosition *)lastPosition
+{
+ return _lastPosition;
+}
+
+- (void)stopTimer
+{
+ [_timer invalidate];
+ _timer = 0;
+}
+
+- (void)timerFired
+{
+ _timer = 0;
+
+ // Expect that views won't be (un)registered while iterating.
+ HashSet<WebView*> views = _registeredViews;
+ for (HashSet<WebView*>::iterator iter = views.begin(); iter != views.end(); ++iter) {
+ if (_error)
+ [*iter _geolocationDidFailWithError:_error];
+ else
+ [*iter _geolocationDidChangePosition:_lastPosition];
+ }
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/NavigationController.h b/Tools/DumpRenderTree/mac/NavigationController.h
new file mode 100644
index 000000000..8ee3432d9
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/NavigationController.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <WebKit/WebView.h>
+
+@interface NavigationController : NSObject
+{
+ enum { None, Load, GoBack, ExecuteScript } pendingAction;
+ NSString *pendingScript;
+ NSURLRequest *pendingRequest;
+}
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame;
+@end
diff --git a/Tools/DumpRenderTree/mac/NavigationController.m b/Tools/DumpRenderTree/mac/NavigationController.m
new file mode 100644
index 000000000..8c01d507b
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/NavigationController.m
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "NavigationController.h"
+
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebScriptObject.h>
+
+
+@implementation NavigationController
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector
+{
+ if (selector == @selector(evaluateWebScript:afterBackForwardNavigation:))
+ return NO;
+ return YES;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)selector
+{
+ if (selector == @selector(evaluateWebScript:afterBackForwardNavigation:))
+ return @"evalAfterBackForwardNavigation";
+ return nil;
+}
+
+- (void)setPendingScript:(NSString *)script
+{
+ if (script != pendingScript) {
+ [pendingScript release];
+ pendingScript = [script copy];
+ }
+}
+
+- (void)setPendingRequest:(NSURLRequest *)request
+{
+ if (request != pendingRequest) {
+ [pendingRequest release];
+ pendingRequest = [request copy];
+ }
+}
+
+- (void)evaluateWebScript:(NSString *)script afterBackForwardNavigation:(NSString *)navigation
+{
+ // Allow both arguments to be optional
+ if (![script isKindOfClass:[NSString class]])
+ script = @"";
+ if (![navigation isKindOfClass:[NSString class]])
+ navigation = @"about:blank";
+
+ [self setPendingScript:script];
+ [self setPendingRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:navigation]]];
+ pendingAction = Load;
+}
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+ if (frame == [[frame webView] mainFrame]) {
+ switch (pendingAction) {
+ case Load:
+ pendingAction = GoBack;
+ [frame loadRequest:pendingRequest];
+ [self setPendingRequest:nil];
+ break;
+ case GoBack:
+ pendingAction = ExecuteScript;
+ [[frame webView] goBack];
+ break;
+ case ExecuteScript:
+ pendingAction = None;
+ [[[frame webView] windowScriptObject] evaluateWebScript:pendingScript];
+ [self setPendingScript:nil];
+ break;
+ case None:
+ default:
+ break;
+ }
+ }
+}
+
+- (void)dealloc
+{
+ [self setPendingScript:nil];
+ [self setPendingRequest:nil];
+ [super dealloc];
+}
+@end
+
diff --git a/Tools/DumpRenderTree/mac/ObjCController.h b/Tools/DumpRenderTree/mac/ObjCController.h
new file mode 100644
index 000000000..d1d001cc5
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ObjCController.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class WebScriptObject;
+
+// This controller should be used to test Objective-C language features and the WebScriptObject.
+@interface ObjCController : NSObject
+{
+ WebScriptObject *storedWebScriptObject;
+}
+@end
diff --git a/Tools/DumpRenderTree/mac/ObjCController.m b/Tools/DumpRenderTree/mac/ObjCController.m
new file mode 100644
index 000000000..af237bf69
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ObjCController.m
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "ObjCController.h"
+
+// Avoid compile error in DOMPrivate.h.
+@class NSFont;
+
+#import <JavaScriptCore/JavaScriptCore.h>
+#import <WebKit/DOMAbstractView.h>
+#import <WebKit/DOMPrivate.h>
+#import <WebKit/WebScriptObject.h>
+#import <WebKit/WebView.h>
+#import <pthread.h>
+#import <wtf/Assertions.h>
+
+// Remove this once hasWebScriptKey has been made public.
+@interface WebScriptObject (StagedForPublic)
+- (BOOL)hasWebScriptKey:(NSString *)name;
+@end
+
+static void* runJavaScriptThread(void* arg)
+{
+ JSGlobalContextRef ctx = JSGlobalContextCreate(0);
+ JSStringRef scriptRef = JSStringCreateWithUTF8CString("'Hello World!'");
+
+ JSValueRef exception = 0;
+ JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
+ ASSERT(!exception);
+
+ JSGlobalContextRelease(ctx);
+ JSStringRelease(scriptRef);
+
+ return 0;
+}
+
+@implementation ObjCController
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
+{
+ if (0
+ || aSelector == @selector(classNameOf:)
+ || aSelector == @selector(isObject:instanceOf:)
+ || aSelector == @selector(objectOfClass:)
+ || aSelector == @selector(arrayOfString)
+ || aSelector == @selector(identityIsEqual::)
+ || aSelector == @selector(longLongRoundTrip:)
+ || aSelector == @selector(unsignedLongLongRoundTrip:)
+ || aSelector == @selector(testWrapperRoundTripping:)
+ || aSelector == @selector(accessStoredWebScriptObject)
+ || aSelector == @selector(storeWebScriptObject:)
+ || aSelector == @selector(testValueForKey)
+ || aSelector == @selector(testHasWebScriptKey:)
+ || aSelector == @selector(testArray)
+ || aSelector == @selector(setSelectElement:selectedIndex:allowingMultiple:)
+ )
+ return NO;
+ return YES;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)aSelector
+{
+ if (aSelector == @selector(classNameOf:))
+ return @"className";
+ if (aSelector == @selector(isObject:instanceOf:))
+ return @"isObjectInstanceOf";
+ if (aSelector == @selector(objectOfClass:))
+ return @"objectOfClass";
+ if (aSelector == @selector(arrayOfString))
+ return @"arrayOfString";
+ if (aSelector == @selector(identityIsEqual::))
+ return @"identityIsEqual";
+ if (aSelector == @selector(longLongRoundTrip:))
+ return @"longLongRoundTrip";
+ if (aSelector == @selector(unsignedLongLongRoundTrip:))
+ return @"unsignedLongLongRoundTrip";
+ if (aSelector == @selector(testWrapperRoundTripping:))
+ return @"testWrapperRoundTripping";
+ if (aSelector == @selector(storeWebScriptObject:))
+ return @"storeWebScriptObject";
+ if (aSelector == @selector(testValueForKey))
+ return @"testValueForKey";
+ if (aSelector == @selector(testHasWebScriptKey:))
+ return @"testHasWebScriptKey";
+ if (aSelector == @selector(testArray))
+ return @"testArray";
+ if (aSelector == @selector(setSelectElement:selectedIndex:allowingMultiple:))
+ return @"setSelectElementSelectedIndexAllowingMultiple";
+
+ return nil;
+}
+
+- (BOOL)isObject:(id)object instanceOf:(NSString *)aClass
+{
+ if (!object)
+ return [aClass isEqualToString:@"nil"];
+
+ return [object isKindOfClass:NSClassFromString(aClass)];
+}
+
+- (NSString *)classNameOf:(id)object
+{
+ if (!object)
+ return @"nil";
+ return NSStringFromClass([object class]);
+}
+
+- (id)objectOfClass:(NSString *)aClass
+{
+ if ([aClass isEqualToString:@"NSNull"])
+ return [NSNull null];
+ if ([aClass isEqualToString:@"WebUndefined"])
+ return [WebUndefined undefined];
+ if ([aClass isEqualToString:@"NSCFBoolean"])
+ return [NSNumber numberWithBool:true];
+ if ([aClass isEqualToString:@"NSCFNumber"])
+ return [NSNumber numberWithInt:1];
+ if ([aClass isEqualToString:@"NSCFString"])
+ return @"";
+ if ([aClass isEqualToString:@"WebScriptObject"])
+ return self;
+ if ([aClass isEqualToString:@"NSArray"])
+ return [NSArray array];
+
+ return nil;
+}
+
+- (NSArray *)arrayOfString
+{
+ NSString *strings[3];
+ strings[0] = @"one";
+ strings[1] = @"two";
+ strings[2] = @"three";
+ NSArray *array = [NSArray arrayWithObjects:strings count:3];
+ return array;
+}
+
+- (BOOL)identityIsEqual:(WebScriptObject *)a :(WebScriptObject *)b
+{
+ if ([a isKindOfClass:[NSString class]] && [b isKindOfClass:[NSString class]])
+ return [(NSString *)a isEqualToString:(NSString *)b];
+ return a == b;
+}
+
+- (long long)longLongRoundTrip:(long long)num
+{
+ return num;
+}
+
+- (unsigned long long)unsignedLongLongRoundTrip:(unsigned long long)num
+{
+ return num;
+}
+
+- (void)testValueForKey
+{
+ ASSERT(storedWebScriptObject);
+
+ @try {
+ [storedWebScriptObject valueForKey:@"ThisKeyDoesNotExist"];
+ } @catch (NSException *e) {
+ }
+
+ pthread_t pthread;
+ pthread_create(&pthread, 0, &runJavaScriptThread, 0);
+ pthread_join(pthread, 0);
+}
+
+- (BOOL)testHasWebScriptKey:(NSString *)key
+{
+ ASSERT(storedWebScriptObject);
+ return [storedWebScriptObject hasWebScriptKey:key];
+}
+
+- (BOOL)testWrapperRoundTripping:(WebScriptObject *)webScriptObject
+{
+ JSObjectRef jsObject = [webScriptObject JSObject];
+
+ if (!jsObject)
+ return false;
+
+ if (!webScriptObject)
+ return false;
+
+ if ([[webScriptObject evaluateWebScript:@"({ })"] class] != [webScriptObject class])
+ return false;
+
+ [webScriptObject setValue:[NSNumber numberWithInt:666] forKey:@"key"];
+ if (![[webScriptObject valueForKey:@"key"] isKindOfClass:[NSNumber class]] ||
+ ![[webScriptObject valueForKey:@"key"] isEqualToNumber:[NSNumber numberWithInt:666]])
+ return false;
+
+ [webScriptObject removeWebScriptKey:@"key"];
+ @try {
+ if ([webScriptObject valueForKey:@"key"])
+ return false;
+ } @catch(NSException *exception) {
+ // NSObject throws an exception if the key doesn't exist.
+ }
+
+ [webScriptObject setWebScriptValueAtIndex:0 value:webScriptObject];
+ if ([webScriptObject webScriptValueAtIndex:0] != webScriptObject)
+ return false;
+
+ if ([[webScriptObject stringRepresentation] isEqualToString:@"[Object object]"])
+ return false;
+
+ if ([webScriptObject callWebScriptMethod:@"returnThis" withArguments:nil] != webScriptObject)
+ return false;
+
+ return true;
+}
+
+- (void)accessStoredWebScriptObject
+{
+#if !ASSERT_DISABLED
+ BOOL isWindowObject = [storedWebScriptObject isKindOfClass:[DOMAbstractView class]];
+ JSObjectRef jsObject = [storedWebScriptObject JSObject];
+ ASSERT((jsObject && isWindowObject) || (!jsObject && !isWindowObject));
+#endif
+ [storedWebScriptObject callWebScriptMethod:@"" withArguments:nil];
+ [storedWebScriptObject evaluateWebScript:@""];
+ [storedWebScriptObject setValue:[WebUndefined undefined] forKey:@"key"];
+ [storedWebScriptObject valueForKey:@"key"];
+ [storedWebScriptObject removeWebScriptKey:@"key"];
+ [storedWebScriptObject stringRepresentation];
+ [storedWebScriptObject webScriptValueAtIndex:0];
+ [storedWebScriptObject setWebScriptValueAtIndex:0 value:[WebUndefined undefined]];
+ [storedWebScriptObject setException:@"exception"];
+}
+
+- (void)storeWebScriptObject:(WebScriptObject *)webScriptObject
+{
+ if (webScriptObject == storedWebScriptObject)
+ return;
+
+ [storedWebScriptObject release];
+ storedWebScriptObject = [webScriptObject retain];
+}
+
+- (NSArray *)testArray
+{
+ return [NSArray array];
+}
+
+- (void)dealloc
+{
+ [storedWebScriptObject release];
+ [super dealloc];
+}
+
+- (id)invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)args
+{
+ // FIXME: Perhaps we should log that this has been called.
+ return nil;
+}
+
+// MARK: -
+// MARK: Testing Objective-C DOM HTML Bindings
+
+- (void)setSelectElement:(WebScriptObject *)element selectedIndex:(int)index allowingMultiple:(BOOL)allowingMultiple
+{
+ if (![element isKindOfClass:[DOMHTMLSelectElement class]])
+ return;
+
+ DOMHTMLSelectElement *select = (DOMHTMLSelectElement*)element;
+ [select _activateItemAtIndex:index allowMultipleSelection:allowingMultiple];
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/ObjCPlugin.h b/Tools/DumpRenderTree/mac/ObjCPlugin.h
new file mode 100644
index 000000000..a6d3e50c1
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ObjCPlugin.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface ObjCPlugin : NSObject
+{
+ BOOL throwOnDealloc;
+}
+
+- (void)removeBridgeRestrictions:(id)container;
+
+@end
diff --git a/Tools/DumpRenderTree/mac/ObjCPlugin.m b/Tools/DumpRenderTree/mac/ObjCPlugin.m
new file mode 100644
index 000000000..023eae17f
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ObjCPlugin.m
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 James G. Speth (speth@end.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+*/
+
+#import "config.h"
+#import "ObjCPlugin.h"
+
+#import <WebKit/WebKit.h>
+#import <objc/objc-runtime.h>
+
+// === NSObject category to expose almost everything to JavaScript ===
+
+// Warning: this class introduces huge security weaknesses, and should only be used
+// for testing inside of DumpRenderTree, and only with trusted code. By default, it has
+// the same restrictive behavior as the standard WebKit setup. However, scripts can use the
+// plugin's removeBridgeRestrictions: method to open up almost total access to the Cocoa
+// frameworks.
+
+static BOOL _allowsScriptsFullAccess = NO;
+
+@interface NSObject (ObjCScriptAccess)
+
++ (void)setAllowsScriptsFullAccess:(BOOL)value;
++ (BOOL)allowsScriptsFullAccess;
+
+@end
+
+@implementation NSObject (ObjCScriptAccess)
+
++ (void)setAllowsScriptsFullAccess:(BOOL)value
+{
+ _allowsScriptsFullAccess = value;
+}
+
++ (BOOL)allowsScriptsFullAccess
+{
+ return _allowsScriptsFullAccess;
+}
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector
+{
+ return !_allowsScriptsFullAccess;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)selector
+{
+ return nil;
+}
+
+@end
+
+@interface JSObjC : NSObject {
+}
+
+// expose some useful objc functions to the scripting environment
+- (id)lookUpClass:(NSString *)name;
+- (void)log:(NSString *)message;
+- (id)retainObject:(id)obj;
+- (id)classOfObject:(id)obj;
+- (NSString *)classNameOfObject:(id)obj;
+
+@end
+
+@implementation JSObjC
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector
+{
+ return NO;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)selector
+{
+ return nil;
+}
+
+- (id)invokeDefaultMethodWithArguments:(NSArray *)args
+{
+ // this is a useful shortcut for accessing objective-c classes from the scripting
+ // environment, e.g. 'var myObject = objc("NSObject").alloc().init();'
+ if ([args count] == 1)
+ return [self lookUpClass:[args objectAtIndex:0]];
+ return nil;
+}
+
+- (id)lookUpClass:(NSString *)name
+{
+ return NSClassFromString(name);
+}
+
+- (void)log:(NSString *)message
+{
+ NSLog(@"%@", message);
+}
+
+- (id)retainObject:(id)obj
+{
+ return [obj retain];
+}
+
+- (id)classOfObject:(id)obj
+{
+ return (id)[obj class];
+}
+
+- (NSString *)classNameOfObject:(id)obj
+{
+ return [obj className];
+}
+
+@end
+
+@implementation ObjCPlugin
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
+{
+ if (aSelector == @selector(removeBridgeRestrictions:))
+ return NO;
+
+ if (aSelector == @selector(echo:))
+ return NO;
+
+ if (aSelector == @selector(throwIfArgumentIsNotHello:))
+ return NO;
+
+ return YES;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)aSelector
+{
+ if (aSelector == @selector(echo:))
+ return @"echo";
+
+ if (aSelector == @selector(throwIfArgumentIsNotHello:))
+ return @"throwIfArgumentIsNotHello";
+
+ return nil;
+}
+
++ (NSString *)webScriptNameForKey:(const char *)key
+{
+ if (strcmp(key, "throwOnDealloc") == 0)
+ return @"throwOnDealloc";
+
+ return nil;
+}
+
++ (BOOL)isKeyExcludedFromWebScript:(const char *)key
+{
+ if (strcmp(key, "throwOnDealloc") == 0)
+ return NO;
+
+ return YES;
+}
+
+- (void)removeBridgeRestrictions:(id)container
+{
+ // let scripts invoke any selector
+ [NSObject setAllowsScriptsFullAccess:YES];
+
+ // store a JSObjC instance into the provided container
+ JSObjC *objc = [[JSObjC alloc] init];
+ [container setValue:objc forKey:@"objc"];
+ [objc release];
+}
+
+- (id)echo:(id)obj
+{
+ return obj;
+}
+
+- (void)throwIfArgumentIsNotHello:(NSString *)str
+{
+ if (![str isEqualToString:@"Hello"])
+ [WebScriptObject throwException:[NSString stringWithFormat:@"%@ != Hello", str]];
+}
+
+- (void)dealloc
+{
+ if (throwOnDealloc)
+ [WebScriptObject throwException:@"Throwing exception on dealloc of ObjCPlugin"];
+
+ [super dealloc];
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/ObjCPluginFunction.h b/Tools/DumpRenderTree/mac/ObjCPluginFunction.h
new file mode 100644
index 000000000..1e81b21f4
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ObjCPluginFunction.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+*/
+
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface ObjCPluginFunction : NSObject
+{
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/ObjCPluginFunction.m b/Tools/DumpRenderTree/mac/ObjCPluginFunction.m
new file mode 100644
index 000000000..5bf3617fc
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ObjCPluginFunction.m
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+*/
+
+#import "config.h"
+#import "ObjCPluginFunction.h"
+
+
+@implementation ObjCPluginFunction
+
+- (id)invokeDefaultMethodWithArguments:(NSArray *)args
+{
+ return @"test";
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c
new file mode 100644
index 000000000..35f051c14
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/sysctl.h>
+
+int processIsCrashing(int pid)
+{
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
+ struct kinfo_proc info;
+ size_t bufferSize = sizeof(info);
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &info, &bufferSize, 0, 0)) {
+ perror("sysctl");
+ return 0;
+ }
+
+ struct extern_proc proc = info.kp_proc;
+
+ // The process is crashing if it is waiting to exit, is not a zombie, and has a non-zero exit code.
+ return proc.p_stat != SZOMB && (proc.p_flag & P_WEXIT) && proc.p_xstat;
+}
diff --git a/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm
new file mode 100644
index 000000000..7b4ea34e5
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm
@@ -0,0 +1,54 @@
+# This file was automatically generated by SWIG
+package DumpRenderTreeSupport;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+package DumpRenderTreeSupportc;
+bootstrap DumpRenderTreeSupport;
+package DumpRenderTreeSupport;
+@EXPORT = qw( );
+
+# ---------- BASE METHODS -------------
+
+package DumpRenderTreeSupport;
+
+sub TIEHASH {
+ my ($classname,$obj) = @_;
+ return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+ my ($self,$field) = @_;
+ my $member_func = "swig_${field}_get";
+ $self->$member_func();
+}
+
+sub STORE {
+ my ($self,$field,$newval) = @_;
+ my $member_func = "swig_${field}_set";
+ $self->$member_func($newval);
+}
+
+sub this {
+ my $ptr = shift;
+ return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package DumpRenderTreeSupport;
+
+*processIsCrashing = *DumpRenderTreeSupportc::processIsCrashing;
+
+# ------- VARIABLE STUBS --------
+
+package DumpRenderTreeSupport;
+
+1;
diff --git a/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c
new file mode 100644
index 000000000..f73498934
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c
@@ -0,0 +1,1167 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.24
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+
+#ifndef SWIG_TEMPLATE_DISAMBIGUATOR
+# if defined(__SUNPRO_CC)
+# define SWIG_TEMPLATE_DISAMBIGUATOR template
+# else
+# define SWIG_TEMPLATE_DISAMBIGUATOR
+# endif
+#endif
+
+/***********************************************************************
+ * swigrun.swg
+ *
+ * This file contains generic CAPI SWIG runtime support for pointer
+ * type checking.
+ *
+ ************************************************************************/
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+ or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "1"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+#define SWIG_QUOTE_STRING(x) #x
+#define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+#define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+#define SWIG_TYPE_TABLE_NAME
+#endif
+
+#include <string.h>
+
+#ifndef SWIGINLINE
+#if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+# define SWIGINLINE inline
+#else
+# define SWIGINLINE
+#endif
+#endif
+
+/*
+ You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+ creating a static or dynamic library from the swig runtime code.
+ In 99.9% of the cases, swig just needs to declare them as 'static'.
+
+ But only do this if is strictly necessary, ie, if you have problems
+ with your compiler or so.
+*/
+#ifndef SWIGRUNTIME
+#define SWIGRUNTIME static
+#endif
+#ifndef SWIGRUNTIMEINLINE
+#define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+typedef struct swig_type_info {
+ const char *name;
+ swig_converter_func converter;
+ const char *str;
+ void *clientdata;
+ swig_dycast_func dcast;
+ struct swig_type_info *next;
+ struct swig_type_info *prev;
+} swig_type_info;
+
+/*
+ Compare two type names skipping the space characters, therefore
+ "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+ Return 0 when the two name types are equivalent, as in
+ strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+ const char *f2, const char *l2) {
+ for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+ while ((*f1 == ' ') && (f1 != l1)) ++f1;
+ while ((*f2 == ' ') && (f2 != l2)) ++f2;
+ if (*f1 != *f2) return *f1 - *f2;
+ }
+ return (l1 - f1) - (l2 - f2);
+}
+
+/*
+ Check type equivalence in a name list like <name1>|<name2>|...
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+ int equiv = 0;
+ const char* te = tb + strlen(tb);
+ const char* ne = nb;
+ while (!equiv && *ne) {
+ for (nb = ne; *ne; ++ne) {
+ if (*ne == '|') break;
+ }
+ equiv = SWIG_TypeNameComp(nb, ne, tb, te) == 0;
+ if (*ne) ++ne;
+ }
+ return equiv;
+}
+
+/*
+ Register a type mapping with the type-checking
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeRegisterTL(swig_type_info **tl, swig_type_info *ti) {
+ swig_type_info *tc, *head, *ret, *next;
+ /* Check to see if this type has already been registered */
+ tc = *tl;
+ while (tc) {
+ /* check simple type equivalence */
+ int typeequiv = (strcmp(tc->name, ti->name) == 0);
+ /* check full type equivalence, resolving typedefs */
+ if (!typeequiv) {
+ /* only if tc is not a typedef (no '|' on it) */
+ if (tc->str && ti->str && !strstr(tc->str,"|")) {
+ typeequiv = SWIG_TypeEquiv(ti->str,tc->str);
+ }
+ }
+ if (typeequiv) {
+ /* Already exists in the table. Just add additional types to the list */
+ if (ti->clientdata) tc->clientdata = ti->clientdata;
+ head = tc;
+ next = tc->next;
+ goto l1;
+ }
+ tc = tc->prev;
+ }
+ head = ti;
+ next = 0;
+
+ /* Place in list */
+ ti->prev = *tl;
+ *tl = ti;
+
+ /* Build linked lists */
+ l1:
+ ret = head;
+ tc = ti + 1;
+ /* Patch up the rest of the links */
+ while (tc->name) {
+ head->next = tc;
+ tc->prev = head;
+ head = tc;
+ tc++;
+ }
+ if (next) next->prev = head;
+ head->next = next;
+
+ return ret;
+}
+
+/*
+ Check the typename
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+ swig_type_info *s;
+ if (!ty) return 0; /* Void pointer */
+ s = ty->next; /* First element always just a name */
+ do {
+ if (strcmp(s->name,c) == 0) {
+ if (s == ty->next) return s;
+ /* Move s to the top of the linked list */
+ s->prev->next = s->next;
+ if (s->next) {
+ s->next->prev = s->prev;
+ }
+ /* Insert s as second element in the list */
+ s->next = ty->next;
+ if (ty->next) ty->next->prev = s;
+ ty->next = s;
+ s->prev = ty;
+ return s;
+ }
+ s = s->next;
+ } while (s && (s != ty->next));
+ return 0;
+}
+
+/*
+ Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_type_info *ty, void *ptr) {
+ return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/*
+ Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+ swig_type_info *lastty = ty;
+ if (!ty || !ty->dcast) return ty;
+ while (ty && (ty->dcast)) {
+ ty = (*ty->dcast)(ptr);
+ if (ty) lastty = ty;
+ }
+ return lastty;
+}
+
+/*
+ Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+ return ty->name;
+}
+
+/*
+ Return the pretty name associated with this type,
+ that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+ /* The "str" field contains the equivalent pretty names of the
+ type, separated by vertical-bar characters. We choose
+ to print the last name, as it is often (?) the most
+ specific. */
+ if (type->str != NULL) {
+ const char *last_name = type->str;
+ const char *s;
+ for (s = type->str; *s; s++)
+ if (*s == '|') last_name = s+1;
+ return last_name;
+ }
+ else
+ return type->name;
+}
+
+/*
+ Search for a swig_type_info structure
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryTL(swig_type_info *tl, const char *name) {
+ swig_type_info *ty = tl;
+ while (ty) {
+ if (ty->str && (SWIG_TypeEquiv(ty->str,name))) return ty;
+ if (ty->name && (strcmp(name,ty->name) == 0)) return ty;
+ ty = ty->prev;
+ }
+ return 0;
+}
+
+/*
+ Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientDataTL(swig_type_info *tl, swig_type_info *ti, void *clientdata) {
+ swig_type_info *tc, *equiv;
+ if (ti->clientdata) return;
+ /* if (ti->clientdata == clientdata) return; */
+ ti->clientdata = clientdata;
+ equiv = ti->next;
+ while (equiv) {
+ if (!equiv->converter) {
+ tc = tl;
+ while (tc) {
+ if ((strcmp(tc->name, equiv->name) == 0))
+ SWIG_TypeClientDataTL(tl,tc,clientdata);
+ tc = tc->prev;
+ }
+ }
+ equiv = equiv->next;
+ }
+}
+
+/*
+ Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+ static char hex[17] = "0123456789abcdef";
+ unsigned char *u = (unsigned char *) ptr;
+ const unsigned char *eu = u + sz;
+ register unsigned char uu;
+ for (; u != eu; ++u) {
+ uu = *u;
+ *(c++) = hex[(uu & 0xf0) >> 4];
+ *(c++) = hex[uu & 0xf];
+ }
+ return c;
+}
+
+/*
+ Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+ register unsigned char *u = (unsigned char *) ptr;
+ register const unsigned char *eu = u + sz;
+ for (; u != eu; ++u) {
+ register int d = *(c++);
+ register unsigned char uu = 0;
+ if ((d >= '0') && (d <= '9'))
+ uu = ((d - '0') << 4);
+ else if ((d >= 'a') && (d <= 'f'))
+ uu = ((d - ('a'-10)) << 4);
+ else
+ return (char *) 0;
+ d = *(c++);
+ if ((d >= '0') && (d <= '9'))
+ uu |= (d - '0');
+ else if ((d >= 'a') && (d <= 'f'))
+ uu |= (d - ('a'-10));
+ else
+ return (char *) 0;
+ *u = uu;
+ }
+ return c;
+}
+
+/*
+ This function will propagate the clientdata field of type to any new
+ swig_type_info structures that have been added into the list of
+ equivalent types. It is like calling SWIG_TypeClientData(type,
+ clientdata) a second time.
+*/
+SWIGRUNTIME void
+SWIG_PropagateClientDataTL(swig_type_info *tl, swig_type_info *type) {
+ swig_type_info *equiv = type->next;
+ swig_type_info *tc;
+ if (!type->clientdata) return;
+ while (equiv) {
+ if (!equiv->converter) {
+ tc = tl;
+ while (tc) {
+ if ((strcmp(tc->name, equiv->name) == 0) && !tc->clientdata)
+ SWIG_TypeClientDataTL(tl,tc, type->clientdata);
+ tc = tc->prev;
+ }
+ }
+ equiv = equiv->next;
+ }
+}
+
+/*
+ Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+ char *r = buff;
+ if ((2*sizeof(void *) + 2) > bsz) return 0;
+ *(r++) = '_';
+ r = SWIG_PackData(r,&ptr,sizeof(void *));
+ if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+ strcpy(r,name);
+ return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+ if (*c != '_') {
+ if (strcmp(c,"NULL") == 0) {
+ *ptr = (void *) 0;
+ return name;
+ } else {
+ return 0;
+ }
+ }
+ return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+ char *r = buff;
+ size_t lname = (name ? strlen(name) : 0);
+ if ((2*sz + 2 + lname) > bsz) return 0;
+ *(r++) = '_';
+ r = SWIG_PackData(r,ptr,sz);
+ if (lname) {
+ strncpy(r,name,lname+1);
+ } else {
+ *r = 0;
+ }
+ return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+ if (*c != '_') {
+ if (strcmp(c,"NULL") == 0) {
+ memset(ptr,0,sz);
+ return name;
+ } else {
+ return 0;
+ }
+ }
+ return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/***********************************************************************
+ * common.swg
+ *
+ * This file contains generic SWIG runtime support for pointer
+ * type checking as well as a few commonly used macros to control
+ * external linkage.
+ *
+ * Author : David Beazley (beazley@cs.uchicago.edu)
+ *
+ * Copyright (c) 1999-2000, The University of Chicago
+ *
+ * This file may be freely redistributed without license or fee provided
+ * this copyright message remains intact.
+ ************************************************************************/
+
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# if !defined(STATIC_LINKED)
+# define SWIGEXPORT(a) __declspec(dllexport) a
+# else
+# define SWIGEXPORT(a) a
+# endif
+#else
+# define SWIGEXPORT(a) a
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*************************************************************************/
+
+
+/* The static type info list */
+
+static swig_type_info *swig_type_list = 0;
+static swig_type_info **swig_type_list_handle = &swig_type_list;
+
+
+/* Register a type mapping with the type-checking */
+static swig_type_info *
+SWIG_TypeRegister(swig_type_info *ti) {
+ return SWIG_TypeRegisterTL(swig_type_list_handle, ti);
+}
+
+/* Search for a swig_type_info structure */
+static swig_type_info *
+SWIG_TypeQuery(const char *name) {
+ return SWIG_TypeQueryTL(*swig_type_list_handle, name);
+}
+
+/* Set the clientdata field for a type */
+static void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+ SWIG_TypeClientDataTL(*swig_type_list_handle, ti, clientdata);
+}
+
+/* This function will propagate the clientdata field of type to
+* any new swig_type_info structures that have been added into the list
+* of equivalent types. It is like calling
+* SWIG_TypeClientData(type, clientdata) a second time.
+*/
+static void
+SWIG_PropagateClientData(swig_type_info *type) {
+ SWIG_PropagateClientDataTL(*swig_type_list_handle, type);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* ---------------------------------------------------------------------- -*- c -*-
+ * perl5.swg
+ *
+ * Perl5 runtime library
+ * $Header: /cvsroot/swig/SWIG/Lib/perl5/perlrun.swg,v 1.20 2004/11/29 23:13:57 wuzzeb Exp $
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPERL
+#define SWIGPERL5
+#ifdef __cplusplus
+/* Needed on some windows machines---since MS plays funny games with the header files under C++ */
+#include <math.h>
+#include <stdlib.h>
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+/* Get rid of free and malloc defined by perl */
+#undef free
+#undef malloc
+
+#ifndef pTHX_
+#define pTHX_
+#endif
+
+#include <string.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* Macro to call an XS function */
+
+#ifdef PERL_OBJECT
+# define SWIG_CALLXS(_name) _name(cv,pPerl)
+#else
+# ifndef MULTIPLICITY
+# define SWIG_CALLXS(_name) _name(cv)
+# else
+# define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv)
+# endif
+#endif
+
+/* Contract support */
+
+#define SWIG_contract_assert(expr,msg) if (!(expr)) { SWIG_croak(msg); } else
+
+/* Note: SwigMagicFuncHack is a typedef used to get the C++ compiler to just shut up already */
+
+#ifdef PERL_OBJECT
+#define MAGIC_PPERL CPerlObj *pPerl = (CPerlObj *) this;
+typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (CPerlObj::*SwigMagicFuncHack)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+#define SWIGCLASS_STATIC
+#else
+#define MAGIC_PPERL
+#define SWIGCLASS_STATIC static
+#ifndef MULTIPLICITY
+#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b)
+typedef int (*SwigMagicFunc)(SV *, MAGIC *);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFuncHack)(SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+
+#else
+#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b)
+typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int (*SwigMagicFuncHack)(struct interpreter *, SV *, MAGIC *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif
+
+#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE)
+#define PerlIO_exportFILE(fh,fl) (FILE*)(fh)
+#endif
+
+/* Modifications for newer Perl 5.005 releases */
+
+#if !defined(PERL_REVISION) || ((PERL_REVISION >= 5) && ((PERL_VERSION < 5) || ((PERL_VERSION == 5) && (PERL_SUBVERSION < 50))))
+# ifndef PL_sv_yes
+# define PL_sv_yes sv_yes
+# endif
+# ifndef PL_sv_undef
+# define PL_sv_undef sv_undef
+# endif
+# ifndef PL_na
+# define PL_na na
+# endif
+#endif
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_OWNER 1
+#define SWIG_SHADOW 2
+
+/* Common SWIG API */
+
+#ifdef PERL_OBJECT
+# define SWIG_ConvertPtr(obj, pp, type, flags) \
+ SWIG_Perl_ConvertPtr(pPerl, obj, pp, type, flags)
+# define SWIG_NewPointerObj(p, type, flags) \
+ SWIG_Perl_NewPointerObj(pPerl, p, type, flags)
+# define SWIG_MakePackedObj(sv, p, s, type) \
+ SWIG_Perl_MakePackedObj(pPerl, sv, p, s, type)
+# define SWIG_ConvertPacked(obj, p, s, type, flags) \
+ SWIG_Perl_ConvertPacked(pPerl, obj, p, s, type, flags)
+
+#else
+# define SWIG_ConvertPtr(obj, pp, type, flags) \
+ SWIG_Perl_ConvertPtr(obj, pp, type, flags)
+# define SWIG_NewPointerObj(p, type, flags) \
+ SWIG_Perl_NewPointerObj(p, type, flags)
+# define SWIG_MakePackedObj(sv, p, s, type) \
+ SWIG_Perl_MakePackedObj(sv, p, s, type )
+# define SWIG_ConvertPacked(obj, p, s, type, flags) \
+ SWIG_Perl_ConvertPacked(obj, p, s, type, flags)
+#endif
+
+/* Perl-specific API */
+#ifdef PERL_OBJECT
+# define SWIG_MakePtr(sv, ptr, type, flags) \
+ SWIG_Perl_MakePtr(pPerl, sv, ptr, type, flags)
+# define SWIG_SetError(str) \
+ SWIG_Perl_SetError(pPerl, str)
+#else
+# define SWIG_MakePtr(sv, ptr, type, flags) \
+ SWIG_Perl_MakePtr(sv, ptr, type, flags)
+# define SWIG_SetError(str) \
+ SWIG_Perl_SetError(str)
+# define SWIG_SetErrorSV(str) \
+ SWIG_Perl_SetErrorSV(str)
+#endif
+
+#define SWIG_SetErrorf SWIG_Perl_SetErrorf
+
+
+#ifdef PERL_OBJECT
+# define SWIG_MAYBE_PERL_OBJECT CPerlObj *pPerl,
+#else
+# define SWIG_MAYBE_PERL_OBJECT
+#endif
+
+static swig_type_info **
+SWIG_Perl_GetTypeListHandle() {
+ static void *type_pointer = (void *)0;
+ SV *pointer;
+
+ /* first check if pointer already created */
+ if (!type_pointer) {
+ pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE);
+ if (pointer && SvOK(pointer)) {
+ type_pointer = INT2PTR(swig_type_info **, SvIV(pointer));
+ }
+ }
+
+ return (swig_type_info **) type_pointer;
+}
+
+/*
+ Search for a swig_type_info structure
+ */
+SWIGRUNTIMEINLINE swig_type_info *
+SWIG_Perl_GetTypeList() {
+ swig_type_info **tlh = SWIG_Perl_GetTypeListHandle();
+ return tlh ? *tlh : (swig_type_info*)0;
+}
+
+#define SWIG_Runtime_GetTypeList SWIG_Perl_GetTypeList
+
+static swig_type_info *
+SWIG_Perl_TypeCheckRV(SWIG_MAYBE_PERL_OBJECT SV *rv, swig_type_info *ty) {
+ swig_type_info *s;
+ if (!ty) return 0; /* Void pointer */
+ s = ty->next; /* First element always just a name */
+ do {
+ if (sv_derived_from(rv, (char *) s->name)) {
+ if (s == ty->next) return s;
+ /* Move s to the top of the linked list */
+ s->prev->next = s->next;
+ if (s->next) {
+ s->next->prev = s->prev;
+ }
+ /* Insert s as second element in the list */
+ s->next = ty->next;
+ if (ty->next) ty->next->prev = s;
+ ty->next = s;
+ s->prev = ty;
+ return s;
+ }
+ s = s->next;
+ } while (s && (s != ty->next));
+ return 0;
+}
+
+/* Function for getting a pointer value */
+
+static int
+SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) {
+ swig_type_info *tc;
+ void *voidptr = (void *)0;
+
+ /* If magical, apply more magic */
+ if (SvGMAGICAL(sv))
+ mg_get(sv);
+
+ /* Check to see if this is an object */
+ if (sv_isobject(sv)) {
+ SV *tsv = (SV*) SvRV(sv);
+ IV tmp = 0;
+ if ((SvTYPE(tsv) == SVt_PVHV)) {
+ MAGIC *mg;
+ if (SvMAGICAL(tsv)) {
+ mg = mg_find(tsv,'P');
+ if (mg) {
+ sv = mg->mg_obj;
+ if (sv_isobject(sv)) {
+ tmp = SvIV((SV*)SvRV(sv));
+ }
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ tmp = SvIV((SV*)SvRV(sv));
+ }
+ voidptr = (void *)tmp;
+ if (!_t) {
+ *(ptr) = voidptr;
+ return 0;
+ }
+ } else if (! SvOK(sv)) { /* Check for undef */
+ *(ptr) = (void *) 0;
+ return 0;
+ } else if (SvTYPE(sv) == SVt_RV) { /* Check for NULL pointer */
+ *(ptr) = (void *) 0;
+ if (!SvROK(sv))
+ return 0;
+ else
+ return -1;
+ } else { /* Don't know what it is */
+ *(ptr) = (void *) 0;
+ return -1;
+ }
+ if (_t) {
+ /* Now see if the types match */
+ char *_c = HvNAME(SvSTASH(SvRV(sv)));
+ tc = SWIG_TypeCheck(_c,_t);
+ if (!tc) {
+ *ptr = voidptr;
+ return -1;
+ }
+ *ptr = SWIG_TypeCast(tc,voidptr);
+ return 0;
+ }
+ *ptr = voidptr;
+ return 0;
+}
+
+static void
+SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) {
+ if (ptr && (flags & SWIG_SHADOW)) {
+ SV *self;
+ SV *obj=newSV(0);
+ HV *hash=newHV();
+ HV *stash;
+ sv_setref_pv(obj, (char *) t->name, ptr);
+ stash=SvSTASH(SvRV(obj));
+ if (flags & SWIG_OWNER) {
+ HV *hv;
+ GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+ if (!isGV(gv))
+ gv_init(gv, stash, "OWNER", 5, FALSE);
+ hv=GvHVn(gv);
+ hv_store_ent(hv, obj, newSViv(1), 0);
+ }
+ sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0);
+ SvREFCNT_dec(obj);
+ self=newRV_noinc((SV *)hash);
+ sv_setsv(sv, self);
+ SvREFCNT_dec((SV *)self);
+ sv_bless(sv, stash);
+ }
+ else {
+ sv_setref_pv(sv, (char *) t->name, ptr);
+ }
+}
+
+static SWIGINLINE SV *
+SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+ SV *result = sv_newmortal();
+ SWIG_MakePtr(result, ptr, t, flags);
+ return result;
+}
+
+static void
+ SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) {
+ char result[1024];
+ char *r = result;
+ if ((2*sz + 1 + strlen(type->name)) > 1000) return;
+ *(r++) = '_';
+ r = SWIG_PackData(r,ptr,sz);
+ strcpy(r,type->name);
+ sv_setpv(sv, result);
+}
+
+/* Convert a packed value value */
+static int
+SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty, int flags) {
+ swig_type_info *tc;
+ const char *c = 0;
+
+ if ((!obj) || (!SvOK(obj))) return -1;
+ c = SvPV(obj, PL_na);
+ /* Pointer values must start with leading underscore */
+ if (*c != '_') return -1;
+ c++;
+ c = SWIG_UnpackData(c,ptr,sz);
+ if (ty) {
+ tc = SWIG_TypeCheck(c,ty);
+ if (!tc) return -1;
+ }
+ return 0;
+}
+
+static SWIGINLINE void
+SWIG_Perl_SetError(SWIG_MAYBE_PERL_OBJECT const char *error) {
+ if (error) sv_setpv(perl_get_sv("@", TRUE), error);
+}
+
+static SWIGINLINE void
+SWIG_Perl_SetErrorSV(SWIG_MAYBE_PERL_OBJECT SV *error) {
+ if (error) sv_setsv(perl_get_sv("@", TRUE), error);
+}
+
+static void
+SWIG_Perl_SetErrorf(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ sv_vsetpvfn(perl_get_sv("@", TRUE), fmt, strlen(fmt), &args, Null(SV**), 0, Null(bool*));
+ va_end(args);
+}
+
+/* Macros for low-level exception handling */
+#define SWIG_fail goto fail
+#define SWIG_croak(x) { SWIG_SetError(x); goto fail; }
+#define SWIG_croakSV(x) { SWIG_SetErrorSV(x); goto fail; }
+/* most preprocessors do not support vararg macros :-( */
+/* #define SWIG_croakf(x...) { SWIG_SetErrorf(x); goto fail; } */
+
+
+typedef XS(SwigPerlWrapper);
+typedef SwigPerlWrapper *SwigPerlWrapperPtr;
+
+/* Structure for command table */
+typedef struct {
+ const char *name;
+ SwigPerlWrapperPtr wrapper;
+} swig_command_info;
+
+/* Information for constant table */
+
+#define SWIG_INT 1
+#define SWIG_FLOAT 2
+#define SWIG_STRING 3
+#define SWIG_POINTER 4
+#define SWIG_BINARY 5
+
+/* Constant information structure */
+typedef struct swig_constant_info {
+ int type;
+ const char *name;
+ long lvalue;
+ double dvalue;
+ void *pvalue;
+ swig_type_info **ptype;
+} swig_constant_info;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Structure for variable table */
+typedef struct {
+ const char *name;
+ SwigMagicFunc set;
+ SwigMagicFunc get;
+ swig_type_info **type;
+} swig_variable_info;
+
+/* Magic variable code */
+#ifndef PERL_OBJECT
+#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c)
+ #ifndef MULTIPLICITY
+ static void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) {
+ #else
+ static void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) {
+ #endif
+#else
+# define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c)
+static void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) {
+#endif
+ MAGIC *mg;
+ sv_magic(sv,sv,'U',(char *) name,strlen(name));
+ mg = mg_find(sv,'U');
+ mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL));
+ mg->mg_virtual->svt_get = (SwigMagicFuncHack) get;
+ mg->mg_virtual->svt_set = (SwigMagicFuncHack) set;
+ mg->mg_virtual->svt_len = 0;
+ mg->mg_virtual->svt_clear = 0;
+ mg->mg_virtual->svt_free = 0;
+}
+
+
+
+
+
+
+#ifdef do_open
+ #undef do_open
+#endif
+#ifdef do_close
+ #undef do_close
+#endif
+#ifdef scalar
+ #undef scalar
+#endif
+#ifdef list
+ #undef list
+#endif
+#ifdef apply
+ #undef apply
+#endif
+#ifdef convert
+ #undef convert
+#endif
+#ifdef Error
+ #undef Error
+#endif
+#ifdef form
+ #undef form
+#endif
+#ifdef vform
+ #undef vform
+#endif
+#ifdef LABEL
+ #undef LABEL
+#endif
+#ifdef METHOD
+ #undef METHOD
+#endif
+#ifdef Move
+ #undef Move
+#endif
+#ifdef yylex
+ #undef yylex
+#endif
+#ifdef yyparse
+ #undef yyparse
+#endif
+#ifdef yyerror
+ #undef yyerror
+#endif
+#ifdef invert
+ #undef invert
+#endif
+#ifdef ref
+ #undef ref
+#endif
+#ifdef ENTER
+ #undef ENTER
+#endif
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+static swig_type_info *swig_types[1];
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init boot_DumpRenderTreeSupport
+
+#define SWIG_name "DumpRenderTreeSupportc::boot_DumpRenderTreeSupport"
+#define SWIG_prefix "DumpRenderTreeSupportc::"
+
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifndef PERL_OBJECT
+#ifndef MULTIPLICITY
+SWIGEXPORT(void) SWIG_init (CV* cv);
+#else
+SWIGEXPORT(void) SWIG_init (pTHXo_ CV* cv);
+#endif
+#else
+SWIGEXPORT(void) SWIG_init (CV *cv, CPerlObj *);
+#endif
+
+int processIsCrashing(int);
+#ifdef PERL_OBJECT
+#define MAGIC_CLASS _wrap_DumpRenderTreeSupport_var::
+class _wrap_DumpRenderTreeSupport_var : public CPerlObj {
+public:
+#else
+#define MAGIC_CLASS
+#endif
+SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *sv, MAGIC *mg) {
+ MAGIC_PPERL
+ sv = sv; mg = mg;
+ croak("Value is read-only.");
+ return 0;
+}
+
+
+#ifdef PERL_OBJECT
+};
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+XS(_wrap_processIsCrashing) {
+ {
+ int arg1 ;
+ int result;
+ int argvi = 0;
+ dXSARGS;
+
+ if ((items < 1) || (items > 1)) {
+ SWIG_croak("Usage: processIsCrashing(pid);");
+ }
+ arg1 = (int) SvIV(ST(0));
+ result = (int)processIsCrashing(arg1);
+
+ ST(argvi) = sv_newmortal();
+ sv_setiv(ST(argvi++), (IV) result);
+ XSRETURN(argvi);
+ fail:
+ ;
+ }
+ croak(Nullch);
+}
+
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+
+static swig_type_info *swig_types_initial[] = {
+0
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_constant_info swig_constants[] = {
+{0,0,0,0,0,0}
+};
+#ifdef __cplusplus
+}
+#endif
+static swig_variable_info swig_variables[] = {
+{0,0,0,0}
+};
+static swig_command_info swig_commands[] = {
+{"DumpRenderTreeSupportc::processIsCrashing", _wrap_processIsCrashing},
+{0,0}
+};
+
+
+static void SWIG_Perl_SetTypeListHandle(swig_type_info **handle) {
+ SV *pointer;
+
+ /* create a new pointer */
+ pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE);
+ sv_setiv(pointer, PTR2IV(swig_type_list_handle));
+}
+
+static swig_type_info **
+SWIG_Perl_LookupTypePointer(swig_type_info **type_list_handle) {
+ swig_type_info **type_pointer;
+
+ /* first check if module already created */
+ type_pointer = SWIG_Perl_GetTypeListHandle();
+ if (type_pointer) {
+ return type_pointer;
+ } else {
+ /* create a new module and variable */
+ SWIG_Perl_SetTypeListHandle(type_list_handle);
+ return type_list_handle;
+ }
+}
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+XS(SWIG_init) {
+ dXSARGS;
+ int i;
+ static int _init = 0;
+ if (!_init) {
+ swig_type_list_handle = SWIG_Perl_LookupTypePointer(swig_type_list_handle);
+ for (i = 0; swig_types_initial[i]; i++) {
+ swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]);
+ }
+ _init = 1;
+ }
+
+ /* Install commands */
+ for (i = 0; swig_commands[i].name; i++) {
+ newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__);
+ }
+
+ /* Install variables */
+ for (i = 0; swig_variables[i].name; i++) {
+ SV *sv;
+ sv = perl_get_sv((char*) swig_variables[i].name, TRUE | 0x2);
+ if (swig_variables[i].type) {
+ SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0);
+ } else {
+ sv_setiv(sv,(IV) 0);
+ }
+ swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get);
+ }
+
+ /* Install constant */
+ for (i = 0; swig_constants[i].type; i++) {
+ SV *sv;
+ sv = perl_get_sv((char*)swig_constants[i].name, TRUE | 0x2);
+ switch(swig_constants[i].type) {
+ case SWIG_INT:
+ sv_setiv(sv, (IV) swig_constants[i].lvalue);
+ break;
+ case SWIG_FLOAT:
+ sv_setnv(sv, (double) swig_constants[i].dvalue);
+ break;
+ case SWIG_STRING:
+ sv_setpv(sv, (char *) swig_constants[i].pvalue);
+ break;
+ case SWIG_POINTER:
+ SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0);
+ break;
+ case SWIG_BINARY:
+ SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype));
+ break;
+ default:
+ break;
+ }
+ SvREADONLY_on(sv);
+ }
+
+ ST(0) = &PL_sv_yes;
+ XSRETURN(1);
+}
+
diff --git a/Tools/DumpRenderTree/mac/PerlSupport/Makefile b/Tools/DumpRenderTree/mac/PerlSupport/Makefile
new file mode 100644
index 000000000..f7808dc3c
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PerlSupport/Makefile
@@ -0,0 +1,82 @@
+# Copyright (C) 2009 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+CONFIGURATION_BUILD_DIR ?= .
+OUTPUT_DIR=$(CONFIGURATION_BUILD_DIR)
+
+WRAPPER_DIR=$(OUTPUT_DIR)/DerivedSources/DumpRenderTree
+WRAPPER=$(WRAPPER_DIR)/DumpRenderTreeSupport_wrap.c
+PERL_MODULE=$(OUTPUT_DIR)/DumpRenderTreeSupport.pm
+DYLIB=$(OUTPUT_DIR)/DumpRenderTreeSupport.dylib
+DUMPRENDERTREE=$(OUTPUT_DIR)/DumpRenderTree
+PERL=/usr/bin/perl
+
+OSX_VERSION = $(shell sw_vers -productVersion | cut -d. -f 2)
+ifeq "$(OSX_VERSION)" "5"
+GENERATE_WRAPPER = YES
+endif
+ifeq "$(OSX_VERSION)" "6"
+GENERATE_WRAPPER = NO
+endif
+
+ifeq "$(GENERATE_WRAPPER)" "YES"
+
+SWIG=/usr/bin/swig
+
+all: $(DYLIB) $(PERL_MODULE)
+
+$(WRAPPER) $(PERL_MODULE): DumpRenderTreeSupport.c $(DUMPRENDERTREE)
+ mkdir -p $(WRAPPER_DIR)
+ $(SWIG) -o $(WRAPPER) -outdir $(OUTPUT_DIR) -perl -module DumpRenderTreeSupport $<
+
+
+else
+
+
+all: $(DYLIB) $(PERL_MODULE)
+
+$(WRAPPER): DumpRenderTreeSupport_wrapPregenerated.c $(DUMPRENDERTREE)
+ mkdir -p $(WRAPPER_DIR)
+ cp DumpRenderTreeSupport_wrapPregenerated.c $(WRAPPER)
+
+$(PERL_MODULE): DumpRenderTreeSupportPregenerated.pm $(DUMPRENDERTREE)
+ cp DumpRenderTreeSupportPregenerated.pm $(PERL_MODULE)
+
+
+endif
+
+$(DYLIB): DumpRenderTreeSupport.c $(WRAPPER)
+ gcc -g -dynamiclib -o $(DYLIB) `$(PERL) -MExtUtils::Embed -eperl_inc` `$(PERL) -MExtUtils::Embed -e'my $$opts = ldopts(0); $$opts =~ s/-arch [^ ]*( |$$)//g; print $$opts, " -arch ", join(" -arch ", split(" ",$$ENV{ARCHS}))'` $^
+
+clean:
+ rm -f $(WRAPPER) $(PERL_MODULE) $(DYLIB)
+
+installhdrs installsrc:
+
+INSTALL_LOCATION=$(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)
+
+install: all
+ mkdir -p $(INSTALL_LOCATION)
+ cp $(DYLIB) $(INSTALL_LOCATION)/DumpRenderTreeSupport.dylib
+ cp $(PERL_MODULE) $(INSTALL_LOCATION)/DumpRenderTreeSupport.pm
+
diff --git a/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm b/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm
new file mode 100644
index 000000000..3d6fbdd59
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "PixelDumpSupport.h"
+#include "PixelDumpSupportCG.h"
+
+#include "DumpRenderTree.h"
+#include "LayoutTestController.h"
+#include <CoreGraphics/CGBitmapContext.h>
+#include <wtf/Assertions.h>
+#include <wtf/RefPtr.h>
+
+#import <WebKit/WebCoreStatistics.h>
+#import <WebKit/WebDocumentPrivate.h>
+#import <WebKit/WebHTMLViewPrivate.h>
+#import <WebKit/WebKit.h>
+#import <WebKit/WebViewPrivate.h>
+
+
+// To ensure pixel tests consistency, we need to always render in the same colorspace.
+// Unfortunately, because of AppKit / WebKit constraints, we can't render directly in the colorspace of our choice.
+// This implies we have to temporarily change the profile of the main display to the colorspace we want to render into.
+// We also need to make sure the CGBitmapContext we return is in that same colorspace.
+
+#define PROFILE_PATH "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc" // FIXME: This cannot be more than CS_MAX_PATH (256 characters)
+
+static CMProfileLocation sInitialProfileLocation; // The locType field is initialized to 0 which is the same as cmNoProfileBase
+
+void restoreMainDisplayColorProfile(int ignored)
+{
+ // This is used as a signal handler, and thus the calls into ColorSync are unsafe
+ // But we might as well try to restore the user's color profile, we're going down anyway...
+ if (sInitialProfileLocation.locType != cmNoProfileBase) {
+ const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost };
+ int error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &sInitialProfileLocation);
+ if (error)
+ fprintf(stderr, "Failed to restore initial color profile for main display! Open System Preferences > Displays > Color and manually re-select the profile. (Error: %i)\n", error);
+ sInitialProfileLocation.locType = cmNoProfileBase;
+ }
+}
+
+void setupMainDisplayColorProfile()
+{
+ const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost };
+ int error;
+
+ CMProfileRef profile = 0;
+ error = CMGetProfileByAVID((CMDisplayIDType)kCGDirectMainDisplay, &profile);
+ if (!error) {
+ UInt32 size = sizeof(CMProfileLocation);
+ error = NCMGetProfileLocation(profile, &sInitialProfileLocation, &size);
+ CMCloseProfile(profile);
+ }
+ if (error) {
+ fprintf(stderr, "Failed to retrieve current color profile for main display, thus it won't be changed. Many pixel tests may fail as a result. (Error: %i)\n", error);
+ sInitialProfileLocation.locType = cmNoProfileBase;
+ return;
+ }
+
+ CMProfileLocation location;
+ location.locType = cmPathBasedProfile;
+ strcpy(location.u.pathLoc.path, PROFILE_PATH);
+ error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &location);
+ if (error) {
+ fprintf(stderr, "Failed to set color profile for main display! Many pixel tests may fail as a result. (Error: %i)\n", error);
+ sInitialProfileLocation.locType = cmNoProfileBase;
+ return;
+ }
+
+ // Other signals are handled in installSignalHandlers() which also calls restoreMainDisplayColorProfile()
+ signal(SIGINT, restoreMainDisplayColorProfile);
+ signal(SIGHUP, restoreMainDisplayColorProfile);
+ signal(SIGTERM, restoreMainDisplayColorProfile);
+}
+
+static PassRefPtr<BitmapContext> createBitmapContext(size_t pixelsWide, size_t pixelsHigh, size_t& rowBytes, void*& buffer)
+{
+ rowBytes = (4 * pixelsWide + 63) & ~63; // Use a multiple of 64 bytes to improve CG performance
+
+ buffer = calloc(pixelsHigh, rowBytes);
+ if (!buffer)
+ return 0;
+
+ static CGColorSpaceRef colorSpace = 0;
+ if (!colorSpace) {
+ CMProfileLocation location;
+ location.locType = cmPathBasedProfile;
+ strcpy(location.u.pathLoc.path, PROFILE_PATH);
+ CMProfileRef profile;
+ if (CMOpenProfile(&profile, &location) == noErr) {
+ colorSpace = CGColorSpaceCreateWithPlatformColorSpace(profile);
+ CMCloseProfile(profile);
+ }
+ }
+
+ CGContextRef context = CGBitmapContextCreate(buffer, pixelsWide, pixelsHigh, 8, rowBytes, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); // Use ARGB8 on PPC or BGRA8 on X86 to improve CG performance
+ if (!context) {
+ free(buffer);
+ return 0;
+ }
+
+ return BitmapContext::createByAdoptingBitmapAndContext(buffer, context);
+}
+
+static void paintRepaintRectOverlay(WebView* webView, CGContextRef context)
+{
+ CGRect viewRect = NSRectToCGRect([webView bounds]);
+
+ CGContextSaveGState(context);
+
+ // Using a transparency layer is easier than futzing with clipping.
+ CGContextBeginTransparencyLayer(context, 0);
+
+ // Flip the context.
+ CGContextScaleCTM(context, 1, -1);
+ CGContextTranslateCTM(context, 0, -viewRect.size.height);
+
+ CGContextSetRGBFillColor(context, 0, 0, 0, static_cast<CGFloat>(0.66));
+ CGContextFillRect(context, viewRect);
+
+ NSArray *repaintRects = [webView trackedRepaintRects];
+ if (repaintRects) {
+
+ for (NSValue *value in repaintRects) {
+ CGRect currRect = NSRectToCGRect([value rectValue]);
+ CGContextClearRect(context, currRect);
+ }
+ }
+
+ CGContextEndTransparencyLayer(context);
+ CGContextRestoreGState(context);
+}
+
+PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect)
+{
+ WebView* view = [mainFrame webView];
+
+ // If the WebHTMLView uses accelerated compositing, we need for force the on-screen capture path
+ // and also force Core Animation to start its animations with -display since the DRT window has autodisplay disabled.
+ if ([view _isUsingAcceleratedCompositing])
+ onscreen = YES;
+
+ float deviceScaleFactor = [view _backingScaleFactor];
+ NSSize webViewSize = [view frame].size;
+ size_t pixelsWide = static_cast<size_t>(webViewSize.width * deviceScaleFactor);
+ size_t pixelsHigh = static_cast<size_t>(webViewSize.height * deviceScaleFactor);
+ size_t rowBytes = 0;
+ void* buffer = 0;
+ RefPtr<BitmapContext> bitmapContext = createBitmapContext(pixelsWide, pixelsHigh, rowBytes, buffer);
+ if (!bitmapContext)
+ return 0;
+ CGContextRef context = bitmapContext->cgContext();
+ CGContextScaleCTM(context, deviceScaleFactor, deviceScaleFactor);
+
+ NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO];
+ ASSERT(nsContext);
+
+ if (incrementalRepaint) {
+ if (sweepHorizontally) {
+ for (NSRect column = NSMakeRect(0, 0, 1, webViewSize.height); column.origin.x < webViewSize.width; column.origin.x++)
+ [view displayRectIgnoringOpacity:column inContext:nsContext];
+ } else {
+ for (NSRect line = NSMakeRect(0, 0, webViewSize.width, 1); line.origin.y < webViewSize.height; line.origin.y++)
+ [view displayRectIgnoringOpacity:line inContext:nsContext];
+ }
+ } else {
+ if (deviceScaleFactor != 1) {
+ // Call displayRectIgnoringOpacity for HiDPI tests since it ensures we paint directly into the context
+ // that we have appropriately sized and scaled.
+ [view displayRectIgnoringOpacity:[view bounds] inContext:nsContext];
+ if ([view isTrackingRepaints])
+ paintRepaintRectOverlay(view, context);
+ } else if (onscreen) {
+ // displayIfNeeded does not update the CA layers if the layer-hosting view was not marked as needing display, so
+ // we're at the mercy of CA's display-link callback to update layers in time. So we need to force a display of the view
+ // to get AppKit to update the CA layers synchronously.
+ // FIXME: this will break repaint testing if we have compositing in repaint tests
+ // (displayWebView() painted gray over the webview, but we'll be making everything repaint again).
+ [view display];
+
+ // Ask the window server to provide us a composited version of the *real* window content including surfaces (i.e. OpenGL content)
+ // Note that the returned image might differ very slightly from the window backing because of dithering artifacts in the window server compositor
+ CGImageRef image = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [[view window] windowNumber], kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque);
+ CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
+ CGImageRelease(image);
+
+ if ([view isTrackingRepaints])
+ paintRepaintRectOverlay(view, context);
+ } else {
+ // Make sure the view has been painted.
+ [view displayIfNeeded];
+
+ // Grab directly the contents of the window backing buffer (this ignores any surfaces on the window)
+ // FIXME: This path is suboptimal: data is read from window backing store, converted to RGB8 then drawn again into an RGBA8 bitmap
+ [view lockFocus];
+ NSBitmapImageRep *imageRep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:[view frame]] autorelease];
+ [view unlockFocus];
+
+ RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext];
+ [NSGraphicsContext setCurrentContext:nsContext];
+ [imageRep draw];
+
+ if ([view isTrackingRepaints])
+ paintRepaintRectOverlay(view, context);
+
+ [NSGraphicsContext setCurrentContext:savedContext.get()];
+ }
+ }
+
+ if (drawSelectionRect) {
+ NSView *documentView = [[mainFrame frameView] documentView];
+ ASSERT([documentView conformsToProtocol:@protocol(WebDocumentSelection)]);
+ NSRect rect = [documentView convertRect:[(id <WebDocumentSelection>)documentView selectionRect] fromView:nil];
+ CGContextSaveGState(context);
+ CGContextSetLineWidth(context, 1.0);
+ CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
+ CGContextStrokeRect(context, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height));
+ CGContextRestoreGState(context);
+ }
+
+ return bitmapContext.release();
+}
+
+PassRefPtr<BitmapContext> createPagedBitmapContext()
+{
+ int pageWidthInPixels = LayoutTestController::maxViewWidth;
+ int pageHeightInPixels = LayoutTestController::maxViewHeight;
+ int numberOfPages = [mainFrame numberOfPages:pageWidthInPixels:pageHeightInPixels];
+ size_t rowBytes = 0;
+ void* buffer = 0;
+
+ RefPtr<BitmapContext> bitmapContext = createBitmapContext(pageWidthInPixels, numberOfPages * (pageHeightInPixels + 1) - 1, rowBytes, buffer);
+ [mainFrame printToCGContext:bitmapContext->cgContext():pageWidthInPixels:pageHeightInPixels];
+ return bitmapContext.release();
+}
diff --git a/Tools/DumpRenderTree/mac/PlainTextController.h b/Tools/DumpRenderTree/mac/PlainTextController.h
new file mode 100644
index 000000000..1488f2fde
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PlainTextController.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+@interface PlainTextController : NSObject
++ (PlainTextController *)sharedPlainTextController;
+@end
diff --git a/Tools/DumpRenderTree/mac/PlainTextController.mm b/Tools/DumpRenderTree/mac/PlainTextController.mm
new file mode 100644
index 000000000..eb89bce4d
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PlainTextController.mm
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "PlainTextController.h"
+
+#import <WebKit/WebKit.h>
+
+@implementation PlainTextController
+
++ (PlainTextController *)sharedPlainTextController
+{
+ static PlainTextController *controller = [[PlainTextController alloc] init];
+ return controller;
+}
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector
+{
+ if (selector == @selector(plainTextForRange:))
+ return NO;
+ return YES;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)selector
+{
+ if (selector == @selector(plainTextForRange:))
+ return @"plainText";
+ return nil;
+}
+
+- (NSString *)plainTextForRange:(DOMRange *)range
+{
+ if (![range isKindOfClass:[DOMRange class]])
+ return nil;
+ return [range text];
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/PolicyDelegate.h b/Tools/DumpRenderTree/mac/PolicyDelegate.h
new file mode 100644
index 000000000..3b954557d
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PolicyDelegate.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+class LayoutTestController;
+
+@interface PolicyDelegate : NSObject {
+ BOOL permissiveDelegate;
+ LayoutTestController* controllerToNotifyDone;
+}
+
+- (void)setPermissive:(BOOL)permissive;
+- (void)setControllerToNotifyDone:(LayoutTestController*)controller;
+
+@end
diff --git a/Tools/DumpRenderTree/mac/PolicyDelegate.mm b/Tools/DumpRenderTree/mac/PolicyDelegate.mm
new file mode 100644
index 000000000..6935ea721
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PolicyDelegate.mm
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "PolicyDelegate.h"
+
+#import "DumpRenderTree.h"
+#import "LayoutTestController.h"
+#import <WebKit/DOMElement.h>
+#import <WebKit/WebPolicyDelegate.h>
+#import <WebKit/WebView.h>
+
+@interface NSURL (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@interface DOMNode (dumpPath)
+- (NSString *)dumpPath;
+@end
+
+@implementation PolicyDelegate
+
+- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation
+ request:(NSURLRequest *)request
+ frame:(WebFrame *)frame
+ decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+ WebNavigationType navType = (WebNavigationType)[[actionInformation objectForKey:WebActionNavigationTypeKey] intValue];
+
+ const char* typeDescription;
+ switch (navType) {
+ case WebNavigationTypeLinkClicked:
+ typeDescription = "link clicked";
+ break;
+ case WebNavigationTypeFormSubmitted:
+ typeDescription = "form submitted";
+ break;
+ case WebNavigationTypeBackForward:
+ typeDescription = "back/forward";
+ break;
+ case WebNavigationTypeReload:
+ typeDescription = "reload";
+ break;
+ case WebNavigationTypeFormResubmitted:
+ typeDescription = "form resubmitted";
+ break;
+ case WebNavigationTypeOther:
+ typeDescription = "other";
+ break;
+ default:
+ typeDescription = "illegal value";
+ }
+
+ NSString *message = [NSString stringWithFormat:@"Policy delegate: attempt to load %@ with navigation type '%s'", [[request URL] _drt_descriptionSuitableForTestResult], typeDescription];
+
+ if (DOMElement *originatingNode = [[actionInformation objectForKey:WebActionElementKey] objectForKey:WebElementDOMNodeKey])
+ message = [message stringByAppendingFormat:@" originating from %@", [originatingNode dumpPath]];
+
+ printf("%s\n", [message UTF8String]);
+
+ if (permissiveDelegate)
+ [listener use];
+ else
+ [listener ignore];
+
+ if (controllerToNotifyDone) {
+ controllerToNotifyDone->notifyDone();
+ controllerToNotifyDone = 0;
+ }
+}
+
+- (void)webView:(WebView *)webView unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame
+{
+ NSString *message = [NSString stringWithFormat:@"Policy delegate: unable to implement policy with error domain '%@', error code %d, in frame '%@'", [error domain], [error code], [frame name]];
+ printf("%s\n", [message UTF8String]);
+}
+
+- (void)setPermissive:(BOOL)permissive
+{
+ permissiveDelegate = permissive;
+}
+
+- (void)setControllerToNotifyDone:(LayoutTestController*)controller
+{
+ controllerToNotifyDone = controller;
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/ResourceLoadDelegate.h b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.h
new file mode 100644
index 000000000..0c4618e93
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface ResourceLoadDelegate : NSObject {
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm
new file mode 100644
index 000000000..5e451f14d
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2007, 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "ResourceLoadDelegate.h"
+
+#import "DumpRenderTree.h"
+#import "LayoutTestController.h"
+#import <WebKit/WebKit.h>
+#import <WebKit/WebTypesInternal.h>
+#import <WebKit/WebDataSourcePrivate.h>
+#import <wtf/Assertions.h>
+
+using namespace std;
+
+@interface NSURL (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@interface NSError (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@interface NSURLResponse (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@interface NSURLRequest (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult;
+@end
+
+@implementation NSError (DRTExtras)
+- (NSString *)_drt_descriptionSuitableForTestResult
+{
+ NSString *str = [NSString stringWithFormat:@"<NSError domain %@, code %d", [self domain], [self code]];
+ NSURL *failingURL;
+
+ if ((failingURL = [[self userInfo] objectForKey:@"NSErrorFailingURLKey"]))
+ str = [str stringByAppendingFormat:@", failing URL \"%@\"", [failingURL _drt_descriptionSuitableForTestResult]];
+
+ str = [str stringByAppendingFormat:@">"];
+
+ return str;
+}
+
+@end
+
+@implementation NSURL (DRTExtras)
+
+- (NSString *)_drt_descriptionSuitableForTestResult
+{
+ if (![self isFileURL])
+ return [self absoluteString];
+
+ WebDataSource *dataSource = [mainFrame dataSource];
+ if (!dataSource)
+ dataSource = [mainFrame provisionalDataSource];
+
+ NSString *basePath = [[[[dataSource request] URL] path] stringByDeletingLastPathComponent];
+ basePath = [basePath stringByAppendingString:@"/"];
+
+ if ([[self path] hasPrefix:basePath])
+ return [[self path] substringFromIndex:[basePath length]];
+ return [self absoluteString];
+}
+
+@end
+
+@implementation NSURLResponse (DRTExtras)
+
+- (NSString *)_drt_descriptionSuitableForTestResult
+{
+ int statusCode = 0;
+ if ([self isKindOfClass:[NSHTTPURLResponse class]])
+ statusCode = [(NSHTTPURLResponse *)self statusCode];
+ return [NSString stringWithFormat:@"<NSURLResponse %@, http status code %i>", [[self URL] _drt_descriptionSuitableForTestResult], statusCode];
+}
+
+@end
+
+@implementation NSURLRequest (DRTExtras)
+
+- (NSString *)_drt_descriptionSuitableForTestResult
+{
+ NSString *httpMethod = [self HTTPMethod];
+ if (!httpMethod)
+ httpMethod = @"(none)";
+ return [NSString stringWithFormat:@"<NSURLRequest URL %@, main document URL %@, http method %@>", [[self URL] _drt_descriptionSuitableForTestResult], [[self mainDocumentURL] _drt_descriptionSuitableForTestResult], httpMethod];
+}
+
+@end
+
+@implementation ResourceLoadDelegate
+
+- (id)webView: (WebView *)wv identifierForInitialRequest: (NSURLRequest *)request fromDataSource: (WebDataSource *)dataSource
+{
+ ASSERT([[dataSource webFrame] dataSource] || [[dataSource webFrame] provisionalDataSource]);
+
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks())
+ return [[request URL] _drt_descriptionSuitableForTestResult];
+
+ return @"<unknown>";
+}
+
+-(NSURLRequest *)webView: (WebView *)wv resource:identifier willSendRequest: (NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
+{
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - willSendRequest %@ redirectResponse %@", identifier, [request _drt_descriptionSuitableForTestResult],
+ [redirectResponse _drt_descriptionSuitableForTestResult]];
+ printf("%s\n", [string UTF8String]);
+ }
+
+ if (!done && !gLayoutTestController->deferMainResourceDataLoad()) {
+ [dataSource _setDeferMainResourceDataLoad:false];
+ }
+
+ if (!done && gLayoutTestController->willSendRequestReturnsNull())
+ return nil;
+
+ if (!done && gLayoutTestController->willSendRequestReturnsNullOnRedirect() && redirectResponse) {
+ printf("Returning null for this redirect\n");
+ return nil;
+ }
+
+ NSURL *url = [request URL];
+ NSString *host = [url host];
+ if (host
+ && (NSOrderedSame == [[url scheme] caseInsensitiveCompare:@"http"] || NSOrderedSame == [[url scheme] caseInsensitiveCompare:@"https"])
+ && NSOrderedSame != [host compare:@"127.0.0.1"]
+ && NSOrderedSame != [host compare:@"255.255.255.255"] // used in some tests that expect to get back an error
+ && NSOrderedSame != [host caseInsensitiveCompare:@"localhost"]) {
+ printf("Blocked access to external URL %s\n", [[url absoluteString] cStringUsingEncoding:NSUTF8StringEncoding]);
+ return nil;
+ }
+
+ if (disallowedURLs && CFSetContainsValue(disallowedURLs, url))
+ return nil;
+
+ NSMutableURLRequest *newRequest = [request mutableCopy];
+ const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders();
+ for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) {
+ NSString *nsHeader = [[NSString alloc] initWithUTF8String:header->c_str()];
+ [newRequest setValue:nil forHTTPHeaderField:nsHeader];
+ [nsHeader release];
+ }
+ const std::string& destination = gLayoutTestController->redirectionDestinationForURL([[url absoluteString] UTF8String]);
+ if (destination.length())
+ [newRequest setURL:[NSURL URLWithString:[NSString stringWithUTF8String:destination.data()]]];
+
+ return [newRequest autorelease];
+}
+
+- (void)webView:(WebView *)wv resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource
+{
+ if (!gLayoutTestController->handlesAuthenticationChallenges()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet", identifier];
+ printf("%s\n", [string UTF8String]);
+
+ [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
+ return;
+ }
+
+ const char* user = gLayoutTestController->authenticationUsername().c_str();
+ NSString *nsUser = [NSString stringWithFormat:@"%s", user ? user : ""];
+
+ const char* password = gLayoutTestController->authenticationPassword().c_str();
+ NSString *nsPassword = [NSString stringWithFormat:@"%s", password ? password : ""];
+
+ NSString *string = [NSString stringWithFormat:@"%@ - didReceiveAuthenticationChallenge - Responding with %@:%@", identifier, nsUser, nsPassword];
+ printf("%s\n", [string UTF8String]);
+
+ [[challenge sender] useCredential:[NSURLCredential credentialWithUser:nsUser password:nsPassword persistence:NSURLCredentialPersistenceForSession]
+ forAuthenticationChallenge:challenge];
+}
+
+- (void)webView:(WebView *)wv resource:(id)identifier didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource
+{
+}
+
+-(void)webView: (WebView *)wv resource:identifier didReceiveResponse: (NSURLResponse *)response fromDataSource:(WebDataSource *)dataSource
+{
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didReceiveResponse %@", identifier, [response _drt_descriptionSuitableForTestResult]];
+ printf("%s\n", [string UTF8String]);
+ }
+ if (!done && gLayoutTestController->dumpResourceResponseMIMETypes())
+ printf("%s has MIME type %s\n", [[[[response URL] relativePath] lastPathComponent] UTF8String], [[response MIMEType] UTF8String]);
+}
+
+-(void)webView: (WebView *)wv resource:identifier didReceiveContentLength: (NSInteger)length fromDataSource:(WebDataSource *)dataSource
+{
+}
+
+-(void)webView: (WebView *)wv resource:identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource
+{
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didFinishLoading", identifier];
+ printf("%s\n", [string UTF8String]);
+ }
+}
+
+-(void)webView: (WebView *)wv resource:identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource
+{
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - didFailLoadingWithError: %@", identifier, [error _drt_descriptionSuitableForTestResult]];
+ printf("%s\n", [string UTF8String]);
+ }
+}
+
+- (void)webView: (WebView *)wv plugInFailedWithError:(NSError *)error dataSource:(WebDataSource *)dataSource
+{
+ // The call to -display here simulates the "Plug-in not found" sheet that Safari shows.
+ // It is used for platform/mac/plugins/update-widget-from-style-recalc.html
+ [wv display];
+}
+
+-(NSCachedURLResponse *) webView: (WebView *)wv resource:(id)identifier willCacheResponse:(NSCachedURLResponse *)response fromDataSource:(WebDataSource *)dataSource
+{
+ if (!done && gLayoutTestController->dumpWillCacheResponse()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - willCacheResponse: called", identifier];
+ printf("%s\n", [string UTF8String]);
+ }
+ return response;
+}
+
+-(BOOL)webView: (WebView*)webView shouldPaintBrokenImageForURL:(NSURL*)imageURL
+{
+ // Only log the message when shouldPaintBrokenImage() returns NO; this avoids changing results of layout tests with failed
+ // images, e.g., security/block-test-no-port.html.
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks() && !gLayoutTestController->shouldPaintBrokenImage()) {
+ NSString *string = [NSString stringWithFormat:@"%@ - shouldPaintBrokenImage: NO", [imageURL _drt_descriptionSuitableForTestResult]];
+ printf("%s\n", [string UTF8String]);
+ }
+
+ return gLayoutTestController->shouldPaintBrokenImage();
+}
+@end
diff --git a/Tools/DumpRenderTree/mac/TextInputController.h b/Tools/DumpRenderTree/mac/TextInputController.h
new file mode 100644
index 000000000..767e72f0c
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/TextInputController.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class WebView;
+@class WebHTMLView;
+@class WebScriptObject;
+
+@interface TextInputController : NSObject
+{
+ WebView *webView;
+ WebHTMLView *inputMethodView;
+ WebScriptObject *inputMethodHandler;
+}
+- (id)initWithWebView:(WebView *)view;
+@end
diff --git a/Tools/DumpRenderTree/mac/TextInputController.m b/Tools/DumpRenderTree/mac/TextInputController.m
new file mode 100644
index 000000000..f78079446
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/TextInputController.m
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "TextInputController.h"
+
+#import "DumpRenderTreeMac.h"
+#import <AppKit/NSInputManager.h>
+#import <WebKit/WebDocument.h>
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebFramePrivate.h>
+#import <WebKit/WebFrameView.h>
+#import <WebKit/WebHTMLViewPrivate.h>
+#import <WebKit/WebScriptObject.h>
+#import <WebKit/WebTypesInternal.h>
+#import <WebKit/WebView.h>
+
+@interface TextInputController (DumpRenderTreeInputMethodHandler)
+- (BOOL)interpretKeyEvents:(NSArray *)eventArray withSender:(WebHTMLView *)sender;
+@end
+
+@interface WebHTMLView (DumpRenderTreeInputMethodHandler)
+- (void)interpretKeyEvents:(NSArray *)eventArray;
+@end
+
+@interface WebHTMLView (WebKitSecretsTextInputControllerIsAwareOf)
+- (WebFrame *)_frame;
+@end
+
+@implementation WebHTMLView (DumpRenderTreeInputMethodHandler)
+- (void)interpretKeyEvents:(NSArray *)eventArray
+{
+ WebScriptObject *obj = [[self _frame] windowObject];
+ TextInputController *tic = [obj valueForKey:@"textInputController"];
+ if (![tic interpretKeyEvents:eventArray withSender:self])
+ [super interpretKeyEvents:eventArray];
+}
+@end
+
+@implementation NSMutableAttributedString (TextInputController)
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
+{
+ if (aSelector == @selector(string)
+ || aSelector == @selector(getLength)
+ || aSelector == @selector(attributeNamesAtIndex:)
+ || aSelector == @selector(valueOfAttribute:atIndex:)
+ || aSelector == @selector(addAttribute:value:)
+ || aSelector == @selector(addAttribute:value:from:length:)
+ || aSelector == @selector(addColorAttribute:red:green:blue:alpha:)
+ || aSelector == @selector(addColorAttribute:red:green:blue:alpha:from:length:)
+ || aSelector == @selector(addFontAttribute:fontName:size:)
+ || aSelector == @selector(addFontAttribute:fontName:size:from:length:))
+ return NO;
+ return YES;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)aSelector
+{
+ if (aSelector == @selector(getLength))
+ return @"length";
+ if (aSelector == @selector(attributeNamesAtIndex:))
+ return @"getAttributeNamesAtIndex";
+ if (aSelector == @selector(valueOfAttribute:atIndex:))
+ return @"getAttributeValueAtIndex";
+ if (aSelector == @selector(addAttribute:value:))
+ return @"addAttribute";
+ if (aSelector == @selector(addAttribute:value:from:length:))
+ return @"addAttributeForRange";
+ if (aSelector == @selector(addColorAttribute:red:green:blue:alpha:))
+ return @"addColorAttribute";
+ if (aSelector == @selector(addColorAttribute:red:green:blue:alpha:from:length:))
+ return @"addColorAttributeForRange";
+ if (aSelector == @selector(addFontAttribute:fontName:size:))
+ return @"addFontAttribute";
+ if (aSelector == @selector(addFontAttribute:fontName:size:from:length:))
+ return @"addFontAttributeForRange";
+
+ return nil;
+}
+
+- (int)getLength
+{
+ return (int)[self length];
+}
+
+- (NSArray *)attributeNamesAtIndex:(int)index
+{
+ NSDictionary *attributes = [self attributesAtIndex:(unsigned)index effectiveRange:nil];
+ return [attributes allKeys];
+}
+
+- (id)valueOfAttribute:(NSString *)attrName atIndex:(int)index
+{
+ return [self attribute:attrName atIndex:(unsigned)index effectiveRange:nil];
+}
+
+- (void)addAttribute:(NSString *)attrName value:(id)value
+{
+ [self addAttribute:attrName value:value range:NSMakeRange(0, [self length])];
+}
+
+- (void)addAttribute:(NSString *)attrName value:(id)value from:(int)from length:(int)length
+{
+ [self addAttribute:attrName value:value range:NSMakeRange((unsigned)from, (unsigned)length)];
+}
+
+- (void)addColorAttribute:(NSString *)attrName red:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
+{
+ [self addAttribute:attrName value:[NSColor colorWithDeviceRed:red green:green blue:blue alpha:alpha] range:NSMakeRange(0, [self length])];
+}
+
+- (void)addColorAttribute:(NSString *)attrName red:(float)red green:(float)green blue:(float)blue alpha:(float)alpha from:(int)from length:(int)length
+{
+ [self addAttribute:attrName value:[NSColor colorWithDeviceRed:red green:green blue:blue alpha:alpha] range:NSMakeRange((unsigned)from, (unsigned)length)];
+}
+
+- (void)addFontAttribute:(NSString *)attrName fontName:(NSString *)fontName size:(float)fontSize
+{
+ [self addAttribute:attrName value:[NSFont fontWithName:fontName size:fontSize] range:NSMakeRange(0, [self length])];
+}
+
+- (void)addFontAttribute:(NSString *)attrName fontName:(NSString *)fontName size:(float)fontSize from:(int)from length:(int)length
+{
+ [self addAttribute:attrName value:[NSFont fontWithName:fontName size:fontSize] range:NSMakeRange((unsigned)from, (unsigned)length)];
+}
+
+@end
+
+@implementation TextInputController
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
+{
+ if (aSelector == @selector(insertText:)
+ || aSelector == @selector(doCommand:)
+ || aSelector == @selector(setMarkedText:selectedFrom:length:)
+ || aSelector == @selector(unmarkText)
+ || aSelector == @selector(hasMarkedText)
+ || aSelector == @selector(conversationIdentifier)
+ || aSelector == @selector(substringFrom:length:)
+ || aSelector == @selector(attributedSubstringFrom:length:)
+ || aSelector == @selector(markedRange)
+ || aSelector == @selector(selectedRange)
+ || aSelector == @selector(firstRectForCharactersFrom:length:)
+ || aSelector == @selector(characterIndexForPointX:Y:)
+ || aSelector == @selector(validAttributesForMarkedText)
+ || aSelector == @selector(attributedStringWithString:)
+ || aSelector == @selector(setInputMethodHandler:))
+ return NO;
+ return YES;
+}
+
++ (NSString *)webScriptNameForSelector:(SEL)aSelector
+{
+ if (aSelector == @selector(insertText:))
+ return @"insertText";
+ else if (aSelector == @selector(doCommand:))
+ return @"doCommand";
+ else if (aSelector == @selector(setMarkedText:selectedFrom:length:))
+ return @"setMarkedText";
+ else if (aSelector == @selector(substringFrom:length:))
+ return @"substringFromRange";
+ else if (aSelector == @selector(attributedSubstringFrom:length:))
+ return @"attributedSubstringFromRange";
+ else if (aSelector == @selector(firstRectForCharactersFrom:length:))
+ return @"firstRectForCharacterRange";
+ else if (aSelector == @selector(characterIndexForPointX:Y:))
+ return @"characterIndexForPoint";
+ else if (aSelector == @selector(attributedStringWithString:))
+ return @"makeAttributedString"; // just a factory method, doesn't call into NSTextInput
+ else if (aSelector == @selector(setInputMethodHandler:))
+ return @"setInputMethodHandler";
+
+ return nil;
+}
+
+- (id)initWithWebView:(WebView *)wv
+{
+ self = [super init];
+ webView = wv;
+ inputMethodView = nil;
+ inputMethodHandler = nil;
+ return self;
+}
+
+- (void)dealloc
+{
+ [inputMethodHandler release];
+ inputMethodHandler = nil;
+
+ [super dealloc];
+}
+
+- (NSObject <NSTextInput> *)textInput
+{
+ NSView <NSTextInput> *view = inputMethodView ? inputMethodView : (id)[[[webView mainFrame] frameView] documentView];
+ return [view conformsToProtocol:@protocol(NSTextInput)] ? view : nil;
+}
+
+- (void)insertText:(id)aString
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput)
+ [textInput insertText:aString];
+}
+
+- (void)doCommand:(NSString *)aCommand
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput)
+ [textInput doCommandBySelector:NSSelectorFromString(aCommand)];
+}
+
+- (void)setMarkedText:(NSString *)aString selectedFrom:(int)from length:(int)length
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput)
+ [textInput setMarkedText:aString selectedRange:NSMakeRange(from, length)];
+}
+
+- (void)unmarkText
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput)
+ [textInput unmarkText];
+}
+
+- (BOOL)hasMarkedText
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput)
+ return [textInput hasMarkedText];
+
+ return FALSE;
+}
+
+- (long)conversationIdentifier
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput)
+ return [textInput conversationIdentifier];
+
+ return 0;
+}
+
+- (NSString *)substringFrom:(int)from length:(int)length
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput)
+ return [[textInput attributedSubstringFromRange:NSMakeRange(from, length)] string];
+
+ return @"";
+}
+
+- (NSMutableAttributedString *)attributedSubstringFrom:(int)from length:(int)length
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ NSMutableAttributedString *ret = [[[NSMutableAttributedString alloc] init] autorelease];
+
+ if (textInput)
+ [ret setAttributedString:[textInput attributedSubstringFromRange:NSMakeRange(from, length)]];
+
+ return ret;
+}
+
+- (NSArray *)markedRange
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput) {
+ NSRange range = [textInput markedRange];
+ return [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:range.location], [NSNumber numberWithUnsignedInt:range.length], nil];
+ }
+
+ return nil;
+}
+
+- (NSArray *)selectedRange
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput) {
+ NSRange range = [textInput selectedRange];
+ return [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:range.location], [NSNumber numberWithUnsignedInt:range.length], nil];
+ }
+
+ return nil;
+}
+
+
+- (NSArray *)firstRectForCharactersFrom:(int)from length:(int)length
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput) {
+ NSRect rect = [textInput firstRectForCharacterRange:NSMakeRange(from, length)];
+ if (rect.origin.x || rect.origin.y || rect.size.width || rect.size.height) {
+ rect.origin = [[webView window] convertScreenToBase:rect.origin];
+ rect = [webView convertRect:rect fromView:nil];
+ }
+ return [NSArray arrayWithObjects:
+ [NSNumber numberWithFloat:rect.origin.x],
+ [NSNumber numberWithFloat:rect.origin.y],
+ [NSNumber numberWithFloat:rect.size.width],
+ [NSNumber numberWithFloat:rect.size.height],
+ nil];
+ }
+
+ return nil;
+}
+
+- (NSInteger)characterIndexForPointX:(float)x Y:(float)y
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput) {
+ NSPoint point = NSMakePoint(x, y);
+ point = [webView convertPoint:point toView:nil];
+ point = [[webView window] convertBaseToScreen:point];
+ NSInteger index = [textInput characterIndexForPoint:point];
+ if (index == NSNotFound)
+ return -1;
+
+ return index;
+ }
+
+ return 0;
+}
+
+- (NSArray *)validAttributesForMarkedText
+{
+ NSObject <NSTextInput> *textInput = [self textInput];
+
+ if (textInput)
+ return [textInput validAttributesForMarkedText];
+
+ return nil;
+}
+
+- (NSMutableAttributedString *)attributedStringWithString:(NSString *)aString
+{
+ return [[[NSMutableAttributedString alloc] initWithString:aString] autorelease];
+}
+
+- (void)setInputMethodHandler:(WebScriptObject *)handler
+{
+ if (inputMethodHandler == handler)
+ return;
+ [handler retain];
+ [inputMethodHandler release];
+ inputMethodHandler = handler;
+}
+
+- (BOOL)interpretKeyEvents:(NSArray *)eventArray withSender:(WebHTMLView *)sender
+{
+ if (!inputMethodHandler)
+ return NO;
+
+ inputMethodView = sender;
+
+ NSEvent *event = [eventArray objectAtIndex:0];
+ unsigned modifierFlags = [event modifierFlags];
+ NSMutableArray *modifiers = [[NSMutableArray alloc] init];
+ if (modifierFlags & NSAlphaShiftKeyMask)
+ [modifiers addObject:@"NSAlphaShiftKeyMask"];
+ if (modifierFlags & NSShiftKeyMask)
+ [modifiers addObject:@"NSShiftKeyMask"];
+ if (modifierFlags & NSControlKeyMask)
+ [modifiers addObject:@"NSControlKeyMask"];
+ if (modifierFlags & NSAlternateKeyMask)
+ [modifiers addObject:@"NSAlternateKeyMask"];
+ if (modifierFlags & NSCommandKeyMask)
+ [modifiers addObject:@"NSCommandKeyMask"];
+ if (modifierFlags & NSNumericPadKeyMask)
+ [modifiers addObject:@"NSNumericPadKeyMask"];
+ if (modifierFlags & NSHelpKeyMask)
+ [modifiers addObject:@"NSHelpKeyMask"];
+ if (modifierFlags & NSFunctionKeyMask)
+ [modifiers addObject:@"NSFunctionKeyMask"];
+
+ WebScriptObject* eventParam = [inputMethodHandler evaluateWebScript:@"new Object();"];
+ [eventParam setValue:[event characters] forKey:@"characters"];
+ [eventParam setValue:[event charactersIgnoringModifiers] forKey:@"charactersIgnoringModifiers"];
+ [eventParam setValue:[NSNumber numberWithBool:[event isARepeat]] forKey:@"isARepeat"];
+ [eventParam setValue:[NSNumber numberWithUnsignedShort:[event keyCode]] forKey:@"keyCode"];
+ [eventParam setValue:modifiers forKey:@"modifierFlags"];
+
+ [modifiers release];
+
+ id result = [inputMethodHandler callWebScriptMethod:@"call" withArguments:[NSArray arrayWithObjects:inputMethodHandler, eventParam, nil]];
+ if (![result respondsToSelector:@selector(boolValue)] || ![result boolValue])
+ [sender doCommandBySelector:@selector(noop:)]; // AppKit sends noop: if the ime does not handle an event
+
+ inputMethodView = nil;
+ return YES;
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/UIDelegate.h b/Tools/DumpRenderTree/mac/UIDelegate.h
new file mode 100644
index 000000000..982b4802c
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/UIDelegate.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface UIDelegate : NSObject {
+
+@private
+ NSRect m_frame;
+ NSMutableSet *m_pendingGeolocationPermissionListeners;
+ NSTimer *m_timer;
+}
+
+- (void)didSetMockGeolocationPermission;
+- (int)numberOfPendingGeolocationPermissionRequests;
+
+@end
diff --git a/Tools/DumpRenderTree/mac/UIDelegate.mm b/Tools/DumpRenderTree/mac/UIDelegate.mm
new file mode 100644
index 000000000..8b462172d
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/UIDelegate.mm
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2006. 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "UIDelegate.h"
+
+#import "DumpRenderTree.h"
+#import "DumpRenderTreeDraggingInfo.h"
+#import "EventSendingController.h"
+#import "LayoutTestController.h"
+#import <WebKit/WebApplicationCache.h>
+#import <WebKit/WebFramePrivate.h>
+#import <WebKit/WebHTMLViewPrivate.h>
+#import <WebKit/WebQuotaManager.h>
+#import <WebKit/WebSecurityOriginPrivate.h>
+#import <WebKit/WebUIDelegatePrivate.h>
+#import <WebKit/WebView.h>
+#import <WebKit/WebViewPrivate.h>
+#import <wtf/Assertions.h>
+
+DumpRenderTreeDraggingInfo *draggingInfo = nil;
+
+@implementation UIDelegate
+
+- (void)webView:(WebView *)sender setFrame:(NSRect)frame
+{
+ m_frame = frame;
+}
+
+- (NSRect)webViewFrame:(WebView *)sender
+{
+ return m_frame;
+}
+
+- (void)webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary withSource:(NSString *)source
+{
+ NSString *message = [dictionary objectForKey:@"message"];
+ NSNumber *lineNumber = [dictionary objectForKey:@"lineNumber"];
+
+ NSRange range = [message rangeOfString:@"file://"];
+ if (range.location != NSNotFound)
+ message = [[message substringToIndex:range.location] stringByAppendingString:[[message substringFromIndex:NSMaxRange(range)] lastPathComponent]];
+
+ printf ("CONSOLE MESSAGE: line %d: %s\n", [lineNumber intValue], [message UTF8String]);
+}
+
+- (void)modalWindowWillClose:(NSNotification *)notification
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:nil];
+ [NSApp abortModal];
+}
+
+- (void)webViewRunModal:(WebView *)sender
+{
+ gLayoutTestController->setWindowIsKey(false);
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(modalWindowWillClose:) name:NSWindowWillCloseNotification object:nil];
+ [NSApp runModalForWindow:[sender window]];
+ gLayoutTestController->setWindowIsKey(true);
+}
+
+- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
+{
+ if (!done)
+ printf("ALERT: %s\n", [message UTF8String]);
+}
+
+- (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
+{
+ if (!done)
+ printf("CONFIRM: %s\n", [message UTF8String]);
+ return YES;
+}
+
+- (NSString *)webView:(WebView *)sender runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WebFrame *)frame
+{
+ if (!done)
+ printf("PROMPT: %s, default text: %s\n", [prompt UTF8String], [defaultText UTF8String]);
+ return defaultText;
+}
+
+- (BOOL)webView:(WebView *)c runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
+{
+ if (!done)
+ printf("CONFIRM NAVIGATION: %s\n", [message UTF8String]);
+
+ return !gLayoutTestController->shouldStayOnPageAfterHandlingBeforeUnload();
+}
+
+
+- (void)webView:(WebView *)sender dragImage:(NSImage *)anImage at:(NSPoint)viewLocation offset:(NSSize)initialOffset event:(NSEvent *)event pasteboard:(NSPasteboard *)pboard source:(id)sourceObj slideBack:(BOOL)slideFlag forView:(NSView *)view
+{
+ assert(!draggingInfo);
+ draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:anImage offset:initialOffset pasteboard:pboard source:sourceObj];
+ [sender draggingUpdated:draggingInfo];
+ [EventSendingController replaySavedEvents];
+}
+
+- (void)webViewFocus:(WebView *)webView
+{
+ gLayoutTestController->setWindowIsKey(true);
+}
+
+- (void)webViewUnfocus:(WebView *)webView
+{
+ gLayoutTestController->setWindowIsKey(false);
+}
+
+- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request
+{
+ if (!gLayoutTestController->canOpenWindows())
+ return nil;
+
+ // Make sure that waitUntilDone has been called.
+ ASSERT(gLayoutTestController->waitToDump());
+
+ WebView *webView = createWebViewAndOffscreenWindow();
+
+ if (gLayoutTestController->newWindowsCopyBackForwardList())
+ [webView _loadBackForwardListFromOtherView:sender];
+
+ return [webView autorelease];
+}
+
+- (void)webViewClose:(WebView *)sender
+{
+ NSWindow* window = [sender window];
+
+ if (gLayoutTestController->callCloseOnWebViews())
+ [sender close];
+
+ [window close];
+}
+
+- (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)databaseIdentifier
+{
+ if (!done && gLayoutTestController->dumpDatabaseCallbacks()) {
+ printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n", [[origin protocol] UTF8String], [[origin host] UTF8String],
+ [origin port], [databaseIdentifier UTF8String]);
+ }
+
+ static const unsigned long long defaultQuota = 5 * 1024 * 1024;
+ [[origin databaseQuotaManager] setQuota:defaultQuota];
+}
+
+- (void)webView:(WebView *)sender exceededApplicationCacheOriginQuotaForSecurityOrigin:(WebSecurityOrigin *)origin totalSpaceNeeded:(NSUInteger)totalSpaceNeeded
+{
+ if (!done && gLayoutTestController->dumpApplicationCacheDelegateCallbacks()) {
+ // For example, numbers from 30000 - 39999 will output as 30000.
+ // Rounding up or down not really matter for these tests. It's
+ // sufficient to just get a range of 10000 to determine if we were
+ // above or below a threshold.
+ unsigned long truncatedSpaceNeeded = static_cast<unsigned long>((totalSpaceNeeded / 10000) * 10000);
+ printf("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:{%s, %s, %i} totalSpaceNeeded:~%lu\n",
+ [[origin protocol] UTF8String], [[origin host] UTF8String], [origin port], truncatedSpaceNeeded);
+ }
+
+ if (gLayoutTestController->disallowIncreaseForApplicationCacheQuota())
+ return;
+
+ static const unsigned long long defaultOriginQuota = [WebApplicationCache defaultOriginQuota];
+ [[origin applicationCacheQuotaManager] setQuota:defaultOriginQuota];
+}
+
+- (void)webView:(WebView *)sender setStatusText:(NSString *)text
+{
+ if (gLayoutTestController->dumpStatusCallbacks())
+ printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", [text UTF8String]);
+}
+
+- (void)webView:(WebView *)webView decidePolicyForGeolocationRequestFromOrigin:(WebSecurityOrigin *)origin frame:(WebFrame *)frame listener:(id<WebGeolocationPolicyListener>)listener
+{
+ if (!gLayoutTestController->isGeolocationPermissionSet()) {
+ if (!m_pendingGeolocationPermissionListeners)
+ m_pendingGeolocationPermissionListeners = [[NSMutableSet set] retain];
+ [m_pendingGeolocationPermissionListeners addObject:listener];
+ return;
+ }
+
+ if (gLayoutTestController->geolocationPermission())
+ [listener allow];
+ else
+ [listener deny];
+}
+
+- (void)didSetMockGeolocationPermission
+{
+ ASSERT(gLayoutTestController->isGeolocationPermissionSet());
+ if (m_pendingGeolocationPermissionListeners && !m_timer)
+ m_timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO];
+}
+
+- (int)numberOfPendingGeolocationPermissionRequests
+{
+ if (!m_pendingGeolocationPermissionListeners)
+ return 0;
+ return [m_pendingGeolocationPermissionListeners count];
+}
+
+
+- (void)timerFired
+{
+ ASSERT(gLayoutTestController->isGeolocationPermissionSet());
+ m_timer = 0;
+ NSEnumerator* enumerator = [m_pendingGeolocationPermissionListeners objectEnumerator];
+ id<WebGeolocationPolicyListener> listener;
+ while ((listener = [enumerator nextObject])) {
+ if (gLayoutTestController->geolocationPermission())
+ [listener allow];
+ else
+ [listener deny];
+ }
+ [m_pendingGeolocationPermissionListeners removeAllObjects];
+ [m_pendingGeolocationPermissionListeners release];
+ m_pendingGeolocationPermissionListeners = nil;
+}
+
+- (BOOL)webView:(WebView *)sender shouldHaltPlugin:(DOMNode *)pluginNode
+{
+ return NO;
+}
+
+- (BOOL)webView:(WebView *)webView supportsFullScreenForElement:(DOMElement*)element withKeyboard:(BOOL)withKeyboard
+{
+ return YES;
+}
+
+- (void)webView:(WebView *)webView enterFullScreenForElement:(DOMElement*)element listener:(NSObject<WebKitFullScreenListener>*)listener
+{
+ [listener webkitWillEnterFullScreen];
+ [listener webkitDidEnterFullScreen];
+}
+
+- (void)webView:(WebView *)webView exitFullScreenForElement:(DOMElement*)element listener:(NSObject<WebKitFullScreenListener>*)listener
+{
+ [listener webkitWillExitFullScreen];
+ [listener webkitDidExitFullScreen];
+}
+
+- (BOOL)webView:(WebView *)webView didPressMissingPluginButton:(DOMElement *)element
+{
+ printf("MISSING PLUGIN BUTTON PRESSED\n");
+ return TRUE;
+}
+
+- (void)dealloc
+{
+ [draggingInfo release];
+ draggingInfo = nil;
+ [m_pendingGeolocationPermissionListeners release];
+ m_pendingGeolocationPermissionListeners = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm b/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm
new file mode 100644
index 000000000..9f94ecbc4
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "WebArchiveDumpSupport.h"
+
+#import <CFNetwork/CFHTTPMessage.h>
+#import <Foundation/Foundation.h>
+#import <WebKit/WebHTMLRepresentation.h>
+#import <wtf/RetainPtr.h>
+
+extern "C" {
+
+enum CFURLCacheStoragePolicy {
+ kCFURLCacheStorageAllowed = 0,
+ kCFURLCacheStorageAllowedInMemoryOnly = 1,
+ kCFURLCacheStorageNotAllowed = 2
+};
+typedef enum CFURLCacheStoragePolicy CFURLCacheStoragePolicy;
+
+extern const CFStringRef kCFHTTPVersion1_1;
+
+CFURLResponseRef CFURLResponseCreate(CFAllocatorRef alloc, CFURLRef URL, CFStringRef mimeType, SInt64 expectedContentLength, CFStringRef textEncodingName, CFURLCacheStoragePolicy recommendedPolicy);
+CFURLResponseRef CFURLResponseCreateWithHTTPResponse(CFAllocatorRef alloc, CFURLRef URL, CFHTTPMessageRef httpResponse, CFURLCacheStoragePolicy recommendedPolicy);
+void CFURLResponseSetExpectedContentLength(CFURLResponseRef response, SInt64 length);
+void CFURLResponseSetMIMEType(CFURLResponseRef response, CFStringRef mimeType);
+
+}
+
+CFURLResponseRef createCFURLResponseFromResponseData(CFDataRef responseData)
+{
+ // Decode NSURLResponse
+ RetainPtr<NSKeyedUnarchiver> unarchiver(AdoptNS, [[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)responseData]);
+ NSURLResponse *response = [unarchiver.get() decodeObjectForKey:@"WebResourceResponse"]; // WebResourceResponseKey in WebResource.m
+ [unarchiver.get() finishDecoding];
+
+ if (![response isKindOfClass:[NSHTTPURLResponse class]])
+ return CFURLResponseCreate(kCFAllocatorDefault, (CFURLRef)[response URL], (CFStringRef)[response MIMEType], [response expectedContentLength], (CFStringRef)[response textEncodingName], kCFURLCacheStorageAllowed);
+
+ NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
+
+ // NSURLResponse is not toll-free bridged to CFURLResponse.
+ RetainPtr<CFHTTPMessageRef> httpMessage(AdoptCF, CFHTTPMessageCreateResponse(kCFAllocatorDefault, [httpResponse statusCode], 0, kCFHTTPVersion1_1));
+
+ NSDictionary *headerFields = [httpResponse allHeaderFields];
+ for (NSString *headerField in [headerFields keyEnumerator])
+ CFHTTPMessageSetHeaderFieldValue(httpMessage.get(), (CFStringRef)headerField, (CFStringRef)[headerFields objectForKey:headerField]);
+
+ return CFURLResponseCreateWithHTTPResponse(kCFAllocatorDefault, (CFURLRef)[response URL], httpMessage.get(), kCFURLCacheStorageAllowed);
+}
+
+CFArrayRef supportedNonImageMIMETypes()
+{
+ return (CFArrayRef)[WebHTMLRepresentation supportedNonImageMIMETypes];
+}
diff --git a/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm b/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm
new file mode 100644
index 000000000..c28e991e2
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#import "config.h"
+#import "DumpRenderTree.h"
+#import "WorkQueueItem.h"
+
+#import <JavaScriptCore/JSStringRef.h>
+#import <JavaScriptCore/JSStringRefCF.h>
+#import <WebKit/WebBackForwardList.h>
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebScriptObject.h>
+#import <WebKit/WebView.h>
+#import <wtf/RetainPtr.h>
+
+bool LoadItem::invoke() const
+{
+ RetainPtr<CFStringRef> urlCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_url.get()));
+ NSString *urlNS = (NSString *)urlCF.get();
+ RetainPtr<CFStringRef> targetCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_target.get()));
+ NSString *targetNS = (NSString *)targetCF.get();
+
+ WebFrame *targetFrame;
+ if (targetNS && [targetNS length])
+ targetFrame = [mainFrame findFrameNamed:targetNS];
+ else
+ targetFrame = mainFrame;
+ [targetFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlNS]]];
+ return true;
+}
+
+bool LoadHTMLStringItem::invoke() const
+{
+ RetainPtr<CFStringRef> contentCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_content.get()));
+ RetainPtr<CFStringRef> baseURLCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_baseURL.get()));
+
+ if (m_unreachableURL) {
+ RetainPtr<CFStringRef> unreachableURLCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_unreachableURL.get()));
+ [mainFrame loadAlternateHTMLString:(NSString *)contentCF.get() baseURL:[NSURL URLWithString:(NSString *)baseURLCF.get()] forUnreachableURL:[NSURL URLWithString:(NSString *)unreachableURLCF.get()]];
+ return true;
+ }
+
+ [mainFrame loadHTMLString:(NSString *)contentCF.get() baseURL:[NSURL URLWithString:(NSString *)baseURLCF.get()]];
+ return true;
+}
+
+bool ReloadItem::invoke() const
+{
+ [[mainFrame webView] reload:nil];
+ return true;
+}
+
+bool ScriptItem::invoke() const
+{
+ RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, m_script.get()));
+ NSString *scriptNS = (NSString *)scriptCF.get();
+ [[mainFrame webView] stringByEvaluatingJavaScriptFromString:scriptNS];
+ return true;
+}
+
+bool BackForwardItem::invoke() const
+{
+ if (m_howFar == 1)
+ [[mainFrame webView] goForward];
+ else if (m_howFar == -1)
+ [[mainFrame webView] goBack];
+ else {
+ WebBackForwardList *bfList = [[mainFrame webView] backForwardList];
+ [[mainFrame webView] goToBackForwardItem:[bfList itemAtIndex:m_howFar]];
+ }
+ return true;
+}
diff --git a/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp b/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp
new file mode 100644
index 000000000..1266c020e
--- /dev/null
+++ b/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "JavaScriptThreading.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <pthread.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+
+static JSContextGroupRef javaScriptThreadsGroup;
+
+static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool javaScriptThreadsShouldTerminate;
+
+static const int javaScriptThreadsCount = 4;
+
+typedef HashSet<pthread_t> ThreadSet;
+
+static ThreadSet* javaScriptThreads()
+{
+ ASSERT(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY);
+ static ThreadSet staticJavaScriptThreads;
+ return &staticJavaScriptThreads;
+}
+
+// This function exercises JSC in a loop until javaScriptThreadsShouldTerminate
+// becomes true or it probabilistically decides to spawn a replacement thread and exit.
+void* runJavaScriptThread(void* arg)
+{
+ static const char* const script =
+ "var array = [];"
+ "for (var i = 0; i < 1024; i++) {"
+ " array.push(String(i));"
+ "}";
+
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ JSGlobalContextRef ctx = JSGlobalContextCreateInGroup(javaScriptThreadsGroup, 0);
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+
+ while (1) {
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ JSValueRef exception = 0;
+ JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
+ ASSERT(!exception);
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ size_t valuesCount = 1024;
+ JSValueRef values[valuesCount];
+ for (size_t i = 0; i < valuesCount; ++i)
+ values[i] = JSObjectMake(ctx, 0, 0);
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+
+ // Check for cancellation.
+ if (javaScriptThreadsShouldTerminate)
+ goto done;
+
+ // Respawn probabilistically.
+ if (random() % 5 == 0) {
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ pthread_t pthread;
+ pthread_create(&pthread, 0, &runJavaScriptThread, 0);
+ pthread_detach(pthread);
+ javaScriptThreads()->add(pthread);
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ goto done;
+ }
+ }
+
+done:
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ JSStringRelease(scriptRef);
+ JSGarbageCollect(ctx);
+ JSGlobalContextRelease(ctx);
+ javaScriptThreads()->remove(pthread_self());
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ return 0;
+}
+
+void startJavaScriptThreads()
+{
+ javaScriptThreadsGroup = JSContextGroupCreate();
+
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+
+ for (int i = 0; i < javaScriptThreadsCount; i++) {
+ pthread_t pthread;
+ pthread_create(&pthread, 0, &runJavaScriptThread, 0);
+ pthread_detach(pthread);
+ javaScriptThreads()->add(pthread);
+ }
+
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+}
+
+void stopJavaScriptThreads()
+{
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+
+ javaScriptThreadsShouldTerminate = true;
+
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+
+ while (true) {
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ int threadCount = javaScriptThreads()->size();
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+
+ if (!threadCount)
+ break;
+
+ usleep(1000);
+ }
+}
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTree.pro b/Tools/DumpRenderTree/qt/DumpRenderTree.pro
new file mode 100644
index 000000000..772cb35d5
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTree.pro
@@ -0,0 +1,61 @@
+# -------------------------------------------------------------------
+# Project file for the DumpRenderTree binary (DRT)
+#
+# See 'Tools/qmake/README' for an overview of the build system
+# -------------------------------------------------------------------
+
+TEMPLATE = app
+
+TARGET = DumpRenderTree
+DESTDIR = $$ROOT_BUILD_DIR/bin
+
+load(features)
+CONFIG += uitools
+
+WEBKIT += wtf webcore
+
+CONFIG += qtwebkit
+
+INCLUDEPATH += \
+ $$PWD/.. \
+ $${ROOT_WEBKIT_DIR}/Source/WebKit/qt/WebCoreSupport
+
+QT = core gui network testlib
+macx: QT += xml
+haveQt(5): QT += widgets printsupport
+
+contains(DEFINES, HAVE_FONTCONFIG=1): PKGCONFIG += fontconfig
+
+HEADERS += \
+ $$PWD/../WorkQueue.h \
+ DumpRenderTreeQt.h \
+ EventSenderQt.h \
+ TextInputControllerQt.h \
+ WorkQueueItemQt.h \
+ LayoutTestControllerQt.h \
+ GCControllerQt.h \
+ PlainTextControllerQt.h \
+ testplugin.h
+
+SOURCES += \
+ $${ROOT_WEBKIT_DIR}/Source/JavaScriptCore/wtf/Assertions.cpp \
+ $$PWD/../WorkQueue.cpp \
+ DumpRenderTreeQt.cpp \
+ EventSenderQt.cpp \
+ TextInputControllerQt.cpp \
+ PlainTextControllerQt.cpp \
+ WorkQueueItemQt.cpp \
+ LayoutTestControllerQt.cpp \
+ GCControllerQt.cpp \
+ testplugin.cpp \
+ main.cpp
+
+wince*: {
+ INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat $$WCECOMPAT/include
+ LIBS += $$WCECOMPAT/lib/wcecompat.lib
+}
+
+DEFINES -= USE_SYSTEM_MALLOC=0
+DEFINES += USE_SYSTEM_MALLOC=1
+
+RESOURCES = DumpRenderTree.qrc
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTree.qrc b/Tools/DumpRenderTree/qt/DumpRenderTree.qrc
new file mode 100644
index 000000000..71d163aa7
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTree.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>resources/user.css</file>
+ </qresource>
+</RCC>
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
new file mode 100644
index 000000000..c1a3ed450
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
@@ -0,0 +1,1185 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTreeQt.h"
+#include "DumpRenderTreeSupportQt.h"
+#include "EventSenderQt.h"
+#include "GCControllerQt.h"
+#include "LayoutTestControllerQt.h"
+#include "TextInputControllerQt.h"
+#include "PlainTextControllerQt.h"
+#include "testplugin.h"
+#include "WorkQueue.h"
+
+#include <QApplication>
+#include <QBuffer>
+#include <QCryptographicHash>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QFocusEvent>
+#include <QFontDatabase>
+#include <QLocale>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QPaintDevice>
+#include <QPaintEngine>
+#ifndef QT_NO_PRINTER
+#include <QPrinter>
+#endif
+#include <QUndoStack>
+#include <QUrl>
+
+#include <qwebsettings.h>
+#include <qwebsecurityorigin.h>
+
+#ifndef QT_NO_UITOOLS
+#include <QtUiTools/QUiLoader>
+#endif
+
+#if HAVE(FONTCONFIG)
+#include <fontconfig/fontconfig.h>
+#endif
+
+#include <limits.h>
+#include <locale.h>
+
+#ifndef Q_OS_WIN
+#include <unistd.h>
+#endif
+
+#include <qdebug.h>
+
+namespace WebCore {
+
+const int databaseDefaultQuota = 5 * 1024 * 1024;
+
+NetworkAccessManager::NetworkAccessManager(QObject* parent)
+ : QNetworkAccessManager(parent)
+{
+#ifndef QT_NO_OPENSSL
+ connect(this, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)),
+ this, SLOT(sslErrorsEncountered(QNetworkReply*, const QList<QSslError>&)));
+#endif
+}
+
+#ifndef QT_NO_OPENSSL
+void NetworkAccessManager::sslErrorsEncountered(QNetworkReply* reply, const QList<QSslError>& errors)
+{
+ if (reply->url().host() == "127.0.0.1" || reply->url().host() == "localhost") {
+ bool ignore = true;
+
+ // Accept any HTTPS certificate.
+ foreach (const QSslError& error, errors) {
+ if (error.error() < QSslError::UnableToGetIssuerCertificate || error.error() > QSslError::HostNameMismatch) {
+ ignore = false;
+ break;
+ }
+ }
+
+ if (ignore)
+ reply->ignoreSslErrors();
+ }
+}
+#endif
+
+
+#ifndef QT_NO_PRINTER
+class NullPrinter : public QPrinter {
+public:
+ class NullPaintEngine : public QPaintEngine {
+ public:
+ virtual bool begin(QPaintDevice*) { return true; }
+ virtual bool end() { return true; }
+ virtual QPaintEngine::Type type() const { return QPaintEngine::User; }
+ virtual void drawPixmap(const QRectF& r, const QPixmap& pm, const QRectF& sr) { }
+ virtual void updateState(const QPaintEngineState& state) { }
+ };
+
+ virtual QPaintEngine* paintEngine() const { return const_cast<NullPaintEngine*>(&m_engine); }
+
+ NullPaintEngine m_engine;
+};
+#endif
+
+WebPage::WebPage(QObject* parent, DumpRenderTree* drt)
+ : QWebPage(parent)
+ , m_webInspector(0)
+ , m_drt(drt)
+{
+ QWebSettings* globalSettings = QWebSettings::globalSettings();
+
+ globalSettings->setFontSize(QWebSettings::MinimumFontSize, 0);
+ globalSettings->setFontSize(QWebSettings::MinimumLogicalFontSize, 5);
+ globalSettings->setFontSize(QWebSettings::DefaultFontSize, 16);
+ globalSettings->setFontSize(QWebSettings::DefaultFixedFontSize, 13);
+
+ globalSettings->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
+ globalSettings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, true);
+ globalSettings->setAttribute(QWebSettings::LinksIncludedInFocusChain, false);
+ globalSettings->setAttribute(QWebSettings::PluginsEnabled, true);
+ globalSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true);
+ globalSettings->setAttribute(QWebSettings::JavascriptEnabled, true);
+ globalSettings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false);
+ globalSettings->setAttribute(QWebSettings::SpatialNavigationEnabled, false);
+
+ connect(this, SIGNAL(geometryChangeRequested(const QRect &)),
+ this, SLOT(setViewGeometry(const QRect & )));
+
+ setNetworkAccessManager(m_drt->networkAccessManager());
+ setPluginFactory(new TestPlugin(this));
+
+ connect(this, SIGNAL(featurePermissionRequested(QWebFrame*, QWebPage::Feature)), this, SLOT(requestPermission(QWebFrame*, QWebPage::Feature)));
+ connect(this, SIGNAL(featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)), this, SLOT(cancelPermission(QWebFrame*, QWebPage::Feature)));
+}
+
+WebPage::~WebPage()
+{
+ delete m_webInspector;
+}
+
+QWebInspector* WebPage::webInspector()
+{
+ if (!m_webInspector) {
+ m_webInspector = new QWebInspector;
+ m_webInspector->setPage(this);
+ }
+ return m_webInspector;
+}
+
+void WebPage::resetSettings()
+{
+ // After each layout test, reset the settings that may have been changed by
+ // layoutTestController.overridePreference() or similar.
+ settings()->resetFontSize(QWebSettings::DefaultFontSize);
+ settings()->resetAttribute(QWebSettings::JavascriptCanOpenWindows);
+ settings()->resetAttribute(QWebSettings::JavascriptEnabled);
+ settings()->resetAttribute(QWebSettings::PrivateBrowsingEnabled);
+ settings()->resetAttribute(QWebSettings::SpatialNavigationEnabled);
+ settings()->resetAttribute(QWebSettings::LinksIncludedInFocusChain);
+ settings()->resetAttribute(QWebSettings::OfflineWebApplicationCacheEnabled);
+ settings()->resetAttribute(QWebSettings::LocalContentCanAccessRemoteUrls);
+ settings()->resetAttribute(QWebSettings::LocalContentCanAccessFileUrls);
+ settings()->resetAttribute(QWebSettings::PluginsEnabled);
+ settings()->resetAttribute(QWebSettings::JavascriptCanAccessClipboard);
+ settings()->resetAttribute(QWebSettings::AutoLoadImages);
+ settings()->resetAttribute(QWebSettings::ZoomTextOnly);
+
+ m_drt->layoutTestController()->setCaretBrowsingEnabled(false);
+ m_drt->layoutTestController()->setAuthorAndUserStylesEnabled(true);
+ m_drt->layoutTestController()->setFrameFlatteningEnabled(false);
+ m_drt->layoutTestController()->setSmartInsertDeleteEnabled(true);
+ m_drt->layoutTestController()->setSelectTrailingWhitespaceEnabled(false);
+ m_drt->layoutTestController()->setDefersLoading(false);
+
+ // globalSettings must be reset explicitly.
+ m_drt->layoutTestController()->setXSSAuditorEnabled(false);
+
+ QWebSettings::setMaximumPagesInCache(0); // reset to default
+ settings()->setUserStyleSheetUrl(QUrl()); // reset to default
+
+ DumpRenderTreeSupportQt::setMinimumTimerInterval(this, DumpRenderTreeSupportQt::defaultMinimumTimerInterval());
+ DumpRenderTreeSupportQt::setHixie76WebSocketProtocolEnabled(this, DumpRenderTreeSupportQt::defaultHixie76WebSocketProtocolEnabled());
+
+ DumpRenderTreeSupportQt::resetInternalsObject(mainFrame());
+
+ m_pendingGeolocationRequests.clear();
+}
+
+QWebPage *WebPage::createWindow(QWebPage::WebWindowType)
+{
+ return m_drt->createWindow();
+}
+
+void WebPage::javaScriptAlert(QWebFrame*, const QString& message)
+{
+ if (!isTextOutputEnabled())
+ return;
+
+ fprintf(stdout, "ALERT: %s\n", message.toUtf8().constData());
+}
+
+void WebPage::requestPermission(QWebFrame* frame, QWebPage::Feature feature)
+{
+ switch (feature) {
+ case Notifications:
+ if (!m_drt->layoutTestController()->ignoreReqestForPermission())
+ setFeaturePermission(frame, feature, PermissionGrantedByUser);
+ break;
+ case Geolocation:
+ if (m_drt->layoutTestController()->isGeolocationPermissionSet())
+ if (m_drt->layoutTestController()->geolocationPermission())
+ setFeaturePermission(frame, feature, PermissionGrantedByUser);
+ else
+ setFeaturePermission(frame, feature, PermissionDeniedByUser);
+ else
+ m_pendingGeolocationRequests.append(frame);
+ break;
+ default:
+ break;
+ }
+}
+
+void WebPage::cancelPermission(QWebFrame* frame, QWebPage::Feature feature)
+{
+ switch (feature) {
+ case Geolocation:
+ m_pendingGeolocationRequests.removeOne(frame);
+ break;
+ default:
+ break;
+ }
+}
+
+void WebPage::permissionSet(QWebPage::Feature feature)
+{
+ switch (feature) {
+ case Geolocation:
+ {
+ Q_ASSERT(m_drt->layoutTestController()->isGeolocationPermissionSet());
+ foreach (QWebFrame* frame, m_pendingGeolocationRequests)
+ if (m_drt->layoutTestController()->geolocationPermission())
+ setFeaturePermission(frame, feature, PermissionGrantedByUser);
+ else
+ setFeaturePermission(frame, feature, PermissionDeniedByUser);
+
+ m_pendingGeolocationRequests.clear();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static QString urlSuitableForTestResult(const QString& url)
+{
+ if (url.isEmpty() || !url.startsWith(QLatin1String("file://")))
+ return url;
+
+ return QFileInfo(url).fileName();
+}
+
+void WebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString&)
+{
+ if (!isTextOutputEnabled())
+ return;
+
+ QString newMessage;
+ if (!message.isEmpty()) {
+ newMessage = message;
+
+ size_t fileProtocol = newMessage.indexOf(QLatin1String("file://"));
+ if (fileProtocol != -1) {
+ newMessage = newMessage.left(fileProtocol) + urlSuitableForTestResult(newMessage.mid(fileProtocol));
+ }
+ }
+
+ fprintf (stdout, "CONSOLE MESSAGE: line %d: %s\n", lineNumber, newMessage.toUtf8().constData());
+}
+
+bool WebPage::javaScriptConfirm(QWebFrame*, const QString& msg)
+{
+ if (!isTextOutputEnabled())
+ return true;
+
+ fprintf(stdout, "CONFIRM: %s\n", msg.toUtf8().constData());
+ return true;
+}
+
+bool WebPage::javaScriptPrompt(QWebFrame*, const QString& msg, const QString& defaultValue, QString* result)
+{
+ if (!isTextOutputEnabled())
+ return true;
+
+ fprintf(stdout, "PROMPT: %s, default text: %s\n", msg.toUtf8().constData(), defaultValue.toUtf8().constData());
+ *result = defaultValue;
+ return true;
+}
+
+bool WebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type)
+{
+ if (m_drt->layoutTestController()->waitForPolicy())
+ m_drt->layoutTestController()->notifyDone();
+
+ return QWebPage::acceptNavigationRequest(frame, request, type);
+}
+
+bool WebPage::supportsExtension(QWebPage::Extension extension) const
+{
+ if (extension == QWebPage::ErrorPageExtension)
+ return m_drt->layoutTestController()->shouldHandleErrorPages();
+
+ return false;
+}
+
+bool WebPage::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
+{
+ const QWebPage::ErrorPageExtensionOption* info = static_cast<const QWebPage::ErrorPageExtensionOption*>(option);
+
+ // Lets handle error pages for the main frame for now.
+ if (info->frame != mainFrame())
+ return false;
+
+ QWebPage::ErrorPageExtensionReturn* errorPage = static_cast<QWebPage::ErrorPageExtensionReturn*>(output);
+
+ errorPage->content = QString("data:text/html,<body/>").toUtf8();
+
+ return true;
+}
+
+QObject* WebPage::createPlugin(const QString& classId, const QUrl& url, const QStringList& paramNames, const QStringList& paramValues)
+{
+ Q_UNUSED(url);
+ Q_UNUSED(paramNames);
+ Q_UNUSED(paramValues);
+#ifndef QT_NO_UITOOLS
+ QUiLoader loader;
+ return loader.createWidget(classId, view());
+#else
+ Q_UNUSED(classId);
+ return 0;
+#endif
+}
+
+void WebPage::setViewGeometry(const QRect& rect)
+{
+ if (WebViewGraphicsBased* v = qobject_cast<WebViewGraphicsBased*>(view()))
+ v->scene()->setSceneRect(QRectF(rect));
+ else if (QWidget *v = view())
+ v->setGeometry(rect);
+}
+
+WebViewGraphicsBased::WebViewGraphicsBased(QWidget* parent)
+ : m_item(new QGraphicsWebView)
+{
+ setScene(new QGraphicsScene(this));
+ scene()->addItem(m_item);
+}
+
+DumpRenderTree::DumpRenderTree()
+ : m_dumpPixels(false)
+ , m_stdin(0)
+ , m_enableTextOutput(false)
+ , m_standAloneMode(false)
+ , m_graphicsBased(false)
+ , m_persistentStoragePath(QString(getenv("DUMPRENDERTREE_TEMP")))
+{
+ QByteArray viewMode = getenv("QT_DRT_WEBVIEW_MODE");
+ if (viewMode == "graphics")
+ setGraphicsBased(true);
+
+ DumpRenderTreeSupportQt::initialize();
+
+ // Set running in DRT mode for qwebpage to create testable objects.
+ DumpRenderTreeSupportQt::setDumpRenderTreeModeEnabled(true);
+ DumpRenderTreeSupportQt::overwritePluginDirectories();
+ QWebSettings::enablePersistentStorage(m_persistentStoragePath);
+
+ m_networkAccessManager = new NetworkAccessManager(this);
+ // create our primary testing page/view.
+ if (isGraphicsBased()) {
+ WebViewGraphicsBased* view = new WebViewGraphicsBased(0);
+ m_page = new WebPage(view, this);
+ view->setPage(m_page);
+ m_mainView = view;
+ } else {
+ QWebView* view = new QWebView(0);
+ m_page = new WebPage(view, this);
+ view->setPage(m_page);
+ m_mainView = view;
+ }
+ // Use a frame group name for all pages created by DumpRenderTree to allow
+ // testing of cross-page frame lookup.
+ DumpRenderTreeSupportQt::webPageSetGroupName(m_page, "org.webkit.qt.DumpRenderTree");
+
+ m_mainView->setContextMenuPolicy(Qt::NoContextMenu);
+ m_mainView->resize(QSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight));
+
+ // clean up cache by resetting quota.
+ qint64 quota = webPage()->settings()->offlineWebApplicationCacheQuota();
+ webPage()->settings()->setOfflineWebApplicationCacheQuota(quota);
+
+ // create our controllers. This has to be done before connectFrame,
+ // as it exports there to the JavaScript DOM window.
+ m_controller = new LayoutTestController(this);
+ connect(m_controller, SIGNAL(showPage()), this, SLOT(showPage()));
+ connect(m_controller, SIGNAL(hidePage()), this, SLOT(hidePage()));
+
+ // async geolocation permission set by controller
+ connect(m_controller, SIGNAL(geolocationPermissionSet()), this, SLOT(geolocationPermissionSet()));
+
+ connect(m_controller, SIGNAL(done()), this, SLOT(dump()));
+ m_eventSender = new EventSender(m_page);
+ m_textInputController = new TextInputController(m_page);
+ m_plainTextController = new PlainTextController(m_page);
+ m_gcController = new GCController(m_page);
+
+ // now connect our different signals
+ connect(m_page, SIGNAL(frameCreated(QWebFrame *)),
+ this, SLOT(connectFrame(QWebFrame *)));
+ connectFrame(m_page->mainFrame());
+
+ connect(m_page, SIGNAL(loadFinished(bool)),
+ m_controller, SLOT(maybeDump(bool)));
+ // We need to connect to loadStarted() because notifyDone should only
+ // dump results itself when the last page loaded in the test has finished loading.
+ connect(m_page, SIGNAL(loadStarted()),
+ m_controller, SLOT(resetLoadFinished()));
+ connect(m_page, SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested()));
+ connect(m_page, SIGNAL(printRequested(QWebFrame*)), this, SLOT(dryRunPrint(QWebFrame*)));
+
+ connect(m_page->mainFrame(), SIGNAL(titleChanged(const QString&)),
+ SLOT(titleChanged(const QString&)));
+ connect(m_page, SIGNAL(databaseQuotaExceeded(QWebFrame*,QString)),
+ this, SLOT(dumpDatabaseQuota(QWebFrame*,QString)));
+ connect(m_page, SIGNAL(applicationCacheQuotaExceeded(QWebSecurityOrigin *, quint64, quint64)),
+ this, SLOT(dumpApplicationCacheQuota(QWebSecurityOrigin *, quint64, quint64)));
+ connect(m_page, SIGNAL(statusBarMessage(const QString&)),
+ this, SLOT(statusBarMessage(const QString&)));
+
+ QObject::connect(this, SIGNAL(quit()), qApp, SLOT(quit()), Qt::QueuedConnection);
+
+ DumpRenderTreeSupportQt::setDumpRenderTreeModeEnabled(true);
+ DumpRenderTreeSupportQt::setInteractiveFormValidationEnabled(webPage(), true);
+ QFocusEvent event(QEvent::FocusIn, Qt::ActiveWindowFocusReason);
+ QApplication::sendEvent(m_mainView, &event);
+}
+
+DumpRenderTree::~DumpRenderTree()
+{
+ if (!m_redirectOutputFileName.isEmpty())
+ fclose(stdout);
+ if (!m_redirectErrorFileName.isEmpty())
+ fclose(stderr);
+ delete m_mainView;
+ delete m_stdin;
+}
+
+static void clearHistory(QWebPage* page)
+{
+ // QWebHistory::clear() leaves current page, so remove it as well by setting
+ // max item count to 0, and then setting it back to it's original value.
+
+ QWebHistory* history = page->history();
+ int itemCount = history->maximumItemCount();
+
+ history->clear();
+ history->setMaximumItemCount(0);
+ history->setMaximumItemCount(itemCount);
+}
+
+void DumpRenderTree::dryRunPrint(QWebFrame* frame)
+{
+#ifndef QT_NO_PRINTER
+ NullPrinter printer;
+ frame->print(&printer);
+#endif
+}
+
+void DumpRenderTree::resetToConsistentStateBeforeTesting(const QUrl& url)
+{
+ // reset so that any current loads are stopped
+ // NOTE: that this has to be done before the layoutTestController is
+ // reset or we get timeouts for some tests.
+ m_page->blockSignals(true);
+ m_page->triggerAction(QWebPage::Stop);
+ m_page->blockSignals(false);
+
+ QList<QWebSecurityOrigin> knownOrigins = QWebSecurityOrigin::allOrigins();
+ for (int i = 0; i < knownOrigins.size(); ++i)
+ knownOrigins[i].setDatabaseQuota(databaseDefaultQuota);
+
+ // reset the layoutTestController at this point, so that we under no
+ // circumstance dump (stop the waitUntilDone timer) during the reset
+ // of the DRT.
+ m_controller->reset();
+
+ // reset mouse clicks counter
+ m_eventSender->resetClickCount();
+
+ closeRemainingWindows();
+
+ // Call setTextSizeMultiplier(1.0) to reset TextZoomFactor and PageZoomFactor too.
+ // It should be done before resetSettings() to guarantee resetting QWebSettings::ZoomTextOnly correctly.
+ m_page->mainFrame()->setTextSizeMultiplier(1.0);
+
+ m_page->resetSettings();
+#ifndef QT_NO_UNDOSTACK
+ m_page->undoStack()->clear();
+#endif
+
+ clearHistory(m_page);
+ DumpRenderTreeSupportQt::scalePageBy(m_page->mainFrame(), 1, QPoint(0, 0));
+ DumpRenderTreeSupportQt::clearFrameName(m_page->mainFrame());
+
+ m_page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded);
+ m_page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded);
+
+ if (url.scheme() == "http" || url.scheme() == "https") {
+ // credentials may exist from previous tests.
+ m_page->setNetworkAccessManager(0);
+ delete m_networkAccessManager;
+ m_networkAccessManager = new NetworkAccessManager(this);
+ m_page->setNetworkAccessManager(m_networkAccessManager);
+ }
+
+ WorkQueue::shared()->clear();
+ WorkQueue::shared()->setFrozen(false);
+
+ DumpRenderTreeSupportQt::resetOriginAccessWhiteLists();
+
+ // Qt defaults to Windows editing behavior.
+ DumpRenderTreeSupportQt::setEditingBehavior(m_page, "win");
+
+ QLocale::setDefault(QLocale::c());
+
+ layoutTestController()->setDeveloperExtrasEnabled(true);
+#ifndef Q_OS_WINCE
+ setlocale(LC_ALL, "");
+#endif
+
+ DumpRenderTreeSupportQt::clearOpener(m_page->mainFrame());
+}
+
+static bool isGlobalHistoryTest(const QUrl& url)
+{
+ if (url.path().contains("globalhistory/"))
+ return true;
+ return false;
+}
+
+static bool isWebInspectorTest(const QUrl& url)
+{
+ if (url.path().contains("inspector/"))
+ return true;
+ return false;
+}
+
+static bool isDumpAsTextTest(const QUrl& url)
+{
+ if (url.path().contains("dumpAsText/"))
+ return true;
+ return false;
+}
+
+
+void DumpRenderTree::open(const QUrl& url)
+{
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacksPath(QFileInfo(url.toString()).path());
+ resetToConsistentStateBeforeTesting(url);
+
+ if (isWebInspectorTest(m_page->mainFrame()->url()))
+ layoutTestController()->closeWebInspector();
+
+ if (isWebInspectorTest(url))
+ layoutTestController()->showWebInspector();
+
+ if (isDumpAsTextTest(url)) {
+ layoutTestController()->dumpAsText();
+ setDumpPixels(false);
+ }
+
+ if (isGlobalHistoryTest(url))
+ layoutTestController()->dumpHistoryCallbacks();
+
+ // W3C SVG tests expect to be 480x360
+ bool isW3CTest = url.toString().contains("svg/W3C-SVG-1.1");
+ int width = isW3CTest ? 480 : LayoutTestController::maxViewWidth;
+ int height = isW3CTest ? 360 : LayoutTestController::maxViewHeight;
+ m_mainView->resize(QSize(width, height));
+ m_page->setPreferredContentsSize(QSize());
+ m_page->setViewportSize(QSize(width, height));
+
+ QFocusEvent ev(QEvent::FocusIn);
+ m_page->event(&ev);
+
+ QWebSettings::clearMemoryCaches();
+#if !(QT_VERSION <= QT_VERSION_CHECK(4, 6, 2))
+ QFontDatabase::removeAllApplicationFonts();
+#endif
+ initializeFonts();
+
+ DumpRenderTreeSupportQt::dumpFrameLoader(url.toString().contains("loading/"));
+ setTextOutputEnabled(true);
+ m_page->mainFrame()->load(url);
+}
+
+void DumpRenderTree::readLine()
+{
+ if (!m_stdin) {
+ m_stdin = new QFile;
+ m_stdin->open(stdin, QFile::ReadOnly);
+
+ if (!m_stdin->isReadable()) {
+ emit quit();
+ return;
+ }
+ }
+
+ QByteArray line = m_stdin->readLine().trimmed();
+
+ if (line.isEmpty()) {
+ emit quit();
+ return;
+ }
+
+ processLine(QString::fromLocal8Bit(line.constData(), line.length()));
+}
+
+void DumpRenderTree::processArgsLine(const QStringList &args)
+{
+ setStandAloneMode(true);
+
+ m_standAloneModeTestList = args;
+
+ QFileInfo firstEntry(m_standAloneModeTestList.first());
+ if (firstEntry.isDir()) {
+ QDir folderEntry(m_standAloneModeTestList.first());
+ QStringList supportedExt;
+ // Check for all supported extensions (from Scripts/webkitpy/layout_tests/layout_package/test_files.py).
+ supportedExt << "*.html" << "*.shtml" << "*.xml" << "*.xhtml" << "*.xhtmlmp" << "*.pl" << "*.php" << "*.svg";
+ m_standAloneModeTestList = folderEntry.entryList(supportedExt, QDir::Files);
+ for (int i = 0; i < m_standAloneModeTestList.size(); ++i)
+ m_standAloneModeTestList[i] = folderEntry.absoluteFilePath(m_standAloneModeTestList[i]);
+ }
+ connect(this, SIGNAL(ready()), this, SLOT(loadNextTestInStandAloneMode()));
+
+ if (!m_standAloneModeTestList.isEmpty()) {
+ QString first = m_standAloneModeTestList.takeFirst();
+ processLine(first);
+ }
+}
+
+void DumpRenderTree::loadNextTestInStandAloneMode()
+{
+ if (m_standAloneModeTestList.isEmpty()) {
+ emit quit();
+ return;
+ }
+ QString first = m_standAloneModeTestList.takeFirst();
+ processLine(first);
+}
+
+void DumpRenderTree::processLine(const QString &input)
+{
+ QString line = input;
+
+ m_expectedHash = QString();
+ if (m_dumpPixels) {
+ // single quote marks the pixel dump hash
+ int i = line.indexOf('\'');
+ if (i > -1) {
+ m_expectedHash = line.mid(i + 1, line.length());
+ line.remove(i, line.length());
+ }
+ }
+
+ if (line.startsWith(QLatin1String("http:"))
+ || line.startsWith(QLatin1String("https:"))
+ || line.startsWith(QLatin1String("file:"))) {
+ open(QUrl(line));
+ } else {
+ QFileInfo fi(line);
+
+ if (!fi.exists()) {
+ QDir currentDir = QDir::currentPath();
+
+ // Try to be smart about where the test is located
+ if (currentDir.dirName() == QLatin1String("LayoutTests"))
+ fi = QFileInfo(currentDir, line.replace(QRegExp(".*?LayoutTests/(.*)"), "\\1"));
+ else if (!line.contains(QLatin1String("LayoutTests")))
+ fi = QFileInfo(currentDir, line.prepend(QLatin1String("LayoutTests/")));
+
+ if (!fi.exists()) {
+ emit ready();
+ return;
+ }
+ }
+
+ open(QUrl::fromLocalFile(fi.absoluteFilePath()));
+ }
+
+ fflush(stdout);
+}
+
+void DumpRenderTree::setDumpPixels(bool dump)
+{
+ m_dumpPixels = dump;
+}
+
+void DumpRenderTree::closeRemainingWindows()
+{
+ foreach (QObject* widget, windows)
+ delete widget;
+ windows.clear();
+}
+
+void DumpRenderTree::initJSObjects()
+{
+ QWebFrame *frame = qobject_cast<QWebFrame*>(sender());
+ Q_ASSERT(frame);
+ frame->addToJavaScriptWindowObject(QLatin1String("layoutTestController"), m_controller);
+ frame->addToJavaScriptWindowObject(QLatin1String("eventSender"), m_eventSender);
+ frame->addToJavaScriptWindowObject(QLatin1String("textInputController"), m_textInputController);
+ frame->addToJavaScriptWindowObject(QLatin1String("GCController"), m_gcController);
+ frame->addToJavaScriptWindowObject(QLatin1String("plainText"), m_plainTextController);
+ DumpRenderTreeSupportQt::injectInternalsObject(frame);
+}
+
+void DumpRenderTree::showPage()
+{
+ m_mainView->show();
+ // we need a paint event but cannot process all the events
+ QPixmap pixmap(m_mainView->size());
+ m_mainView->render(&pixmap);
+}
+
+void DumpRenderTree::hidePage()
+{
+ m_mainView->hide();
+}
+
+QString DumpRenderTree::dumpFrameScrollPosition(QWebFrame* frame)
+{
+ if (!frame || !DumpRenderTreeSupportQt::hasDocumentElement(frame))
+ return QString();
+
+ QString result;
+ QPoint pos = frame->scrollPosition();
+ if (pos.x() > 0 || pos.y() > 0) {
+ QWebFrame* parent = qobject_cast<QWebFrame *>(frame->parent());
+ if (parent)
+ result.append(QString("frame '%1' ").arg(frame->title()));
+ result.append(QString("scrolled to %1,%2\n").arg(pos.x()).arg(pos.y()));
+ }
+
+ if (m_controller->shouldDumpChildFrameScrollPositions()) {
+ QList<QWebFrame*> children = frame->childFrames();
+ for (int i = 0; i < children.size(); ++i)
+ result += dumpFrameScrollPosition(children.at(i));
+ }
+ return result;
+}
+
+QString DumpRenderTree::dumpFramesAsText(QWebFrame* frame)
+{
+ if (!frame || !DumpRenderTreeSupportQt::hasDocumentElement(frame))
+ return QString();
+
+ QString result;
+ QWebFrame* parent = qobject_cast<QWebFrame*>(frame->parent());
+ if (parent) {
+ result.append(QLatin1String("\n--------\nFrame: '"));
+ result.append(frame->frameName());
+ result.append(QLatin1String("'\n--------\n"));
+ }
+
+ QString innerText = frame->toPlainText();
+ result.append(innerText);
+ result.append(QLatin1String("\n"));
+
+ if (m_controller->shouldDumpChildrenAsText()) {
+ QList<QWebFrame *> children = frame->childFrames();
+ for (int i = 0; i < children.size(); ++i)
+ result += dumpFramesAsText(children.at(i));
+ }
+
+ return result;
+}
+
+static QString dumpHistoryItem(const QWebHistoryItem& item, int indent, bool current)
+{
+ QString result;
+
+ int start = 0;
+ if (current) {
+ result.append(QLatin1String("curr->"));
+ start = 6;
+ }
+ for (int i = start; i < indent; i++)
+ result.append(' ');
+
+ QString url = item.url().toString();
+ if (url.contains("file://")) {
+ static QString layoutTestsString("/LayoutTests/");
+ static QString fileTestString("(file test):");
+
+ QString res = url.mid(url.indexOf(layoutTestsString) + layoutTestsString.length());
+ if (res.isEmpty())
+ return result;
+
+ result.append(fileTestString);
+ result.append(res);
+ } else {
+ result.append(url);
+ }
+
+ QString target = DumpRenderTreeSupportQt::historyItemTarget(item);
+ if (!target.isEmpty())
+ result.append(QString(QLatin1String(" (in frame \"%1\")")).arg(target));
+
+ if (DumpRenderTreeSupportQt::isTargetItem(item))
+ result.append(QLatin1String(" **nav target**"));
+ result.append(QLatin1String("\n"));
+
+ QMap<QString, QWebHistoryItem> children = DumpRenderTreeSupportQt::getChildHistoryItems(item);
+ foreach (QWebHistoryItem item, children)
+ result += dumpHistoryItem(item, 12, false);
+
+ return result;
+}
+
+QString DumpRenderTree::dumpBackForwardList(QWebPage* page)
+{
+ QWebHistory* history = page->history();
+
+ QString result;
+ result.append(QLatin1String("\n============== Back Forward List ==============\n"));
+
+ // FORMAT:
+ // " (file test):fast/loader/resources/click-fragment-link.html **nav target**"
+ // "curr-> (file test):fast/loader/resources/click-fragment-link.html#testfragment **nav target**"
+
+ int maxItems = history->maximumItemCount();
+
+ foreach (const QWebHistoryItem item, history->backItems(maxItems)) {
+ if (!item.isValid())
+ continue;
+ result.append(dumpHistoryItem(item, 8, false));
+ }
+
+ QWebHistoryItem item = history->currentItem();
+ if (item.isValid())
+ result.append(dumpHistoryItem(item, 8, true));
+
+ foreach (const QWebHistoryItem item, history->forwardItems(maxItems)) {
+ if (!item.isValid())
+ continue;
+ result.append(dumpHistoryItem(item, 8, false));
+ }
+
+ result.append(QLatin1String("===============================================\n"));
+ return result;
+}
+
+static const char *methodNameStringForFailedTest(LayoutTestController *controller)
+{
+ const char *errorMessage;
+ if (controller->shouldDumpAsText())
+ errorMessage = "[documentElement innerText]";
+ // FIXME: Add when we have support
+ //else if (controller->dumpDOMAsWebArchive())
+ // errorMessage = "[[mainFrame DOMDocument] webArchive]";
+ //else if (controller->dumpSourceAsWebArchive())
+ // errorMessage = "[[mainFrame dataSource] webArchive]";
+ else
+ errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";
+
+ return errorMessage;
+}
+
+void DumpRenderTree::dump()
+{
+ // Prevent any further frame load or resource load callbacks from appearing after we dump the result.
+ DumpRenderTreeSupportQt::dumpFrameLoader(false);
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(false);
+
+ QWebFrame *mainFrame = m_page->mainFrame();
+
+ if (isStandAloneMode()) {
+ QString markup = mainFrame->toHtml();
+ fprintf(stdout, "Source:\n\n%s\n", markup.toUtf8().constData());
+ }
+
+ QString mimeType = DumpRenderTreeSupportQt::responseMimeType(mainFrame);
+ if (mimeType == "text/plain")
+ m_controller->dumpAsText();
+
+ // Dump render text...
+ QString resultString;
+ if (m_controller->shouldDumpAsText())
+ resultString = dumpFramesAsText(mainFrame);
+ else {
+ resultString = mainFrame->renderTreeDump();
+ resultString += dumpFrameScrollPosition(mainFrame);
+ }
+ if (!resultString.isEmpty()) {
+ fprintf(stdout, "Content-Type: text/plain\n");
+ fprintf(stdout, "%s", resultString.toUtf8().constData());
+
+ if (m_controller->shouldDumpBackForwardList()) {
+ fprintf(stdout, "%s", dumpBackForwardList(webPage()).toUtf8().constData());
+ foreach (QObject* widget, windows) {
+ QWebPage* page = qobject_cast<QWebPage*>(widget->findChild<QWebPage*>());
+ fprintf(stdout, "%s", dumpBackForwardList(page).toUtf8().constData());
+ }
+ }
+
+ } else
+ printf("ERROR: nil result from %s", methodNameStringForFailedTest(m_controller));
+
+ // signal end of text block
+ fputs("#EOF\n", stdout);
+ fputs("#EOF\n", stderr);
+
+ // FIXME: All other ports don't dump pixels, if generatePixelResults is false.
+ if (m_dumpPixels) {
+ QImage image(m_page->viewportSize(), QImage::Format_ARGB32);
+ image.fill(Qt::white);
+ QPainter painter(&image);
+ mainFrame->render(&painter);
+ painter.end();
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ for (int row = 0; row < image.height(); ++row)
+ hash.addData(reinterpret_cast<const char*>(image.scanLine(row)), image.width() * 4);
+ QString actualHash = hash.result().toHex();
+
+ fprintf(stdout, "\nActualHash: %s\n", qPrintable(actualHash));
+
+ bool dumpImage = true;
+
+ if (!m_expectedHash.isEmpty()) {
+ Q_ASSERT(m_expectedHash.length() == 32);
+ fprintf(stdout, "\nExpectedHash: %s\n", qPrintable(m_expectedHash));
+
+ if (m_expectedHash == actualHash)
+ dumpImage = false;
+ }
+
+ if (dumpImage) {
+ image.setText("checksum", actualHash);
+
+ QBuffer buffer;
+ buffer.open(QBuffer::WriteOnly);
+ image.save(&buffer, "PNG");
+ buffer.close();
+ const QByteArray &data = buffer.data();
+
+ printf("Content-Type: %s\n", "image/png");
+ printf("Content-Length: %lu\n", static_cast<unsigned long>(data.length()));
+
+ const quint32 bytesToWriteInOneChunk = 1 << 15;
+ quint32 dataRemainingToWrite = data.length();
+ const char *ptr = data.data();
+ while (dataRemainingToWrite) {
+ quint32 bytesToWriteInThisChunk = qMin(dataRemainingToWrite, bytesToWriteInOneChunk);
+ quint32 bytesWritten = fwrite(ptr, 1, bytesToWriteInThisChunk, stdout);
+ if (bytesWritten != bytesToWriteInThisChunk)
+ break;
+ dataRemainingToWrite -= bytesWritten;
+ ptr += bytesWritten;
+ }
+ }
+
+ fflush(stdout);
+ }
+
+ puts("#EOF"); // terminate the (possibly empty) pixels block
+
+ fflush(stdout);
+ fflush(stderr);
+
+ emit ready();
+}
+
+void DumpRenderTree::titleChanged(const QString &s)
+{
+ if (m_controller->shouldDumpTitleChanges())
+ printf("TITLE CHANGED: %s\n", s.toUtf8().data());
+}
+
+void DumpRenderTree::connectFrame(QWebFrame *frame)
+{
+ connect(frame, SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(initJSObjects()));
+ connect(frame, SIGNAL(provisionalLoad()),
+ layoutTestController(), SLOT(provisionalLoad()));
+}
+
+void DumpRenderTree::dumpDatabaseQuota(QWebFrame* frame, const QString& dbName)
+{
+ if (!m_controller->shouldDumpDatabaseCallbacks())
+ return;
+ QWebSecurityOrigin origin = frame->securityOrigin();
+ printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n",
+ origin.scheme().toUtf8().data(),
+ origin.host().toUtf8().data(),
+ origin.port(),
+ dbName.toUtf8().data());
+ origin.setDatabaseQuota(databaseDefaultQuota);
+}
+
+void DumpRenderTree::dumpApplicationCacheQuota(QWebSecurityOrigin* origin, quint64 defaultOriginQuota, quint64 totalSpaceNeeded)
+{
+ if (m_controller->shouldDumpApplicationCacheDelegateCallbacks()) {
+ // For example, numbers from 30000 - 39999 will output as 30000.
+ // Rounding up or down not really matter for these tests. It's
+ // sufficient to just get a range of 10000 to determine if we were
+ // above or below a threshold.
+ quint64 truncatedSpaceNeeded = (totalSpaceNeeded / 10000) * 10000;
+ printf("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:{%s, %s, %i} totalSpaceNeeded:~%llu\n",
+ origin->scheme().toUtf8().data(),
+ origin->host().toUtf8().data(),
+ origin->port(),
+ truncatedSpaceNeeded
+ );
+ }
+
+ if (m_controller->shouldDisallowIncreaseForApplicationCacheQuota())
+ return;
+
+ origin->setApplicationCacheQuota(defaultOriginQuota);
+}
+
+void DumpRenderTree::statusBarMessage(const QString& message)
+{
+ if (!m_controller->shouldDumpStatusCallbacks())
+ return;
+
+ printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message.toUtf8().constData());
+}
+
+QWebPage *DumpRenderTree::createWindow()
+{
+ if (!m_controller->canOpenWindows())
+ return 0;
+
+ // Create a dummy container object to track the page in DRT.
+ // QObject is used instead of QWidget to prevent DRT from
+ // showing the main view when deleting the container.
+
+ QObject* container = new QObject(m_mainView);
+ // create a QWebPage we want to return
+ QWebPage* page = static_cast<QWebPage*>(new WebPage(container, this));
+ // gets cleaned up in closeRemainingWindows()
+ windows.append(container);
+
+ // connect the needed signals to the page
+ connect(page, SIGNAL(frameCreated(QWebFrame*)), this, SLOT(connectFrame(QWebFrame*)));
+ connectFrame(page->mainFrame());
+ connect(page, SIGNAL(loadFinished(bool)), m_controller, SLOT(maybeDump(bool)));
+ connect(page, SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested()));
+
+ // Use a frame group name for all pages created by DumpRenderTree to allow
+ // testing of cross-page frame lookup.
+ DumpRenderTreeSupportQt::webPageSetGroupName(page, "org.webkit.qt.DumpRenderTree");
+
+ return page;
+}
+
+void DumpRenderTree::windowCloseRequested()
+{
+ QWebPage* page = qobject_cast<QWebPage*>(sender());
+ QObject* container = page->parent();
+ windows.removeAll(container);
+ container->deleteLater();
+}
+
+int DumpRenderTree::windowCount() const
+{
+// include the main view in the count
+ return windows.count() + 1;
+}
+
+void DumpRenderTree::geolocationPermissionSet()
+{
+ m_page->permissionSet(QWebPage::Geolocation);
+}
+
+void DumpRenderTree::switchFocus(bool focused)
+{
+ QFocusEvent event((focused) ? QEvent::FocusIn : QEvent::FocusOut, Qt::ActiveWindowFocusReason);
+ if (!isGraphicsBased())
+ QApplication::sendEvent(m_mainView, &event);
+ else {
+ if (WebViewGraphicsBased* view = qobject_cast<WebViewGraphicsBased*>(m_mainView))
+ view->scene()->sendEvent(view->graphicsView(), &event);
+ }
+
+}
+
+QList<WebPage*> DumpRenderTree::getAllPages() const
+{
+ QList<WebPage*> pages;
+ pages.append(m_page);
+ foreach (QObject* widget, windows) {
+ if (WebPage* page = widget->findChild<WebPage*>())
+ pages.append(page);
+ }
+ return pages;
+}
+
+void DumpRenderTree::initializeFonts()
+{
+#if HAVE(FONTCONFIG)
+ static int numFonts = -1;
+
+ FcInit();
+
+ // Some test cases may add or remove application fonts (via @font-face).
+ // Make sure to re-initialize the font set if necessary.
+ FcFontSet* appFontSet = FcConfigGetFonts(0, FcSetApplication);
+ if (appFontSet && numFonts >= 0 && appFontSet->nfont == numFonts)
+ return;
+
+ QByteArray fontDir = getenv("WEBKIT_TESTFONTS");
+ if (fontDir.isEmpty() || !QDir(fontDir).exists()) {
+ fprintf(stderr,
+ "\n\n"
+ "----------------------------------------------------------------------\n"
+ "WEBKIT_TESTFONTS environment variable is not set correctly.\n"
+ "This variable has to point to the directory containing the fonts\n"
+ "you can clone from git://gitorious.org/qtwebkit/testfonts.git\n"
+ "----------------------------------------------------------------------\n"
+ );
+ exit(1);
+ }
+ char currentPath[PATH_MAX+1];
+ if (!getcwd(currentPath, PATH_MAX))
+ qFatal("Couldn't get current working directory");
+ QByteArray configFile = currentPath;
+ FcConfig *config = FcConfigCreate();
+ configFile += "/Tools/DumpRenderTree/qt/fonts.conf";
+ if (!FcConfigParseAndLoad (config, (FcChar8*) configFile.data(), true))
+ qFatal("Couldn't load font configuration file");
+ if (!FcConfigAppFontAddDir (config, (FcChar8*) fontDir.data()))
+ qFatal("Couldn't add font dir!");
+ FcConfigSetCurrent(config);
+
+ appFontSet = FcConfigGetFonts(config, FcSetApplication);
+ numFonts = appFontSet->nfont;
+#endif
+}
+
+}
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
new file mode 100644
index 000000000..77b6e461f
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeQt_h
+#define DumpRenderTreeQt_h
+
+#include <QList>
+#include <QNetworkAccessManager>
+#include <QObject>
+#include <QTextStream>
+#include <QSocketNotifier>
+
+#ifndef QT_NO_OPENSSL
+#include <QSslError>
+#endif
+
+#include "DumpRenderTreeSupportQt.h"
+#include <qgraphicsview.h>
+#include <qgraphicswebview.h>
+#include <qwebframe.h>
+#include <qwebinspector.h>
+#include <qwebpage.h>
+#include <qwebview.h>
+
+QT_BEGIN_NAMESPACE
+class QUrl;
+class QFile;
+QT_END_NAMESPACE
+
+class QWebFrame;
+
+class LayoutTestController;
+class DumpRenderTreeSupportQt;
+class EventSender;
+class TextInputController;
+class GCController;
+class PlainTextController;
+
+namespace WebCore {
+
+class WebPage;
+class NetworkAccessManager;
+
+class DumpRenderTree : public QObject {
+Q_OBJECT
+
+public:
+ DumpRenderTree();
+ virtual ~DumpRenderTree();
+
+ // Initialize in single-file mode.
+ void open(const QUrl& url);
+
+ void setTextOutputEnabled(bool enable) { m_enableTextOutput = enable; }
+ bool isTextOutputEnabled() { return m_enableTextOutput; }
+
+ void setGraphicsBased(bool flag) { m_graphicsBased = flag; }
+ bool isGraphicsBased() { return m_graphicsBased; }
+
+ void setDumpPixels(bool);
+
+ void closeRemainingWindows();
+ void resetToConsistentStateBeforeTesting(const QUrl&);
+
+ LayoutTestController *layoutTestController() const { return m_controller; }
+ EventSender *eventSender() const { return m_eventSender; }
+ TextInputController *textInputController() const { return m_textInputController; }
+ QString persistentStoragePath() const { return m_persistentStoragePath; }
+ NetworkAccessManager *networkAccessManager() const { return m_networkAccessManager; }
+
+ QWebPage *createWindow();
+ int windowCount() const;
+
+ void switchFocus(bool focused);
+
+ WebPage *webPage() const { return m_page; }
+ QList<WebPage*> getAllPages() const;
+
+ static void initializeFonts();
+
+ void processArgsLine(const QStringList&);
+ void setRedirectOutputFileName(const QString& fileName) { m_redirectOutputFileName = fileName; }
+ void setRedirectErrorFileName(const QString& fileName) { m_redirectErrorFileName = fileName; }
+
+public Q_SLOTS:
+ void initJSObjects();
+
+ void readLine();
+ void processLine(const QString&);
+
+ void dump();
+ void titleChanged(const QString &s);
+ void connectFrame(QWebFrame *frame);
+ void dumpDatabaseQuota(QWebFrame* frame, const QString& dbName);
+ void dumpApplicationCacheQuota(QWebSecurityOrigin* origin, quint64 defaultOriginQuota, quint64 totalSpaceNeeded);
+ void statusBarMessage(const QString& message);
+ void windowCloseRequested();
+
+Q_SIGNALS:
+ void quit();
+ void ready();
+
+private Q_SLOTS:
+ void showPage();
+ void hidePage();
+ void dryRunPrint(QWebFrame*);
+ void loadNextTestInStandAloneMode();
+ void geolocationPermissionSet();
+
+private:
+ void setStandAloneMode(bool flag) { m_standAloneMode = flag; }
+ bool isStandAloneMode() { return m_standAloneMode; }
+
+ QString dumpFramesAsText(QWebFrame* frame);
+ QString dumpBackForwardList(QWebPage* page);
+ QString dumpFrameScrollPosition(QWebFrame* frame);
+ LayoutTestController *m_controller;
+
+ bool m_dumpPixels;
+ QString m_expectedHash;
+ QStringList m_standAloneModeTestList;
+
+ WebPage *m_page;
+ QWidget* m_mainView;
+
+ EventSender *m_eventSender;
+ TextInputController *m_textInputController;
+ GCController* m_gcController;
+ PlainTextController* m_plainTextController;
+ NetworkAccessManager* m_networkAccessManager;
+
+ QFile *m_stdin;
+
+ QList<QObject*> windows;
+ bool m_enableTextOutput;
+ bool m_standAloneMode;
+ bool m_graphicsBased;
+ QString m_persistentStoragePath;
+ QString m_redirectOutputFileName;
+ QString m_redirectErrorFileName;
+};
+
+class NetworkAccessManager : public QNetworkAccessManager {
+ Q_OBJECT
+public:
+ NetworkAccessManager(QObject* parent);
+
+private slots:
+#ifndef QT_NO_OPENSSL
+ void sslErrorsEncountered(QNetworkReply*, const QList<QSslError>&);
+#endif
+};
+
+class WebPage : public QWebPage {
+ Q_OBJECT
+public:
+ WebPage(QObject* parent, DumpRenderTree*);
+ virtual ~WebPage();
+ QWebInspector* webInspector();
+ void closeWebInspector();
+
+ QWebPage *createWindow(QWebPage::WebWindowType);
+
+ void javaScriptAlert(QWebFrame *frame, const QString& message);
+ void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID);
+ bool javaScriptConfirm(QWebFrame *frame, const QString& msg);
+ bool javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result);
+
+ void resetSettings();
+
+ virtual bool supportsExtension(QWebPage::Extension extension) const;
+ virtual bool extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output);
+
+ QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&);
+
+ void permissionSet(QWebPage::Feature feature);
+
+public slots:
+ bool shouldInterruptJavaScript() { return false; }
+ void requestPermission(QWebFrame* frame, QWebPage::Feature feature);
+ void cancelPermission(QWebFrame* frame, QWebPage::Feature feature);
+
+protected:
+ bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type);
+ bool isTextOutputEnabled() { return m_drt->isTextOutputEnabled(); }
+
+private slots:
+ void setViewGeometry(const QRect&);
+
+private:
+ QWebInspector* m_webInspector;
+ QList<QWebFrame*> m_pendingGeolocationRequests;
+ DumpRenderTree *m_drt;
+};
+
+class WebViewGraphicsBased : public QGraphicsView {
+ Q_OBJECT
+
+public:
+ WebViewGraphicsBased(QWidget* parent);
+ QGraphicsWebView* graphicsView() const { return m_item; }
+ void setPage(QWebPage* page) { m_item->setPage(page); }
+
+private:
+ QGraphicsWebView* m_item;
+};
+
+}
+
+#endif
diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.cpp b/Tools/DumpRenderTree/qt/EventSenderQt.cpp
new file mode 100644
index 000000000..3e4590e7f
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.cpp
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "EventSenderQt.h"
+
+#include <QGraphicsSceneMouseEvent>
+#include <QtTest/QtTest>
+
+#define KEYCODE_DEL 127
+#define KEYCODE_BACKSPACE 8
+#define KEYCODE_LEFTARROW 0xf702
+#define KEYCODE_RIGHTARROW 0xf703
+#define KEYCODE_UPARROW 0xf700
+#define KEYCODE_DOWNARROW 0xf701
+
+// Ports like Gtk and Windows expose a different approach for their zooming
+// API if compared to Qt: they have specific methods for zooming in and out,
+// as well as a settable zoom factor, while Qt has only a 'setZoomValue' method.
+// Hence Qt DRT adopts a fixed zoom-factor (1.2) for compatibility.
+#define ZOOM_STEP 1.2
+
+#define DRT_MESSAGE_DONE (QEvent::User + 1)
+
+struct DRTEventQueue {
+ QEvent* m_event;
+ int m_delay;
+};
+
+static DRTEventQueue eventQueue[1024];
+static unsigned endOfQueue;
+static unsigned startOfQueue;
+
+EventSender::EventSender(QWebPage* parent)
+ : QObject(parent)
+{
+ m_page = parent;
+ m_mouseButtonPressed = false;
+ m_drag = false;
+ memset(eventQueue, 0, sizeof(eventQueue));
+ endOfQueue = 0;
+ startOfQueue = 0;
+ m_eventLoop = 0;
+ m_currentButton = 0;
+ resetClickCount();
+ m_page->view()->installEventFilter(this);
+ // So that we can match Scrollbar::pixelsPerLineStep() in WheelEventQt.cpp and
+ // pass fast/events/platform-wheelevent-in-scrolling-div.html
+ QApplication::setWheelScrollLines(2);
+}
+
+static Qt::KeyboardModifiers getModifiers(const QStringList& modifiers)
+{
+ Qt::KeyboardModifiers modifs = 0;
+ for (int i = 0; i < modifiers.size(); ++i) {
+ const QString& m = modifiers.at(i);
+ if (m == "ctrlKey")
+ modifs |= Qt::ControlModifier;
+ else if (m == "shiftKey")
+ modifs |= Qt::ShiftModifier;
+ else if (m == "altKey")
+ modifs |= Qt::AltModifier;
+ else if (m == "metaKey")
+ modifs |= Qt::MetaModifier;
+ }
+ return modifs;
+}
+
+void EventSender::mouseDown(int button, const QStringList& modifiers)
+{
+ Qt::KeyboardModifiers modifs = getModifiers(modifiers);
+ Qt::MouseButton mouseButton;
+ switch (button) {
+ case 0:
+ mouseButton = Qt::LeftButton;
+ break;
+ case 1:
+ mouseButton = Qt::MidButton;
+ break;
+ case 2:
+ mouseButton = Qt::RightButton;
+ break;
+ case 3:
+ // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
+ mouseButton = Qt::MidButton;
+ break;
+ default:
+ mouseButton = Qt::LeftButton;
+ break;
+ }
+
+ // only consider a click to count, an event originated by the
+ // same previous button and at the same position.
+ if (m_currentButton == button
+ && m_mousePos == m_clickPos
+ && m_clickTimer.isActive())
+ m_clickCount++;
+ else
+ m_clickCount = 1;
+
+ m_currentButton = button;
+ m_clickPos = m_mousePos;
+ m_mouseButtons |= mouseButton;
+
+// qDebug() << "EventSender::mouseDown" << frame;
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneMouseEvent((m_clickCount == 2) ?
+ QEvent::GraphicsSceneMouseDoubleClick : QEvent::GraphicsSceneMousePress,
+ m_mousePos, m_mousePos, mouseButton, m_mouseButtons, modifs);
+ } else {
+ event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick :
+ QEvent::MouseButtonPress, m_mousePos, m_mousePos,
+ mouseButton, m_mouseButtons, modifs);
+ }
+
+ sendOrQueueEvent(event);
+
+ m_clickTimer.start(QApplication::doubleClickInterval(), this);
+}
+
+void EventSender::mouseUp(int button)
+{
+ Qt::MouseButton mouseButton;
+ switch (button) {
+ case 0:
+ mouseButton = Qt::LeftButton;
+ break;
+ case 1:
+ mouseButton = Qt::MidButton;
+ break;
+ case 2:
+ mouseButton = Qt::RightButton;
+ break;
+ case 3:
+ // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
+ mouseButton = Qt::MidButton;
+ break;
+ default:
+ mouseButton = Qt::LeftButton;
+ break;
+ }
+
+ m_mouseButtons &= ~mouseButton;
+
+// qDebug() << "EventSender::mouseUp" << frame;
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease,
+ m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
+ } else {
+ event = new QMouseEvent(QEvent::MouseButtonRelease,
+ m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
+ }
+
+ sendOrQueueEvent(event);
+}
+
+void EventSender::mouseMoveTo(int x, int y)
+{
+// qDebug() << "EventSender::mouseMoveTo" << x << y;
+ m_mousePos = QPoint(x, y);
+
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseMove,
+ m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
+ } else {
+ event = new QMouseEvent(QEvent::MouseMove,
+ m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
+ }
+
+ sendOrQueueEvent(event);
+}
+
+#ifndef QT_NO_WHEELEVENT
+void EventSender::mouseScrollBy(int x, int y)
+{
+ continuousMouseScrollBy((x*120), (y*120));
+}
+
+void EventSender::continuousMouseScrollBy(int x, int y)
+{
+ // continuousMouseScrollBy() mimics devices that send fine-grained scroll events where the 'delta' specified is not the usual
+ // multiple of 120. See http://doc.qt.nokia.com/4.6/qwheelevent.html#delta for a good explanation of this.
+ if (x) {
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
+ m_mousePos, m_mousePos, x, Qt::NoModifier, Qt::Horizontal);
+ } else
+ event = new QWheelEvent(m_mousePos, m_mousePos, x, m_mouseButtons, Qt::NoModifier, Qt::Horizontal);
+
+ sendOrQueueEvent(event);
+ }
+ if (y) {
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
+ m_mousePos, m_mousePos, y, Qt::NoModifier, Qt::Vertical);
+ } else
+ event = new QWheelEvent(m_mousePos, m_mousePos, y, m_mouseButtons, Qt::NoModifier, Qt::Vertical);
+
+ sendOrQueueEvent(event);
+ }
+}
+#endif
+
+void EventSender::leapForward(int ms)
+{
+ eventQueue[endOfQueue].m_delay = ms;
+ //qDebug() << "EventSender::leapForward" << ms;
+}
+
+void EventSender::keyDown(const QString& string, const QStringList& modifiers, unsigned int location)
+{
+ QString s = string;
+ Qt::KeyboardModifiers modifs = getModifiers(modifiers);
+ if (location == 3)
+ modifs |= Qt::KeypadModifier;
+ int code = 0;
+ if (string.length() == 1) {
+ code = string.unicode()->unicode();
+ //qDebug() << ">>>>>>>>> keyDown" << code << (char)code;
+ // map special keycodes used by the tests to something that works for Qt/X11
+ if (code == '\r') {
+ code = Qt::Key_Return;
+ } else if (code == '\t') {
+ code = Qt::Key_Tab;
+ if (modifs == Qt::ShiftModifier)
+ code = Qt::Key_Backtab;
+ s = QString();
+ } else if (code == KEYCODE_DEL || code == KEYCODE_BACKSPACE) {
+ code = Qt::Key_Backspace;
+ if (modifs == Qt::AltModifier)
+ modifs = Qt::ControlModifier;
+ s = QString();
+ } else if (code == 'o' && modifs == Qt::ControlModifier) {
+ // Mimic the emacs ctrl-o binding on Mac by inserting a paragraph
+ // separator and then putting the cursor back to its original
+ // position. Allows us to pass emacs-ctrl-o.html
+ s = QLatin1String("\n");
+ code = '\n';
+ modifs = 0;
+ QKeyEvent event(QEvent::KeyPress, code, modifs, s);
+ sendEvent(m_page, &event);
+ QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
+ sendEvent(m_page, &event2);
+ s = QString();
+ code = Qt::Key_Left;
+ } else if (code == 'y' && modifs == Qt::ControlModifier) {
+ s = QLatin1String("c");
+ code = 'c';
+ } else if (code == 'k' && modifs == Qt::ControlModifier) {
+ s = QLatin1String("x");
+ code = 'x';
+ } else if (code == 'a' && modifs == Qt::ControlModifier) {
+ s = QString();
+ code = Qt::Key_Home;
+ modifs = 0;
+ } else if (code == KEYCODE_LEFTARROW) {
+ s = QString();
+ code = Qt::Key_Left;
+ if (modifs & Qt::MetaModifier) {
+ code = Qt::Key_Home;
+ modifs &= ~Qt::MetaModifier;
+ }
+ } else if (code == KEYCODE_RIGHTARROW) {
+ s = QString();
+ code = Qt::Key_Right;
+ if (modifs & Qt::MetaModifier) {
+ code = Qt::Key_End;
+ modifs &= ~Qt::MetaModifier;
+ }
+ } else if (code == KEYCODE_UPARROW) {
+ s = QString();
+ code = Qt::Key_Up;
+ if (modifs & Qt::MetaModifier) {
+ code = Qt::Key_PageUp;
+ modifs &= ~Qt::MetaModifier;
+ }
+ } else if (code == KEYCODE_DOWNARROW) {
+ s = QString();
+ code = Qt::Key_Down;
+ if (modifs & Qt::MetaModifier) {
+ code = Qt::Key_PageDown;
+ modifs &= ~Qt::MetaModifier;
+ }
+ } else if (code == 'a' && modifs == Qt::ControlModifier) {
+ s = QString();
+ code = Qt::Key_Home;
+ modifs = 0;
+ } else
+ code = string.unicode()->toUpper().unicode();
+ } else {
+ //qDebug() << ">>>>>>>>> keyDown" << string;
+
+ if (string.startsWith(QLatin1Char('F')) && string.count() <= 3) {
+ s = s.mid(1);
+ int functionKey = s.toInt();
+ Q_ASSERT(functionKey >= 1 && functionKey <= 35);
+ code = Qt::Key_F1 + (functionKey - 1);
+ // map special keycode strings used by the tests to something that works for Qt/X11
+ } else if (string == QLatin1String("leftArrow")) {
+ s = QString();
+ code = Qt::Key_Left;
+ } else if (string == QLatin1String("rightArrow")) {
+ s = QString();
+ code = Qt::Key_Right;
+ } else if (string == QLatin1String("upArrow")) {
+ s = QString();
+ code = Qt::Key_Up;
+ } else if (string == QLatin1String("downArrow")) {
+ s = QString();
+ code = Qt::Key_Down;
+ } else if (string == QLatin1String("pageUp")) {
+ s = QString();
+ code = Qt::Key_PageUp;
+ } else if (string == QLatin1String("pageDown")) {
+ s = QString();
+ code = Qt::Key_PageDown;
+ } else if (string == QLatin1String("home")) {
+ s = QString();
+ code = Qt::Key_Home;
+ } else if (string == QLatin1String("end")) {
+ s = QString();
+ code = Qt::Key_End;
+ } else if (string == QLatin1String("insert")) {
+ s = QString();
+ code = Qt::Key_Insert;
+ } else if (string == QLatin1String("delete")) {
+ s = QString();
+ code = Qt::Key_Delete;
+ } else if (string == QLatin1String("printScreen")) {
+ s = QString();
+ code = Qt::Key_Print;
+ } else if (string == QLatin1String("menu")) {
+ s = QString();
+ code = Qt::Key_Menu;
+ }
+ }
+ QKeyEvent event(QEvent::KeyPress, code, modifs, s);
+ sendEvent(m_page, &event);
+ QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
+ sendEvent(m_page, &event2);
+}
+
+QStringList EventSender::contextClick()
+{
+ QMouseEvent event(QEvent::MouseButtonPress, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
+ sendEvent(m_page, &event);
+ QMouseEvent event2(QEvent::MouseButtonRelease, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
+ sendEvent(m_page, &event2);
+
+ if (isGraphicsBased()) {
+ QGraphicsSceneContextMenuEvent ctxEvent(QEvent::GraphicsSceneContextMenu);
+ ctxEvent.setReason(QGraphicsSceneContextMenuEvent::Mouse);
+ ctxEvent.setPos(m_mousePos);
+ WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view());
+ if (view)
+ sendEvent(view->graphicsView(), &ctxEvent);
+ } else {
+ QContextMenuEvent ctxEvent(QContextMenuEvent::Mouse, m_mousePos);
+ sendEvent(m_page->view(), &ctxEvent);
+ }
+ return DumpRenderTreeSupportQt::contextMenu(m_page);
+}
+
+void EventSender::scheduleAsynchronousClick()
+{
+ QMouseEvent* event = new QMouseEvent(QEvent::MouseButtonPress, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
+ postEvent(m_page, event);
+ QMouseEvent* event2 = new QMouseEvent(QEvent::MouseButtonRelease, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
+ postEvent(m_page, event2);
+}
+
+void EventSender::addTouchPoint(int x, int y)
+{
+ const int id = m_touchPoints.isEmpty() ? 0 : m_touchPoints.last().id() + 1;
+ const QPointF pos(x, y);
+ QTouchEvent::TouchPoint point(id);
+ point.setPos(pos);
+ point.setStartPos(pos);
+ point.setState(Qt::TouchPointPressed);
+ m_touchPoints.append(point);
+}
+
+void EventSender::updateTouchPoint(int index, int x, int y)
+{
+ if (index < 0 || index >= m_touchPoints.count())
+ return;
+
+ QTouchEvent::TouchPoint &p = m_touchPoints[index];
+ p.setPos(QPointF(x, y));
+ p.setState(Qt::TouchPointMoved);
+}
+
+void EventSender::setTouchModifier(const QString &modifier, bool enable)
+{
+ Qt::KeyboardModifier mod = Qt::NoModifier;
+ if (!modifier.compare(QLatin1String("shift"), Qt::CaseInsensitive))
+ mod = Qt::ShiftModifier;
+ else if (!modifier.compare(QLatin1String("alt"), Qt::CaseInsensitive))
+ mod = Qt::AltModifier;
+ else if (!modifier.compare(QLatin1String("meta"), Qt::CaseInsensitive))
+ mod = Qt::MetaModifier;
+ else if (!modifier.compare(QLatin1String("ctrl"), Qt::CaseInsensitive))
+ mod = Qt::ControlModifier;
+
+ if (enable)
+ m_touchModifiers |= mod;
+ else
+ m_touchModifiers &= ~mod;
+}
+
+void EventSender::touchStart()
+{
+ if (!m_touchActive) {
+ sendTouchEvent(QEvent::TouchBegin);
+ m_touchActive = true;
+ } else
+ sendTouchEvent(QEvent::TouchUpdate);
+}
+
+void EventSender::touchMove()
+{
+ sendTouchEvent(QEvent::TouchUpdate);
+}
+
+void EventSender::touchEnd()
+{
+ for (int i = 0; i < m_touchPoints.count(); ++i)
+ if (m_touchPoints[i].state() != Qt::TouchPointReleased) {
+ sendTouchEvent(QEvent::TouchUpdate);
+ return;
+ }
+ sendTouchEvent(QEvent::TouchEnd);
+ m_touchActive = false;
+}
+
+void EventSender::clearTouchPoints()
+{
+ m_touchPoints.clear();
+ m_touchModifiers = Qt::KeyboardModifiers();
+ m_touchActive = false;
+}
+
+void EventSender::releaseTouchPoint(int index)
+{
+ if (index < 0 || index >= m_touchPoints.count())
+ return;
+
+ m_touchPoints[index].setState(Qt::TouchPointReleased);
+}
+
+void EventSender::sendTouchEvent(QEvent::Type type)
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+ static QTouchDevice* device = 0;
+ if (!device) {
+ device = new QTouchDevice;
+ device->setType(QTouchDevice::TouchScreen);
+ QWindowSystemInterface::registerTouchDevice(device);
+ }
+
+ QTouchEvent event(type, device, m_touchModifiers);
+#else
+ QTouchEvent event(type, QTouchEvent::TouchScreen, m_touchModifiers);
+#endif
+ event.setTouchPoints(m_touchPoints);
+ sendEvent(m_page, &event);
+ QList<QTouchEvent::TouchPoint>::Iterator it = m_touchPoints.begin();
+ while (it != m_touchPoints.end()) {
+ if (it->state() == Qt::TouchPointReleased)
+ it = m_touchPoints.erase(it);
+ else {
+ it->setState(Qt::TouchPointStationary);
+ ++it;
+ }
+ }
+}
+
+void EventSender::zoomPageIn()
+{
+ if (QWebFrame* frame = m_page->mainFrame())
+ frame->setZoomFactor(frame->zoomFactor() * ZOOM_STEP);
+}
+
+void EventSender::zoomPageOut()
+{
+ if (QWebFrame* frame = m_page->mainFrame())
+ frame->setZoomFactor(frame->zoomFactor() / ZOOM_STEP);
+}
+
+void EventSender::textZoomIn()
+{
+ if (QWebFrame* frame = m_page->mainFrame())
+ frame->setTextSizeMultiplier(frame->textSizeMultiplier() * ZOOM_STEP);
+}
+
+void EventSender::textZoomOut()
+{
+ if (QWebFrame* frame = m_page->mainFrame())
+ frame->setTextSizeMultiplier(frame->textSizeMultiplier() / ZOOM_STEP);
+}
+
+void EventSender::scalePageBy(float scaleFactor, float x, float y)
+{
+ if (QWebFrame* frame = m_page->mainFrame())
+ DumpRenderTreeSupportQt::scalePageBy(frame, scaleFactor, QPoint(x, y));
+}
+
+QWebFrame* EventSender::frameUnderMouse() const
+{
+ QWebFrame* frame = m_page->mainFrame();
+
+redo:
+ QList<QWebFrame*> children = frame->childFrames();
+ for (int i = 0; i < children.size(); ++i) {
+ if (children.at(i)->geometry().contains(m_mousePos)) {
+ frame = children.at(i);
+ goto redo;
+ }
+ }
+ if (frame->geometry().contains(m_mousePos))
+ return frame;
+ return 0;
+}
+
+void EventSender::sendOrQueueEvent(QEvent* event)
+{
+ // Mouse move events are queued if
+ // 1. A previous event was queued.
+ // 2. A delay was set-up by leapForward().
+ // 3. A call to mouseMoveTo while the mouse button is pressed could initiate a drag operation, and that does not return until mouseUp is processed.
+ // To be safe and avoid a deadlock, this event is queued.
+ if (endOfQueue == startOfQueue && !eventQueue[endOfQueue].m_delay && (!(m_mouseButtonPressed && (m_eventLoop && event->type() == QEvent::MouseButtonRelease)))) {
+ sendEvent(m_page->view(), event);
+ delete event;
+ return;
+ }
+ eventQueue[endOfQueue++].m_event = event;
+ eventQueue[endOfQueue].m_delay = 0;
+ replaySavedEvents(event->type() != QEvent::MouseMove);
+}
+
+void EventSender::replaySavedEvents(bool flush)
+{
+ if (startOfQueue < endOfQueue) {
+ // First send all the events that are ready to be sent
+ while (!eventQueue[startOfQueue].m_delay && startOfQueue < endOfQueue) {
+ QEvent* ev = eventQueue[startOfQueue++].m_event;
+ postEvent(m_page->view(), ev);
+ }
+ if (startOfQueue == endOfQueue) {
+ // Reset the queue
+ startOfQueue = 0;
+ endOfQueue = 0;
+ } else {
+ QTest::qWait(eventQueue[startOfQueue].m_delay);
+ eventQueue[startOfQueue].m_delay = 0;
+ }
+ }
+ if (!flush)
+ return;
+
+ // Send a marker event, it will tell us when it is safe to exit the new event loop
+ QEvent* drtEvent = new QEvent((QEvent::Type)DRT_MESSAGE_DONE);
+ QApplication::postEvent(m_page->view(), drtEvent);
+
+ // Start an event loop for async handling of Drag & Drop
+ m_eventLoop = new QEventLoop;
+ m_eventLoop->exec();
+ delete m_eventLoop;
+ m_eventLoop = 0;
+}
+
+bool EventSender::eventFilter(QObject* watched, QEvent* event)
+{
+ if (watched != m_page->view())
+ return false;
+ switch (event->type()) {
+ case QEvent::Leave:
+ return true;
+ case QEvent::MouseButtonPress:
+ case QEvent::GraphicsSceneMousePress:
+ m_mouseButtonPressed = true;
+ break;
+ case QEvent::MouseMove:
+ case QEvent::GraphicsSceneMouseMove:
+ if (m_mouseButtonPressed)
+ m_drag = true;
+ break;
+ case QEvent::MouseButtonRelease:
+ case QEvent::GraphicsSceneMouseRelease:
+ m_mouseButtonPressed = false;
+ m_drag = false;
+ break;
+ case DRT_MESSAGE_DONE:
+ m_eventLoop->exit();
+ return true;
+ }
+ return false;
+}
+
+void EventSender::timerEvent(QTimerEvent* ev)
+{
+ m_clickTimer.stop();
+}
+
+QGraphicsSceneMouseEvent* EventSender::createGraphicsSceneMouseEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
+{
+ QGraphicsSceneMouseEvent* event;
+ event = new QGraphicsSceneMouseEvent(type);
+ event->setPos(pos);
+ event->setScreenPos(screenPos);
+ event->setButton(button);
+ event->setButtons(buttons);
+ event->setModifiers(modifiers);
+
+ return event;
+}
+
+QGraphicsSceneWheelEvent* EventSender::createGraphicsSceneWheelEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, int delta, Qt::KeyboardModifiers modifiers, Qt::Orientation orientation)
+{
+ QGraphicsSceneWheelEvent* event;
+ event = new QGraphicsSceneWheelEvent(type);
+ event->setPos(pos);
+ event->setScreenPos(screenPos);
+ event->setDelta(delta);
+ event->setModifiers(modifiers);
+ event->setOrientation(orientation);
+
+ return event;
+}
+
+void EventSender::sendEvent(QObject* receiver, QEvent* event)
+{
+ if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver))
+ view->scene()->sendEvent(view->graphicsView(), event);
+ else
+ QApplication::sendEvent(receiver, event);
+}
+
+void EventSender::postEvent(QObject* receiver, QEvent* event)
+{
+ // QGraphicsScene does not have a postEvent method, so send the event in this case
+ // and delete it after that.
+ if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver)) {
+ view->scene()->sendEvent(view->graphicsView(), event);
+ delete event;
+ } else
+ QApplication::postEvent(receiver, event); // event deleted by the system
+}
diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.h b/Tools/DumpRenderTree/qt/EventSenderQt.h
new file mode 100644
index 000000000..736818442
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 EventSenderQt_h
+#define EventSenderQt_h
+
+
+#include "DumpRenderTreeQt.h"
+
+#include <QApplication>
+#include <QBasicTimer>
+#include <QEvent>
+#include <QEventLoop>
+#include <QMouseEvent>
+#include <QObject>
+#include <QPoint>
+#include <QString>
+#include <QStringList>
+#include <QTouchEvent>
+
+#include <qwebpage.h>
+#include <qwebframe.h>
+
+
+class EventSender : public QObject {
+ Q_OBJECT
+public:
+ EventSender(QWebPage* parent);
+ virtual bool eventFilter(QObject* watched, QEvent* event);
+ void resetClickCount() { m_clickCount = 0; }
+
+public slots:
+ void mouseDown(int button = 0, const QStringList& modifiers = QStringList());
+ void mouseUp(int button = 0);
+ void mouseMoveTo(int x, int y);
+#ifndef QT_NO_WHEELEVENT
+ void mouseScrollBy(int x, int y);
+ void continuousMouseScrollBy(int x, int y);
+#endif
+ void leapForward(int ms);
+ void keyDown(const QString& string, const QStringList& modifiers = QStringList(), unsigned int location = 0);
+ void clearKillRing() {}
+ QStringList contextClick();
+ void scheduleAsynchronousClick();
+ void addTouchPoint(int x, int y);
+ void updateTouchPoint(int index, int x, int y);
+ void setTouchModifier(const QString &modifier, bool enable);
+ void touchStart();
+ void touchMove();
+ void touchEnd();
+ void zoomPageIn();
+ void zoomPageOut();
+ void textZoomIn();
+ void textZoomOut();
+ void scalePageBy(float scaleFactor, float x, float y);
+ void clearTouchPoints();
+ void releaseTouchPoint(int index);
+
+protected:
+ void timerEvent(QTimerEvent*);
+
+private:
+ bool isGraphicsBased() const { return qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view()); }
+ QGraphicsSceneMouseEvent* createGraphicsSceneMouseEvent(QEvent::Type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton, Qt::MouseButtons, Qt::KeyboardModifiers);
+ QGraphicsSceneWheelEvent* createGraphicsSceneWheelEvent(QEvent::Type, const QPoint& pos, const QPoint& screenPos, int delta, Qt::KeyboardModifiers, Qt::Orientation);
+ void sendEvent(QObject* receiver, QEvent* event);
+ void postEvent(QObject* receiver, QEvent* event);
+
+private:
+ void sendTouchEvent(QEvent::Type);
+ void sendOrQueueEvent(QEvent*);
+ void replaySavedEvents(bool flush);
+ QPoint m_mousePos;
+ QPoint m_clickPos;
+ Qt::MouseButtons m_mouseButtons;
+ QWebPage* m_page;
+ int m_clickCount;
+ int m_currentButton;
+ bool m_mouseButtonPressed;
+ bool m_drag;
+ QEventLoop* m_eventLoop;
+ QWebFrame* frameUnderMouse() const;
+ QBasicTimer m_clickTimer;
+ QList<QTouchEvent::TouchPoint> m_touchPoints;
+ Qt::KeyboardModifiers m_touchModifiers;
+ bool m_touchActive;
+};
+#endif // EventSenderQt_h
diff --git a/Tools/DumpRenderTree/qt/GCControllerQt.cpp b/Tools/DumpRenderTree/qt/GCControllerQt.cpp
new file mode 100644
index 000000000..a2e5e0c85
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/GCControllerQt.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "GCControllerQt.h"
+#include "DumpRenderTreeSupportQt.h"
+
+#include <qwebpage.h>
+
+GCController::GCController(QWebPage* parent)
+ : QObject(parent)
+{
+}
+
+void GCController::collect() const
+{
+ DumpRenderTreeSupportQt::garbageCollectorCollect();
+}
+
+void GCController::collectOnAlternateThread(bool waitUntilDone) const
+{
+ DumpRenderTreeSupportQt::garbageCollectorCollectOnAlternateThread(waitUntilDone);
+}
+
+unsigned int GCController::getJSObjectCount() const
+{
+ return DumpRenderTreeSupportQt::javaScriptObjectsCount();
+}
diff --git a/Tools/DumpRenderTree/qt/GCControllerQt.h b/Tools/DumpRenderTree/qt/GCControllerQt.h
new file mode 100644
index 000000000..d3c83b9fe
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/GCControllerQt.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 GCControllerQt_h
+#define GCControllerQt_h
+
+#include <QObject>
+
+class QWebPage;
+class DumpRenderTreeSupportQt;
+
+class GCController : public QObject
+{
+ Q_OBJECT
+public:
+ GCController(QWebPage* parent);
+
+public slots:
+ void collect() const;
+ void collectOnAlternateThread(bool waitUntilDone) const;
+ unsigned int getJSObjectCount() const;
+
+};
+
+#endif
diff --git a/Tools/DumpRenderTree/qt/ImageDiff.cpp b/Tools/DumpRenderTree/qt/ImageDiff.cpp
new file mode 100644
index 000000000..a1da2e026
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/ImageDiff.cpp
@@ -0,0 +1,151 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <QtCore/qmath.h>
+
+#include <QApplication>
+#include <QBuffer>
+#include <QByteArray>
+#include <QImage>
+#include <QStringList>
+
+#include <stdio.h>
+
+int main(int argc, char* argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ qreal tolerance = 0;
+
+ QStringList args = app.arguments();
+ for (int i = 0; i < argc; ++i)
+ if (args[i] == "-t" || args[i] == "--tolerance")
+ tolerance = args[i + 1].toDouble();
+
+ char buffer[2048];
+ QImage actualImage;
+ QImage baselineImage;
+
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ // remove the CR
+ char* newLineCharacter = strchr(buffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (!strncmp("Content-Length: ", buffer, 16)) {
+ strtok(buffer, " ");
+ int imageSize = strtol(strtok(0, " "), 0, 10);
+
+ if (imageSize <= 0) {
+ fputs("error, image size must be specified.\n", stdout);
+ } else {
+ unsigned char buffer[2048];
+ QBuffer data;
+
+ // Read all the incoming chunks
+ data.open(QBuffer::WriteOnly);
+ while (imageSize > 0) {
+ size_t bytesToRead = qMin(imageSize, 2048);
+ size_t bytesRead = fread(buffer, 1, bytesToRead, stdin);
+ data.write(reinterpret_cast<const char*>(buffer), bytesRead);
+ imageSize -= static_cast<int>(bytesRead);
+ }
+
+ // Convert into QImage
+ QImage decodedImage;
+ decodedImage.loadFromData(data.data(), "PNG");
+ decodedImage.convertToFormat(QImage::Format_ARGB32);
+
+ // Place it in the right place
+ if (actualImage.isNull())
+ actualImage = decodedImage;
+ else
+ baselineImage = decodedImage;
+ }
+ }
+
+ if (!actualImage.isNull() && !baselineImage.isNull()) {
+
+ if (actualImage.size() != baselineImage.size()) {
+ fprintf(stderr, "error, test and reference image have different properties.\n");
+ fflush(stderr);
+ } else {
+
+ int w = actualImage.width();
+ int h = actualImage.height();
+ QImage diffImage(w, h, QImage::Format_ARGB32);
+
+ int count = 0;
+ qreal sum = 0;
+ qreal maxDistance = 0;
+
+ for (int x = 0; x < w; ++x)
+ for (int y = 0; y < h; ++y) {
+ QRgb pixel = actualImage.pixel(x, y);
+ QRgb basePixel = baselineImage.pixel(x, y);
+ qreal red = (qRed(pixel) - qRed(basePixel)) / static_cast<float>(qMax(255 - qRed(basePixel), qRed(basePixel)));
+ qreal green = (qGreen(pixel) - qGreen(basePixel)) / static_cast<float>(qMax(255 - qGreen(basePixel), qGreen(basePixel)));
+ qreal blue = (qBlue(pixel) - qBlue(basePixel)) / static_cast<float>(qMax(255 - qBlue(basePixel), qBlue(basePixel)));
+ qreal alpha = (qAlpha(pixel) - qAlpha(basePixel)) / static_cast<float>(qMax(255 - qAlpha(basePixel), qAlpha(basePixel)));
+ qreal distance = qSqrt(red * red + green * green + blue * blue + alpha * alpha) / 2.0f;
+ int gray = distance * qreal(255);
+ diffImage.setPixel(x, y, qRgb(gray, gray, gray));
+ if (distance >= 1 / qreal(255)) {
+ count++;
+ sum += distance;
+ maxDistance = qMax(maxDistance, distance);
+ }
+ }
+
+ qreal difference = 0;
+ if (count)
+ difference = 100 * sum / static_cast<qreal>(w * h);
+ if (difference <= tolerance) {
+ difference = 0;
+ } else {
+ difference = qRound(difference * 100) / 100;
+ difference = qMax(difference, qreal(0.01));
+ }
+
+ if (!difference)
+ fprintf(stdout, "diff: %01.2f%% passed\n", difference);
+ else {
+ QBuffer buffer;
+ buffer.open(QBuffer::WriteOnly);
+ diffImage.save(&buffer, "PNG");
+ buffer.close();
+ const QByteArray &data = buffer.data();
+ printf("Content-Length: %lu\n", static_cast<unsigned long>(data.length()));
+
+ // We have to use the return value of fwrite to avoid "ignoring return value" gcc warning
+ // See https://bugs.webkit.org/show_bug.cgi?id=45384 for details.
+ if (fwrite(data.constData(), 1, data.length(), stdout)) {}
+
+ fprintf(stdout, "diff: %01.2f%% failed\n", difference);
+ }
+
+ fflush(stdout);
+ }
+ actualImage = QImage();
+ baselineImage = QImage();
+ }
+ }
+
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/qt/ImageDiff.pro b/Tools/DumpRenderTree/qt/ImageDiff.pro
new file mode 100644
index 000000000..729ec259a
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/ImageDiff.pro
@@ -0,0 +1,15 @@
+# -------------------------------------------------------------------
+# Project file for the ImageDiff binary
+#
+# See 'Tools/qmake/README' for an overview of the build system
+# -------------------------------------------------------------------
+
+TEMPLATE = app
+
+TARGET = ImageDiff
+DESTDIR = $$ROOT_BUILD_DIR/bin
+
+QT = core gui
+haveQt(5): QT += widgets
+
+SOURCES = ImageDiff.cpp
diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
new file mode 100644
index 000000000..b16511efb
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
@@ -0,0 +1,1023 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "LayoutTestControllerQt.h"
+#include "DumpRenderTreeSupportQt.h"
+
+#include "DumpRenderTreeQt.h"
+#include "WorkQueue.h"
+#include "WorkQueueItemQt.h"
+#include <QCoreApplication>
+#include <QDir>
+#include <QLocale>
+#include <qwebsettings.h>
+
+LayoutTestController::LayoutTestController(WebCore::DumpRenderTree* drt)
+ : QObject()
+ , m_drt(drt)
+{
+ reset();
+ DumpRenderTreeSupportQt::dumpNotification(true);
+}
+
+void LayoutTestController::reset()
+{
+ m_hasDumped = false;
+ m_loadFinished = false;
+ m_textDump = false;
+ m_dumpBackForwardList = false;
+ m_dumpChildrenAsText = false;
+ m_dumpChildFrameScrollPositions = false;
+ m_canOpenWindows = false;
+ m_waitForDone = false;
+ m_disallowIncreaseForApplicationCacheQuota = false;
+ m_dumpTitleChanges = false;
+ m_dumpDatabaseCallbacks = false;
+ m_dumpApplicationCacheDelegateCallbacks = false;
+ m_dumpStatusCallbacks = false;
+ m_timeoutTimer.stop();
+ m_topLoadingFrame = 0;
+ m_waitForPolicy = false;
+ m_handleErrorPages = false;
+ m_webHistory = 0;
+ m_globalFlag = false;
+ m_userStyleSheetEnabled = false;
+ m_desktopNotificationAllowedOrigins.clear();
+ m_ignoreDesktopNotification = false;
+ m_isGeolocationPermissionSet = false;
+ m_isPrinting = false;
+ m_geolocationPermission = false;
+
+ DumpRenderTreeSupportQt::dumpEditingCallbacks(false);
+ DumpRenderTreeSupportQt::dumpFrameLoader(false);
+ DumpRenderTreeSupportQt::dumpProgressFinishedCallback(false);
+ DumpRenderTreeSupportQt::dumpUserGestureInFrameLoader(false);
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(false);
+ DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(false);
+ DumpRenderTreeSupportQt::dumpWillCacheResponseCallbacks(false);
+ DumpRenderTreeSupportQt::setDeferMainResourceDataLoad(true);
+ DumpRenderTreeSupportQt::setWillSendRequestReturnsNullOnRedirect(false);
+ DumpRenderTreeSupportQt::setWillSendRequestReturnsNull(false);
+ DumpRenderTreeSupportQt::setWillSendRequestClearHeaders(QStringList());
+ DumpRenderTreeSupportQt::clearScriptWorlds();
+ DumpRenderTreeSupportQt::setCustomPolicyDelegate(false, false);
+ DumpRenderTreeSupportQt::dumpHistoryCallbacks(false);
+ DumpRenderTreeSupportQt::dumpVisitedLinksCallbacks(false);
+ DumpRenderTreeSupportQt::resetGeolocationMock(m_drt->webPage());
+ setIconDatabaseEnabled(false);
+ clearAllDatabases();
+#if QT_VERSION >= 0x040800
+ // The default state for DRT is to block third-party cookies, mimicing the Mac port
+ setAlwaysAcceptCookies(false);
+#endif
+ emit hidePage();
+}
+
+void LayoutTestController::processWork()
+{
+ // qDebug() << ">>>processWork";
+
+ // if we didn't start a new load, then we finished all the commands, so we're ready to dump state
+ if (WorkQueue::shared()->processWork() && !shouldWaitUntilDone()) {
+ emit done();
+ m_hasDumped = true;
+ }
+}
+
+// Called on loadFinished on WebPage
+void LayoutTestController::maybeDump(bool /*success*/)
+{
+
+ // This can happen on any of the http/tests/security/window-events-*.html tests, where the test opens
+ // a new window, calls the unload and load event handlers on the window's page, and then immediately
+ // issues a notifyDone. Needs investigation.
+ if (!m_topLoadingFrame)
+ return;
+
+ // It is possible that we get called by windows created from the main page that have finished
+ // loading, so we don't ASSERT here. At the moment we do not gather results from such windows,
+ // but may need to in future.
+ if (sender() != m_topLoadingFrame->page())
+ return;
+
+ m_loadFinished = true;
+ // as the function is called on loadFinished, the test might
+ // already have dumped and thus no longer be active, thus
+ // bail out here.
+ if (m_hasDumped)
+ return;
+
+ WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
+ if (WorkQueue::shared()->count())
+ QTimer::singleShot(0, this, SLOT(processWork()));
+ else if (!shouldWaitUntilDone()) {
+ emit done();
+ m_hasDumped = true;
+ }
+}
+
+void LayoutTestController::waitUntilDone()
+{
+ //qDebug() << ">>>>waitForDone";
+ m_waitForDone = true;
+ m_timeoutTimer.start(30000, this);
+}
+
+QString LayoutTestController::counterValueForElementById(const QString& id)
+{
+ return DumpRenderTreeSupportQt::counterValueForElementById(m_drt->webPage()->mainFrame(), id);
+}
+
+void LayoutTestController::setViewModeMediaFeature(const QString& mode)
+{
+ m_drt->webPage()->setProperty("_q_viewMode", mode);
+}
+
+int LayoutTestController::webHistoryItemCount()
+{
+ if (!m_webHistory)
+ return -1;
+
+ // Subtract one here as our QWebHistory::count() includes the actual page,
+ // which is not considered in the DRT tests.
+ return m_webHistory->count() - 1;
+}
+
+void LayoutTestController::keepWebHistory()
+{
+ m_webHistory = m_drt->webPage()->history();
+}
+
+void LayoutTestController::notifyDone()
+{
+ qDebug() << ">>>>notifyDone";
+
+ if (!m_timeoutTimer.isActive())
+ return;
+
+ m_timeoutTimer.stop();
+ m_waitForDone = false;
+
+ // If the page has not finished loading (i.e. loadFinished() has not been emitted) then
+ // content created by the likes of document.write() JS methods will not be available yet.
+ // When the page has finished loading, maybeDump above will dump the results now that we have
+ // just set shouldWaitUntilDone to false.
+ if (!m_loadFinished)
+ return;
+
+ emit done();
+
+ // FIXME: investigate why always resetting these result in timeouts
+ m_hasDumped = true;
+ m_waitForPolicy = false;
+}
+
+int LayoutTestController::windowCount()
+{
+ return m_drt->windowCount();
+}
+
+void LayoutTestController::grantDesktopNotificationPermission(const QString& origin)
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ m_drt->webPage()->setFeaturePermission(frame, QWebPage::Notifications, QWebPage::PermissionGrantedByUser);
+ m_desktopNotificationAllowedOrigins.append(origin);
+}
+
+void LayoutTestController::ignoreDesktopNotificationPermissionRequests()
+{
+ m_ignoreDesktopNotification = true;
+}
+
+bool LayoutTestController::checkDesktopNotificationPermission(const QString& origin)
+{
+ return !m_ignoreDesktopNotification && m_desktopNotificationAllowedOrigins.contains(origin);
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(const QString& title)
+{
+ DumpRenderTreeSupportQt::simulateDesktopNotificationClick(title);
+}
+
+void LayoutTestController::display()
+{
+ emit showPage();
+}
+
+void LayoutTestController::displayInvalidatedRegion()
+{
+ display();
+}
+
+void LayoutTestController::clearBackForwardList()
+{
+ m_drt->webPage()->history()->clear();
+}
+
+QString LayoutTestController::pathToLocalResource(const QString& url)
+{
+ QString localTmpUrl(QLatin1String("file:///tmp/LayoutTests"));
+
+ // Translate a request for /tmp/LayoutTests to the repository LayoutTests directory.
+ // Do not rely on a symlink to be created via the test runner, which will not work on Windows.
+ if (url.startsWith(localTmpUrl)) {
+ // DumpRenderTree lives in WebKit/WebKitBuild/<build_mode>/bin.
+ // Translate from WebKit/WebKitBuild/Release/bin => WebKit/LayoutTests.
+ QFileInfo layoutTestsRoot(QCoreApplication::applicationDirPath() + QLatin1String("/../../../LayoutTests/"));
+ if (layoutTestsRoot.exists())
+ return QLatin1String("file://") + layoutTestsRoot.absolutePath() + url.mid(localTmpUrl.length());
+ }
+
+ return url;
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int deviceDPI, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight)
+{
+ QString res = DumpRenderTreeSupportQt::viewportAsText(m_drt->webPage(), deviceDPI, QSize(deviceWidth, deviceHeight), QSize(availableWidth, availableHeight));
+ fputs(qPrintable(res), stdout);
+}
+
+void LayoutTestController::dumpEditingCallbacks()
+{
+ qDebug() << ">>>dumpEditingCallbacks";
+ DumpRenderTreeSupportQt::dumpEditingCallbacks(true);
+}
+
+void LayoutTestController::dumpFrameLoadCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpFrameLoader(true);
+}
+
+void LayoutTestController::dumpProgressFinishedCallback()
+{
+ DumpRenderTreeSupportQt::dumpProgressFinishedCallback(true);
+}
+
+void LayoutTestController::dumpUserGestureInFrameLoadCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpUserGestureInFrameLoader(true);
+}
+
+void LayoutTestController::dumpResourceLoadCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(true);
+}
+
+void LayoutTestController::dumpResourceResponseMIMETypes()
+{
+ DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(true);
+}
+
+void LayoutTestController::dumpWillCacheResponse()
+{
+ DumpRenderTreeSupportQt::dumpWillCacheResponseCallbacks(true);
+}
+
+void LayoutTestController::dumpHistoryCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpHistoryCallbacks(true);
+}
+
+void LayoutTestController::setWillSendRequestReturnsNullOnRedirect(bool enabled)
+{
+ DumpRenderTreeSupportQt::setWillSendRequestReturnsNullOnRedirect(enabled);
+}
+
+void LayoutTestController::setWillSendRequestReturnsNull(bool enabled)
+{
+ DumpRenderTreeSupportQt::setWillSendRequestReturnsNull(enabled);
+}
+
+void LayoutTestController::setWillSendRequestClearHeader(const QStringList& headers)
+{
+ DumpRenderTreeSupportQt::setWillSendRequestClearHeaders(headers);
+}
+
+void LayoutTestController::setDeferMainResourceDataLoad(bool defer)
+{
+ DumpRenderTreeSupportQt::setDeferMainResourceDataLoad(defer);
+}
+
+void LayoutTestController::queueBackNavigation(int howFarBackward)
+{
+ //qDebug() << ">>>queueBackNavigation" << howFarBackward;
+ for (int i = 0; i != howFarBackward; ++i)
+ WorkQueue::shared()->queue(new BackItem(1, m_drt->webPage()));
+}
+
+void LayoutTestController::queueForwardNavigation(int howFarForward)
+{
+ //qDebug() << ">>>queueForwardNavigation" << howFarForward;
+ for (int i = 0; i != howFarForward; ++i)
+ WorkQueue::shared()->queue(new ForwardItem(1, m_drt->webPage()));
+}
+
+void LayoutTestController::queueLoad(const QString& url, const QString& target)
+{
+ //qDebug() << ">>>queueLoad" << url << target;
+ QUrl mainResourceUrl = m_drt->webPage()->mainFrame()->url();
+ QString absoluteUrl = mainResourceUrl.resolved(QUrl(url)).toEncoded();
+ WorkQueue::shared()->queue(new LoadItem(absoluteUrl, target, m_drt->webPage()));
+}
+
+void LayoutTestController::queueLoadHTMLString(const QString& content, const QString& baseURL, const QString& failingURL)
+{
+ if (failingURL.isEmpty())
+ WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL, m_drt->webPage()));
+ else
+ WorkQueue::shared()->queue(new LoadAlternateHTMLStringItem(content, baseURL, failingURL, m_drt->webPage()));
+}
+
+void LayoutTestController::queueReload()
+{
+ //qDebug() << ">>>queueReload";
+ WorkQueue::shared()->queue(new ReloadItem(m_drt->webPage()));
+}
+
+void LayoutTestController::queueLoadingScript(const QString& script)
+{
+ //qDebug() << ">>>queueLoadingScript" << script;
+ WorkQueue::shared()->queue(new LoadingScriptItem(script, m_drt->webPage()));
+}
+
+void LayoutTestController::queueNonLoadingScript(const QString& script)
+{
+ //qDebug() << ">>>queueNonLoadingScript" << script;
+ WorkQueue::shared()->queue(new NonLoadingScriptItem(script, m_drt->webPage()));
+}
+
+void LayoutTestController::provisionalLoad()
+{
+ QWebFrame* frame = qobject_cast<QWebFrame*>(sender());
+ if (!m_topLoadingFrame && !m_hasDumped)
+ m_topLoadingFrame = frame;
+}
+
+void LayoutTestController::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == m_timeoutTimer.timerId()) {
+ const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
+ fprintf(stderr, "%s", message);
+ fprintf(stdout, "%s", message);
+ notifyDone();
+ } else
+ QObject::timerEvent(ev);
+}
+
+QString LayoutTestController::encodeHostName(const QString& host)
+{
+ QString encoded = QString::fromLatin1(QUrl::toAce(host + QLatin1String(".no")));
+ encoded.truncate(encoded.length() - 3); // strip .no
+ return encoded;
+}
+
+QString LayoutTestController::decodeHostName(const QString& host)
+{
+ QString decoded = QUrl::fromAce(host.toLatin1() + QByteArray(".no"));
+ decoded.truncate(decoded.length() - 3);
+ return decoded;
+}
+
+void LayoutTestController::setMediaType(const QString& type)
+{
+ DumpRenderTreeSupportQt::setMediaType(m_drt->webPage()->mainFrame(), type);
+}
+
+void LayoutTestController::closeWebInspector()
+{
+ DumpRenderTreeSupportQt::webInspectorClose(m_drt->webPage());
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, false);
+}
+
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, enabled);
+}
+
+void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool)
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::showWebInspector()
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
+ DumpRenderTreeSupportQt::webInspectorShow(m_drt->webPage());
+}
+
+void LayoutTestController::evaluateInWebInspector(long callId, const QString& script)
+{
+ DumpRenderTreeSupportQt::webInspectorExecuteScript(m_drt->webPage(), callId, script);
+}
+
+void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
+{
+ DumpRenderTreeSupportQt::setFrameFlatteningEnabled(m_drt->webPage(), enabled);
+}
+
+void LayoutTestController::goBack()
+{
+ DumpRenderTreeSupportQt::goBack(m_drt->webPage());
+}
+
+void LayoutTestController::setDefersLoading(bool flag)
+{
+ DumpRenderTreeSupportQt::setDefersLoading(m_drt->webPage(), flag);
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, enabled);
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessFileUrls, enabled);
+}
+
+void LayoutTestController::setAppCacheMaximumSize(unsigned long long quota)
+{
+ m_drt->webPage()->settings()->setOfflineWebApplicationCacheQuota(quota);
+}
+
+void LayoutTestController::setAutofilled(const QWebElement& element, bool isAutofilled)
+{
+ return DumpRenderTreeSupportQt::setAutofilled(element, isAutofilled);
+}
+
+void LayoutTestController::setJavaScriptProfilingEnabled(bool enable)
+{
+ setDeveloperExtrasEnabled(enable);
+ DumpRenderTreeSupportQt::setJavaScriptProfilingEnabled(m_topLoadingFrame, enable);
+}
+
+void LayoutTestController::setValueForUser(const QWebElement& element, const QString& value)
+{
+ DumpRenderTreeSupportQt::setValueForUser(element, value);
+}
+
+void LayoutTestController::setFixedContentsSize(int width, int height)
+{
+ m_topLoadingFrame->page()->setPreferredContentsSize(QSize(width, height));
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(bool enable)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, enable);
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool enable)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::SpatialNavigationEnabled, enable);
+}
+
+void LayoutTestController::setPopupBlockingEnabled(bool enable)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, !enable);
+}
+
+void LayoutTestController::setPluginsEnabled(bool flag)
+{
+ // FIXME: Implement
+}
+
+void LayoutTestController::setPOSIXLocale(const QString& locale)
+{
+ QLocale qlocale(locale);
+ QLocale::setDefault(qlocale);
+}
+
+void LayoutTestController::setWindowIsKey(bool isKey)
+{
+ m_drt->switchFocus(isKey);
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(bool isFirst)
+{
+ //FIXME: only need this for the moment: https://bugs.webkit.org/show_bug.cgi?id=32990
+}
+
+void LayoutTestController::setJavaScriptCanAccessClipboard(bool enable)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::JavascriptCanAccessClipboard, enable);
+}
+
+void LayoutTestController::setXSSAuditorEnabled(bool enable)
+{
+ // Set XSSAuditingEnabled globally so that windows created by the test inherit it too.
+ // resetSettings() will call this to reset the page and global setting to false again.
+ // Needed by http/tests/security/xssAuditor/link-opens-new-window.html
+ QWebSettings* globalSettings = QWebSettings::globalSettings();
+ globalSettings->setAttribute(QWebSettings::XSSAuditingEnabled, enable);
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::XSSAuditingEnabled, enable);
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const QString& animationName,
+ double time,
+ const QString& elementId)
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ return DumpRenderTreeSupportQt::pauseAnimation(frame, animationName, time, elementId);
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const QString& propertyName,
+ double time,
+ const QString& elementId)
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ return DumpRenderTreeSupportQt::pauseTransitionOfProperty(frame, propertyName, time, elementId);
+}
+
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(const QString& animationId,
+ double time,
+ const QString& elementId)
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ return DumpRenderTreeSupportQt::pauseSVGAnimation(frame, animationId, time, elementId);
+}
+
+unsigned LayoutTestController::numberOfActiveAnimations() const
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ return DumpRenderTreeSupportQt::numberOfActiveAnimations(frame);
+}
+
+void LayoutTestController::suspendAnimations() const
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ DumpRenderTreeSupportQt::suspendAnimations(frame);
+}
+
+void LayoutTestController::resumeAnimations() const
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ DumpRenderTreeSupportQt::resumeAnimations(frame);
+}
+
+void LayoutTestController::disableImageLoading()
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::AutoLoadImages, false);
+}
+
+void LayoutTestController::dispatchPendingLoadRequests()
+{
+ // FIXME: Implement for testing fix for 6727495
+}
+
+void LayoutTestController::clearAllApplicationCaches()
+{
+ DumpRenderTreeSupportQt::clearAllApplicationCaches();
+}
+
+void LayoutTestController::clearApplicationCacheForOrigin(const QString& url)
+{
+ // FIXME: Implement to support deleting all application caches for an origin.
+}
+
+long long LayoutTestController::localStorageDiskUsageForOrigin(const QString& originIdentifier)
+{
+ // FIXME: Implement to support getting disk usage in bytes for an origin.
+ return 0;
+}
+
+void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota)
+{
+ if (!m_topLoadingFrame)
+ return;
+ m_topLoadingFrame->securityOrigin().setApplicationCacheQuota(quota);
+}
+
+long long LayoutTestController::applicationCacheDiskUsageForOrigin(const QString& origin)
+{
+ // FIXME: Implement to support getting disk usage by all application caches for an origin.
+ return 0;
+}
+
+QStringList LayoutTestController::originsWithApplicationCache()
+{
+ // FIXME: Implement to get origins that have application caches.
+ return QStringList();
+}
+
+void LayoutTestController::setCacheModel(int model)
+{
+ // qwebsetting doesn't have matched setting yet :
+ // WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER
+ // WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER
+ // WEBKIT_CACHE_MODEL_WEB_BROWSER
+
+ // FIXME: Implement.
+}
+
+void LayoutTestController::setDatabaseQuota(int size)
+{
+ if (!m_topLoadingFrame)
+ return;
+ m_topLoadingFrame->securityOrigin().setDatabaseQuota(size);
+}
+
+void LayoutTestController::clearAllDatabases()
+{
+ QWebDatabase::removeAllDatabases();
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
+{
+ DumpRenderTreeSupportQt::whiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
+{
+ DumpRenderTreeSupportQt::removeWhiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
+}
+
+void LayoutTestController::setCustomPolicyDelegate(bool enabled, bool permissive)
+{
+ DumpRenderTreeSupportQt::setCustomPolicyDelegate(enabled, permissive);
+}
+
+void LayoutTestController::waitForPolicyDelegate()
+{
+ setCustomPolicyDelegate(true);
+ m_waitForPolicy = true;
+ waitUntilDone();
+}
+
+void LayoutTestController::overridePreference(const QString& name, const QVariant& value)
+{
+ QWebSettings* settings = m_topLoadingFrame->page()->settings();
+
+ if (name == "WebKitJavaScriptEnabled")
+ settings->setAttribute(QWebSettings::JavascriptEnabled, value.toBool());
+ else if (name == "WebKitTabToLinksPreferenceKey")
+ settings->setAttribute(QWebSettings::LinksIncludedInFocusChain, value.toBool());
+ else if (name == "WebKitOfflineWebApplicationCacheEnabled")
+ settings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, value.toBool());
+ else if (name == "WebKitDefaultFontSize")
+ settings->setFontSize(QWebSettings::DefaultFontSize, value.toInt());
+ else if (name == "WebKitUsesPageCachePreferenceKey")
+ QWebSettings::setMaximumPagesInCache(value.toInt());
+ else if (name == "WebKitEnableCaretBrowsing")
+ setCaretBrowsingEnabled(value.toBool());
+ else if (name == "WebKitPluginsEnabled")
+ settings->setAttribute(QWebSettings::PluginsEnabled, value.toBool());
+ else if (name == "WebKitWebGLEnabled")
+ settings->setAttribute(QWebSettings::WebGLEnabled, value.toBool());
+ else if (name == "WebKitHyperlinkAuditingEnabled")
+ settings->setAttribute(QWebSettings::HyperlinkAuditingEnabled, value.toBool());
+ else if (name == "WebKitHixie76WebSocketProtocolEnabled")
+ DumpRenderTreeSupportQt::setHixie76WebSocketProtocolEnabled(m_topLoadingFrame->page(), value.toBool());
+ else
+ printf("ERROR: LayoutTestController::overridePreference() does not support the '%s' preference\n",
+ name.toLatin1().data());
+}
+
+void LayoutTestController::setUserStyleSheetLocation(const QString& url)
+{
+ QByteArray urlData = pathToLocalResource(url).toLatin1();
+ m_userStyleSheetLocation = QUrl::fromEncoded(urlData, QUrl::StrictMode);
+
+ if (m_userStyleSheetEnabled)
+ setUserStyleSheetEnabled(true);
+}
+
+void LayoutTestController::setCaretBrowsingEnabled(bool value)
+{
+ DumpRenderTreeSupportQt::setCaretBrowsingEnabled(m_drt->webPage(), value);
+}
+
+void LayoutTestController::setAuthorAndUserStylesEnabled(bool value)
+{
+ DumpRenderTreeSupportQt::setAuthorAndUserStylesEnabled(m_drt->webPage(), value);
+}
+
+void LayoutTestController::setUserStyleSheetEnabled(bool enabled)
+{
+ m_userStyleSheetEnabled = enabled;
+
+ if (enabled)
+ m_drt->webPage()->settings()->setUserStyleSheetUrl(m_userStyleSheetLocation);
+ else
+ m_drt->webPage()->settings()->setUserStyleSheetUrl(QUrl());
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme)
+{
+ DumpRenderTreeSupportQt::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
+}
+
+int LayoutTestController::workerThreadCount()
+{
+ return DumpRenderTreeSupportQt::workerThreadCount();
+}
+
+int LayoutTestController::pageNumberForElementById(const QString& id, float width, float height)
+{
+ // If no size specified, webpage viewport size is used
+ if (!width && !height) {
+ width = m_drt->webPage()->viewportSize().width();
+ height = m_drt->webPage()->viewportSize().height();
+ }
+
+ return DumpRenderTreeSupportQt::pageNumberForElementById(m_drt->webPage()->mainFrame(), id, width, height);
+}
+
+int LayoutTestController::numberOfPages(float width, float height)
+{
+ return DumpRenderTreeSupportQt::numberOfPages(m_drt->webPage()->mainFrame(), width, height);
+}
+
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ return DumpRenderTreeSupportQt::shouldClose(m_drt->webPage()->mainFrame());
+}
+
+void LayoutTestController::setScrollbarPolicy(const QString& orientation, const QString& policy)
+{
+ Qt::Orientation o;
+ Qt::ScrollBarPolicy p;
+
+ if (orientation == "vertical")
+ o = Qt::Vertical;
+ else if (orientation == "horizontal")
+ o = Qt::Horizontal;
+ else
+ return;
+
+ if (policy == "on")
+ p = Qt::ScrollBarAlwaysOn;
+ else if (policy == "auto")
+ p = Qt::ScrollBarAsNeeded;
+ else if (policy == "off")
+ p = Qt::ScrollBarAlwaysOff;
+ else
+ return;
+
+ m_drt->webPage()->mainFrame()->setScrollBarPolicy(o, p);
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(bool enable)
+{
+ DumpRenderTreeSupportQt::setSmartInsertDeleteEnabled(m_drt->webPage(), enable);
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool enable)
+{
+ DumpRenderTreeSupportQt::setSelectTrailingWhitespaceEnabled(m_drt->webPage(), enable);
+}
+
+void LayoutTestController::execCommand(const QString& name, const QString& value)
+{
+ DumpRenderTreeSupportQt::executeCoreCommandByName(m_drt->webPage(), name, value);
+}
+
+bool LayoutTestController::isCommandEnabled(const QString& name) const
+{
+ return DumpRenderTreeSupportQt::isCommandEnabled(m_drt->webPage(), name);
+}
+
+bool LayoutTestController::findString(const QString& string, const QStringList& optionArray)
+{
+ return DumpRenderTreeSupportQt::findString(m_drt->webPage(), string, optionArray);
+}
+
+QString LayoutTestController::markerTextForListItem(const QWebElement& listItem)
+{
+ return DumpRenderTreeSupportQt::markerTextForListItem(listItem);
+}
+
+QVariantMap LayoutTestController::computedStyleIncludingVisitedInfo(const QWebElement& element) const
+{
+ return DumpRenderTreeSupportQt::computedStyleIncludingVisitedInfo(element);
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(const QString& elementId)
+{
+ return DumpRenderTreeSupportQt::elementDoesAutoCompleteForElementWithId(m_drt->webPage()->mainFrame(), elementId);
+}
+
+void LayoutTestController::authenticateSession(const QString&, const QString&, const QString&)
+{
+ // FIXME: If there is a concept per-session (per-process) credential storage, the credentials should be added to it for later use.
+}
+
+void LayoutTestController::setIconDatabaseEnabled(bool enable)
+{
+ if (enable && !m_drt->persistentStoragePath().isEmpty())
+ QWebSettings::setIconDatabasePath(m_drt->persistentStoragePath());
+ else
+ QWebSettings::setIconDatabasePath(QString());
+}
+
+void LayoutTestController::setEditingBehavior(const QString& editingBehavior)
+{
+ DumpRenderTreeSupportQt::setEditingBehavior(m_drt->webPage(), editingBehavior);
+}
+
+void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
+{
+ QList<WebCore::WebPage*> pages = m_drt->getAllPages();
+ foreach (WebCore::WebPage* page, pages)
+ DumpRenderTreeSupportQt::setMockDeviceOrientation(page, canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma);
+}
+
+void LayoutTestController::setGeolocationPermission(bool allow)
+{
+ setGeolocationPermissionCommon(allow);
+ QList<WebCore::WebPage*> pages = m_drt->getAllPages();
+ foreach (WebCore::WebPage* page, pages)
+ DumpRenderTreeSupportQt::setMockGeolocationPermission(page, allow);
+}
+
+int LayoutTestController::numberOfPendingGeolocationPermissionRequests()
+{
+ int pendingPermissionCount = 0;
+ QList<WebCore::WebPage*> pages = m_drt->getAllPages();
+ foreach (WebCore::WebPage* page, pages)
+ pendingPermissionCount += DumpRenderTreeSupportQt::numberOfPendingGeolocationPermissionRequests(page);
+
+ return pendingPermissionCount;
+}
+
+void LayoutTestController::setGeolocationPermissionCommon(bool allow)
+{
+ m_isGeolocationPermissionSet = true;
+ m_geolocationPermission = allow;
+}
+
+void LayoutTestController::setMockGeolocationError(int code, const QString& message)
+{
+ QList<WebCore::WebPage*> pages = m_drt->getAllPages();
+ foreach (WebCore::WebPage* page, pages)
+ DumpRenderTreeSupportQt::setMockGeolocationError(page, code, message);
+}
+
+void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
+{
+ QList<WebCore::WebPage*> pages = m_drt->getAllPages();
+ foreach (WebCore::WebPage* page, pages)
+ DumpRenderTreeSupportQt::setMockGeolocationPosition(page, latitude, longitude, accuracy);
+}
+
+void LayoutTestController::addMockSpeechInputResult(const QString& result, double confidence, const QString& language)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::startSpeechInput(const QString& inputElement)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(int worldID, const QString& script)
+{
+ DumpRenderTreeSupportQt::evaluateScriptInIsolatedWorld(m_drt->webPage()->mainFrame(), worldID, script);
+}
+
+bool LayoutTestController::isPageBoxVisible(int pageIndex)
+{
+ return DumpRenderTreeSupportQt::isPageBoxVisible(m_drt->webPage()->mainFrame(), pageIndex);
+}
+
+QString LayoutTestController::pageSizeAndMarginsInPixels(int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft)
+{
+ return DumpRenderTreeSupportQt::pageSizeAndMarginsInPixels(m_drt->webPage()->mainFrame(), pageIndex,
+ width, height, marginTop, marginRight, marginBottom, marginLeft);
+}
+
+QString LayoutTestController::pageProperty(const QString& propertyName, int pageNumber)
+{
+ return DumpRenderTreeSupportQt::pageProperty(m_drt->webPage()->mainFrame(), propertyName, pageNumber);
+}
+
+void LayoutTestController::addUserStyleSheet(const QString& sourceCode)
+{
+ DumpRenderTreeSupportQt::addUserStyleSheet(m_drt->webPage(), sourceCode);
+}
+
+void LayoutTestController::removeAllVisitedLinks()
+{
+ QWebHistory* history = m_drt->webPage()->history();
+ history->clear();
+ DumpRenderTreeSupportQt::dumpVisitedLinksCallbacks(true);
+}
+
+bool LayoutTestController::hasSpellingMarker(int, int)
+{
+ // FIXME: Implement.
+ return false;
+}
+
+QVariantList LayoutTestController::nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping)
+{
+ return DumpRenderTreeSupportQt::nodesFromRect(document, x, y, top, right, bottom, left, ignoreClipping);
+}
+
+void LayoutTestController::addURLToRedirect(const QString& origin, const QString& destination)
+{
+ DumpRenderTreeSupportQt::addURLToRedirect(origin, destination);
+}
+
+void LayoutTestController::setMinimumTimerInterval(double minimumTimerInterval)
+{
+ DumpRenderTreeSupportQt::setMinimumTimerInterval(m_drt->webPage(), minimumTimerInterval);
+}
+
+void LayoutTestController::originsWithLocalStorage()
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::deleteAllLocalStorage()
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::deleteLocalStorageForOrigin(const QString& originIdentifier)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::observeStorageTrackerNotifications(unsigned number)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::syncLocalStorage()
+{
+ // FIXME: Implement.
+}
+
+QString LayoutTestController::layerTreeAsText()
+{
+ return DumpRenderTreeSupportQt::layerTreeAsText(m_drt->webPage()->mainFrame());
+}
+
+void LayoutTestController::setTextDirection(const QString& directionName)
+{
+ if (directionName == "auto")
+ m_drt->webPage()->triggerAction(QWebPage::SetTextDirectionDefault);
+ else if (directionName == "rtl")
+ m_drt->webPage()->triggerAction(QWebPage::SetTextDirectionRightToLeft);
+ else if (directionName == "ltr")
+ m_drt->webPage()->triggerAction(QWebPage::SetTextDirectionLeftToRight);
+}
+
+#if QT_VERSION >= 0x040800
+void LayoutTestController::setAlwaysAcceptCookies(bool accept)
+{
+ QWebSettings* globalSettings = QWebSettings::globalSettings();
+ if (accept)
+ globalSettings->setThirdPartyCookiePolicy(QWebSettings::AlwaysAllowThirdPartyCookies);
+ else {
+ // This matches the Safari third-party cookie blocking policy tested in third-party-cookie-relaxing.html
+ globalSettings->setThirdPartyCookiePolicy(QWebSettings::AllowThirdPartyWithExistingCookies);
+ }
+}
+
+void LayoutTestController::setAlwaysBlockCookies(bool block)
+{
+ QWebSettings* globalSettings = QWebSettings::globalSettings();
+ if (block)
+ globalSettings->setThirdPartyCookiePolicy(QWebSettings::AlwaysBlockThirdPartyCookies);
+ else
+ globalSettings->setThirdPartyCookiePolicy(QWebSettings::AlwaysAllowThirdPartyCookies);
+}
+#endif
+
+const unsigned LayoutTestController::maxViewWidth = 800;
+const unsigned LayoutTestController::maxViewHeight = 600;
diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h
new file mode 100644
index 000000000..b842fe4df
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 LayoutTestControllerQt_h
+#define LayoutTestControllerQt_h
+
+#include <QBasicTimer>
+#include <QObject>
+#include <QSize>
+#include <QString>
+#include <QtDebug>
+#include <QTimer>
+#include <QTimerEvent>
+#include <QVariant>
+
+#include <qwebdatabase.h>
+#include <qwebelement.h>
+#include <qwebframe.h>
+#include <qwebhistory.h>
+#include <qwebpage.h>
+#include <qwebsecurityorigin.h>
+
+class QWebFrame;
+class DumpRenderTreeSupportQt;
+namespace WebCore {
+ class DumpRenderTree;
+}
+class LayoutTestController : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(int webHistoryItemCount READ webHistoryItemCount)
+ Q_PROPERTY(int workerThreadCount READ workerThreadCount)
+ Q_PROPERTY(bool globalFlag READ globalFlag WRITE setGlobalFlag)
+public:
+ LayoutTestController(WebCore::DumpRenderTree* drt);
+
+ bool shouldDisallowIncreaseForApplicationCacheQuota() const { return m_disallowIncreaseForApplicationCacheQuota; }
+ bool shouldDumpAsText() const { return m_textDump; }
+ bool shouldDumpBackForwardList() const { return m_dumpBackForwardList; }
+ bool shouldDumpChildrenAsText() const { return m_dumpChildrenAsText; }
+ bool shouldDumpChildFrameScrollPositions() const { return m_dumpChildFrameScrollPositions; }
+ bool shouldDumpDatabaseCallbacks() const { return m_dumpDatabaseCallbacks; }
+ bool shouldDumpApplicationCacheDelegateCallbacks() const { return m_dumpApplicationCacheDelegateCallbacks; }
+ bool shouldDumpStatusCallbacks() const { return m_dumpStatusCallbacks; }
+ bool shouldWaitUntilDone() const { return m_waitForDone; }
+ bool shouldHandleErrorPages() const { return m_handleErrorPages; }
+ bool canOpenWindows() const { return m_canOpenWindows; }
+ bool shouldDumpTitleChanges() const { return m_dumpTitleChanges; }
+ bool waitForPolicy() const { return m_waitForPolicy; }
+ bool ignoreReqestForPermission() const { return m_ignoreDesktopNotification; }
+ bool isPrinting() { return m_isPrinting; }
+
+ void reset();
+
+ static const unsigned int maxViewWidth;
+ static const unsigned int maxViewHeight;
+
+protected:
+ void timerEvent(QTimerEvent*);
+
+signals:
+ void done();
+
+ void showPage();
+ void hidePage();
+ void geolocationPermissionSet();
+
+public slots:
+ void maybeDump(bool ok);
+ void disallowIncreaseForApplicationCacheQuota() { m_disallowIncreaseForApplicationCacheQuota = true; }
+ void dumpAsText() { m_textDump = true; }
+ void dumpChildFramesAsText() { m_dumpChildrenAsText = true; }
+ void dumpChildFrameScrollPositions() { m_dumpChildFrameScrollPositions = true; }
+ void dumpDatabaseCallbacks() { m_dumpDatabaseCallbacks = true; }
+ void dumpApplicationCacheDelegateCallbacks() { m_dumpApplicationCacheDelegateCallbacks = true; }
+ void dumpStatusCallbacks() { m_dumpStatusCallbacks = true; }
+ void setCanOpenWindows() { m_canOpenWindows = true; }
+ void setPrinting() { m_isPrinting = true; }
+ void waitUntilDone();
+ QString counterValueForElementById(const QString& id);
+ int webHistoryItemCount();
+ void keepWebHistory();
+ void notifyDone();
+ void dumpBackForwardList() { m_dumpBackForwardList = true; }
+ bool globalFlag() const { return m_globalFlag; }
+ void setGlobalFlag(bool flag) { m_globalFlag = flag; }
+ void handleErrorPages() { m_handleErrorPages = true; }
+ void dumpEditingCallbacks();
+ void dumpFrameLoadCallbacks();
+ void dumpProgressFinishedCallback();
+ void dumpUserGestureInFrameLoadCallbacks();
+ void dumpResourceLoadCallbacks();
+ void dumpResourceResponseMIMETypes();
+ void dumpWillCacheResponse();
+ void dumpHistoryCallbacks();
+ void dumpConfigurationForViewport(int deviceDPI, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight);
+ void setWillSendRequestReturnsNullOnRedirect(bool enabled);
+ void setWillSendRequestReturnsNull(bool enabled);
+ void setWillSendRequestClearHeader(const QStringList& headers);
+ void queueBackNavigation(int howFarBackward);
+ void queueForwardNavigation(int howFarForward);
+ void queueLoad(const QString& url, const QString& target = QString());
+ void queueLoadHTMLString(const QString& content, const QString& baseURL = QString(), const QString& failingURL = QString());
+ void queueReload();
+ void queueLoadingScript(const QString& script);
+ void queueNonLoadingScript(const QString& script);
+ void provisionalLoad();
+ void setCloseRemainingWindowsWhenComplete(bool = false) {}
+ int windowCount();
+ void grantDesktopNotificationPermission(const QString& origin);
+ void ignoreDesktopNotificationPermissionRequests();
+ bool checkDesktopNotificationPermission(const QString& origin);
+ void simulateDesktopNotificationClick(const QString& title);
+ void display();
+ void displayInvalidatedRegion();
+ void clearBackForwardList();
+ QString pathToLocalResource(const QString& url);
+ void dumpTitleChanges() { m_dumpTitleChanges = true; }
+ QString encodeHostName(const QString& host);
+ QString decodeHostName(const QString& host);
+ void dumpSelectionRect() const {}
+ void setDeveloperExtrasEnabled(bool);
+ void setAsynchronousSpellCheckingEnabled(bool);
+ void showWebInspector();
+ void closeWebInspector();
+ void evaluateInWebInspector(long callId, const QString& script);
+ void removeAllVisitedLinks();
+ void setMediaType(const QString& type);
+ void setFrameFlatteningEnabled(bool enable);
+ void setAllowUniversalAccessFromFileURLs(bool enable);
+ void setAllowFileAccessFromFileURLs(bool enable);
+ void setAppCacheMaximumSize(unsigned long long quota);
+ void setAutofilled(const QWebElement&, bool enable);
+ void setJavaScriptProfilingEnabled(bool enable);
+ void setValueForUser(const QWebElement&, const QString& value);
+ void setFixedContentsSize(int width, int height);
+ void setPrivateBrowsingEnabled(bool enable);
+ void setSpatialNavigationEnabled(bool enabled);
+ void setPluginsEnabled(bool flag);
+ void setPopupBlockingEnabled(bool enable);
+ void setPOSIXLocale(const QString& locale);
+ void resetLoadFinished() { m_loadFinished = false; }
+ void setWindowIsKey(bool isKey);
+ void setMainFrameIsFirstResponder(bool isFirst);
+ void setDeferMainResourceDataLoad(bool);
+ void setJavaScriptCanAccessClipboard(bool enable);
+ void setXSSAuditorEnabled(bool enable);
+ void setCaretBrowsingEnabled(bool enable);
+ void setAuthorAndUserStylesEnabled(bool);
+ void setViewModeMediaFeature(const QString& mode);
+ void setSmartInsertDeleteEnabled(bool enable);
+ void setSelectTrailingWhitespaceEnabled(bool enable);
+ void execCommand(const QString& name, const QString& value = QString());
+ bool isCommandEnabled(const QString& name) const;
+ bool findString(const QString& string, const QStringList& optionArray);
+
+ bool pauseAnimationAtTimeOnElementWithId(const QString& animationName, double time, const QString& elementId);
+ bool pauseTransitionAtTimeOnElementWithId(const QString& propertyName, double time, const QString& elementId);
+ bool sampleSVGAnimationForElementAtTime(const QString& animationId, double time, const QString& elementId);
+ bool elementDoesAutoCompleteForElementWithId(const QString& elementId);
+
+ unsigned numberOfActiveAnimations() const;
+ void suspendAnimations() const;
+ void resumeAnimations() const;
+
+ void addOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
+ void removeOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
+
+ void dispatchPendingLoadRequests();
+ void disableImageLoading();
+
+ void clearAllApplicationCaches();
+ void clearApplicationCacheForOrigin(const QString& url);
+ void setApplicationCacheOriginQuota(unsigned long long quota);
+ QStringList originsWithApplicationCache();
+ long long applicationCacheDiskUsageForOrigin(const QString&);
+ void setCacheModel(int);
+
+ void setDatabaseQuota(int size);
+ void clearAllDatabases();
+ void setIconDatabaseEnabled(bool enable);
+
+ void setCustomPolicyDelegate(bool enabled, bool permissive = false);
+ void waitForPolicyDelegate();
+
+ void overridePreference(const QString& name, const QVariant& value);
+ void setUserStyleSheetLocation(const QString& url);
+ void setUserStyleSheetEnabled(bool enabled);
+ void setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme);
+ int workerThreadCount();
+ int pageNumberForElementById(const QString& id, float width = 0, float height = 0);
+ int numberOfPages(float width = maxViewWidth, float height = maxViewHeight);
+ bool callShouldCloseOnWebView();
+ // For now, this is a no-op. This may change depending on outcome of
+ // https://bugs.webkit.org/show_bug.cgi?id=33333
+ void setCallCloseOnWebViews() {}
+ // This is a no-op - it allows us to pass
+ // plugins/get-url-that-the-resource-load-delegate-will-disallow.html
+ // which is a Mac-specific test.
+ void addDisallowedURL(const QString&) {}
+
+ void setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma);
+
+ void setMockGeolocationError(int code, const QString& message);
+ void setMockGeolocationPosition(double latitude, double longitude, double accuracy);
+ void setGeolocationPermission(bool allow);
+ int numberOfPendingGeolocationPermissionRequests();
+ bool isGeolocationPermissionSet() const { return m_isGeolocationPermissionSet; }
+ bool geolocationPermission() const { return m_geolocationPermission; }
+
+ void addMockSpeechInputResult(const QString& result, double confidence, const QString& language);
+ void startSpeechInput(const QString& inputElement);
+
+ // Empty stub method to keep parity with object model exposed by global LayoutTestController.
+ void abortModal() {}
+ bool hasSpellingMarker(int from, int length);
+
+ QVariantList nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping);
+
+ void addURLToRedirect(const QString& origin, const QString& destination);
+
+ /*
+ Policy values: 'on', 'auto' or 'off'.
+ Orientation values: 'vertical' or 'horizontal'.
+ */
+ void setScrollbarPolicy(const QString& orientation, const QString& policy);
+
+ QString markerTextForListItem(const QWebElement& listItem);
+ QVariantMap computedStyleIncludingVisitedInfo(const QWebElement& element) const;
+
+ // Simulate a request an embedding application could make, populating per-session credential storage.
+ void authenticateSession(const QString& url, const QString& username, const QString& password);
+
+ void setEditingBehavior(const QString& editingBehavior);
+
+ void evaluateScriptInIsolatedWorld(int worldID, const QString& script);
+ bool isPageBoxVisible(int pageIndex);
+ QString pageSizeAndMarginsInPixels(int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft);
+ QString pageProperty(const QString& propertyName, int pageNumber);
+ void addUserStyleSheet(const QString& sourceCode);
+
+ void setMinimumTimerInterval(double);
+
+ void originsWithLocalStorage();
+ void deleteAllLocalStorage();
+ void deleteLocalStorageForOrigin(const QString& originIdentifier);
+ long long localStorageDiskUsageForOrigin(const QString& originIdentifier);
+ void observeStorageTrackerNotifications(unsigned number);
+ void syncLocalStorage();
+ QString layerTreeAsText();
+ void setTextDirection(const QString& directionName);
+ void goBack();
+ void setDefersLoading(bool);
+#if QT_VERSION >= 0x040800
+ void setAlwaysAcceptCookies(bool);
+ void setAlwaysBlockCookies(bool);
+#endif
+
+private slots:
+ void processWork();
+
+private:
+ void setGeolocationPermissionCommon(bool allow);
+
+private:
+ bool m_hasDumped;
+ bool m_textDump;
+ bool m_disallowIncreaseForApplicationCacheQuota;
+ bool m_dumpBackForwardList;
+ bool m_dumpChildrenAsText;
+ bool m_dumpChildFrameScrollPositions;
+ bool m_canOpenWindows;
+ bool m_waitForDone;
+ bool m_dumpTitleChanges;
+ bool m_dumpDatabaseCallbacks;
+ bool m_dumpApplicationCacheDelegateCallbacks;
+ bool m_dumpStatusCallbacks;
+ bool m_waitForPolicy;
+ bool m_handleErrorPages;
+ bool m_loadFinished;
+ bool m_globalFlag;
+ bool m_userStyleSheetEnabled;
+ bool m_isGeolocationPermissionSet;
+ bool m_isPrinting;
+ bool m_geolocationPermission;
+
+ QUrl m_userStyleSheetLocation;
+ QBasicTimer m_timeoutTimer;
+ QWebFrame* m_topLoadingFrame;
+ WebCore::DumpRenderTree* m_drt;
+ QWebHistory* m_webHistory;
+ QStringList m_desktopNotificationAllowedOrigins;
+ bool m_ignoreDesktopNotification;
+};
+
+#endif // LayoutTestControllerQt_h
diff --git a/Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp b/Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp
new file mode 100644
index 000000000..dd63feadb
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Robert Hogan <robert@roberthogan.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "PlainTextControllerQt.h"
+
+#include "DumpRenderTreeSupportQt.h"
+#include <QApplication>
+#include <QInputMethodEvent>
+#include <QKeyEvent>
+
+PlainTextController::PlainTextController(QWebPage* parent)
+ : QObject(parent)
+{
+}
+
+QString PlainTextController::plainText(const QVariant& range)
+{
+ return DumpRenderTreeSupportQt::plainText(range);
+}
diff --git a/Tools/DumpRenderTree/qt/PlainTextControllerQt.h b/Tools/DumpRenderTree/qt/PlainTextControllerQt.h
new file mode 100644
index 000000000..e78e1105a
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/PlainTextControllerQt.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 Robert Hogan <robert@roberthogan.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PlainTextControllerQt_h
+#define PlainTextControllerQt_h
+
+#include <QList>
+#include <QObject>
+#include <QString>
+#include <QVariant>
+
+#include "qwebpage.h"
+
+class PlainTextController : public QObject {
+ Q_OBJECT
+public:
+ PlainTextController(QWebPage* parent);
+
+public slots:
+ QString plainText(const QVariant& range);
+};
+
+#endif // PlainTextControllerQt_h
diff --git a/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
new file mode 100644
index 000000000..cbcd92198
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
@@ -0,0 +1,60 @@
+# -------------------------------------------------------------------
+# Project file for the NPAPI test plugin
+#
+# See 'Tools/qmake/README' for an overview of the build system
+# -------------------------------------------------------------------
+
+TEMPLATE = lib
+TARGET = TestNetscapePlugIn
+
+CONFIG += plugin
+
+SOURCES += \
+ PluginObject.cpp \
+ PluginTest.cpp \
+ TestObject.cpp \
+ main.cpp \
+ Tests/DocumentOpenInDestroyStream.cpp \
+ Tests/EvaluateJSAfterRemovingPluginElement.cpp \
+ Tests/FormValue.cpp \
+ Tests/GetURLNotifyWithURLThatFailsToLoad.cpp \
+ Tests/GetURLWithJavaScriptURL.cpp \
+ Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp \
+ Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \
+ Tests/NPDeallocateCalledBeforeNPShutdown.cpp \
+ Tests/NPPSetWindowCalledDuringDestruction.cpp \
+ Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \
+ Tests/NPRuntimeRemoveProperty.cpp \
+ Tests/NullNPPGetValuePointer.cpp \
+ Tests/PassDifferentNPPStruct.cpp \
+ Tests/PluginScriptableNPObjectInvokeDefault.cpp \
+ Tests/PrivateBrowsing.cpp
+
+WEBKIT += webcore # For NPAPI headers
+
+VPATH = ../../unix/TestNetscapePlugin ../../TestNetscapePlugIn
+
+
+INCLUDEPATH += \
+ ../../unix/TestNetscapePlugin/ForwardingHeaders \
+ ../../unix/TestNetscapePlugin/ForwardingHeaders/WebKit \
+ ../../TestNetscapePlugIn
+
+DESTDIR = $${ROOT_BUILD_DIR}/lib/plugins
+
+mac {
+ CONFIG += plugin_bundle
+ QMAKE_INFO_PLIST = ../../TestNetscapePlugIn/mac/Info.plist
+ QMAKE_PLUGIN_BUNDLE_NAME = $$TARGET
+ QMAKE_BUNDLE_LOCATION += "Contents/MacOS"
+
+ !build_pass:CONFIG += build_all
+
+ OBJECTIVE_SOURCES += PluginObjectMac.mm
+ LIBS += -framework Carbon -framework Cocoa -framework QuartzCore
+}
+
+!win32:!embedded:!mac {
+ LIBS += -lX11
+ DEFINES += XP_UNIX
+}
diff --git a/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp b/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp
new file mode 100644
index 000000000..d5645a523
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "TextInputControllerQt.h"
+#include "DumpRenderTreeSupportQt.h"
+
+#include <QApplication>
+#include <QInputMethodEvent>
+#include <QKeyEvent>
+
+TextInputController::TextInputController(QWebPage* parent)
+ : QObject(parent)
+{
+}
+
+void TextInputController::doCommand(const QString& command)
+{
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+ int keycode = 0;
+ if (command == "moveBackwardAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveDown:") {
+ keycode = Qt::Key_Down;
+ } else if (command =="moveDownAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Down;
+ } else if (command =="moveForward:") {
+ keycode = Qt::Key_Right;
+ } else if (command =="moveForwardAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveLeft:") {
+ keycode = Qt::Key_Left;
+ } else if (command =="moveLeftAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveRight:") {
+ keycode = Qt::Key_Right;
+ } else if (command =="moveRightAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveToBeginningOfDocument:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Home;
+ } else if (command =="moveToBeginningOfLine:") {
+ keycode = Qt::Key_Home;
+// } else if (command =="moveToBeginningOfParagraph:") {
+ } else if (command =="moveToEndOfDocument:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_End;
+ } else if (command =="moveToEndOfLine:") {
+ keycode = Qt::Key_End;
+// } else if (command =="moveToEndOfParagraph:") {
+ } else if (command =="moveUp:") {
+ keycode = Qt::Key_Up;
+ } else if (command =="moveUpAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Up;
+ } else if (command =="moveWordBackward:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Up;
+ } else if (command =="moveWordBackwardAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveWordForward:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveWordForwardAndModifySelection:") {
+ modifiers |= Qt::ControlModifier;
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveWordLeft:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveWordRight:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveWordRightAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveWordLeftAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="pageDown:") {
+ keycode = Qt::Key_PageDown;
+ } else if (command =="pageUp:") {
+ keycode = Qt::Key_PageUp;
+ } else if (command == "deleteWordBackward:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Backspace;
+ } else if (command == "deleteBackward:") {
+ keycode = Qt::Key_Backspace;
+ } else if (command == "deleteForward:") {
+ keycode = Qt::Key_Delete;
+ }
+
+ QKeyEvent event(QEvent::KeyPress, keycode, modifiers);
+ QApplication::sendEvent(parent(), &event);
+ QKeyEvent event2(QEvent::KeyRelease, keycode, modifiers);
+ QApplication::sendEvent(parent(), &event2);
+}
+
+void TextInputController::setMarkedText(const QString& string, int start, int end)
+{
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent::Attribute selection(QInputMethodEvent::Selection, start, end, QVariant());
+ attributes << selection;
+ QInputMethodEvent event(string, attributes);
+ QApplication::sendEvent(parent(), &event);
+}
+
+void TextInputController::insertText(const QString& string)
+{
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(string, attributes);
+ event.setCommitString(string);
+ QApplication::sendEvent(parent(), &event);
+}
+
+QVariantList TextInputController::selectedRange()
+{
+ return DumpRenderTreeSupportQt::selectedRange(qobject_cast<QWebPage*>(parent()));
+}
+
+QVariantList TextInputController::firstRectForCharacterRange(int location, int length)
+{
+ return DumpRenderTreeSupportQt::firstRectForCharacterRange(qobject_cast<QWebPage*>(parent()), location, length);
+}
+
+void TextInputController::unmarkText()
+{
+ DumpRenderTreeSupportQt::confirmComposition(qobject_cast<QWebPage*>(parent()), 0);
+}
diff --git a/Tools/DumpRenderTree/qt/TextInputControllerQt.h b/Tools/DumpRenderTree/qt/TextInputControllerQt.h
new file mode 100644
index 000000000..572abfd7c
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/TextInputControllerQt.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 TextInputControllerQt_h
+#define TextInputControllerQt_h
+
+#include <QList>
+#include <QObject>
+#include <QVariant>
+#include <QString>
+#include "qwebpage.h"
+
+class TextInputController : public QObject {
+ Q_OBJECT
+public:
+ TextInputController(QWebPage* parent);
+
+public slots:
+ void doCommand(const QString& command);
+ void setMarkedText(const QString& string, int start, int end);
+// bool hasMarkedText();
+ void unmarkText();
+// QList<int> markedRange();
+ QVariantList selectedRange();
+// void validAttributesForMarkedText();
+ void insertText(const QString& string);
+ QVariantList firstRectForCharacterRange(int location, int length);
+// void characterIndexForPoint(int, int);
+// void substringFromRange(int, int);
+// void conversationIdentifier();
+};
+#endif // TextInputControllerQt_h
diff --git a/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp b/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp
new file mode 100644
index 000000000..b09336667
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "WorkQueueItemQt.h"
+#include "DumpRenderTreeSupportQt.h"
+
+QWebFrame* findFrameNamed(const QString& frameName, QWebFrame* frame)
+{
+ if (frame->frameName() == frameName)
+ return frame;
+
+ foreach (QWebFrame* childFrame, frame->childFrames())
+ if (QWebFrame* f = findFrameNamed(frameName, childFrame))
+ return f;
+
+ return 0;
+}
+
+bool LoadItem::invoke() const
+{
+ //qDebug() << ">>>LoadItem::invoke";
+ Q_ASSERT(m_webPage);
+
+ QWebFrame* frame = 0;
+ const QString t = target();
+ if (t.isEmpty())
+ frame = m_webPage->mainFrame();
+ else
+ frame = findFrameNamed(t, m_webPage->mainFrame());
+
+ if (!frame)
+ return false;
+
+ frame->load(url());
+ return true;
+}
+
+bool LoadHTMLStringItem::invoke() const
+{
+ Q_ASSERT(m_webPage);
+
+ QWebFrame* frame = m_webPage->mainFrame();
+ if (!frame)
+ return false;
+
+ frame->setHtml(m_content, QUrl(m_baseURL));
+ return true;
+}
+
+bool LoadAlternateHTMLStringItem::invoke() const
+{
+ Q_ASSERT(m_webPage);
+
+ QWebFrame* frame = m_webPage->mainFrame();
+ if (!frame)
+ return false;
+
+ DumpRenderTreeSupportQt::setAlternateHtml(frame, m_content, QUrl(m_baseURL), QUrl(m_failingURL));
+ return true;
+}
+
+bool ReloadItem::invoke() const
+{
+ //qDebug() << ">>>ReloadItem::invoke";
+ Q_ASSERT(m_webPage);
+ m_webPage->triggerAction(QWebPage::Reload);
+ return true;
+}
+
+bool ScriptItem::invoke() const
+{
+ //qDebug() << ">>>ScriptItem::invoke";
+ Q_ASSERT(m_webPage);
+ m_webPage->mainFrame()->evaluateJavaScript(script());
+ return true;
+}
+
+bool BackForwardItem::invoke() const
+{
+ //qDebug() << ">>>BackForwardItem::invoke";
+ Q_ASSERT(m_webPage);
+ if (!m_howFar)
+ return false;
+
+ if (m_howFar > 0) {
+ for (int i = 0; i != m_howFar; ++i)
+ m_webPage->triggerAction(QWebPage::Forward);
+ } else {
+ for (int i = 0; i != m_howFar; --i)
+ m_webPage->triggerAction(QWebPage::Back);
+ }
+ return true;
+}
diff --git a/Tools/DumpRenderTree/qt/WorkQueueItemQt.h b/Tools/DumpRenderTree/qt/WorkQueueItemQt.h
new file mode 100644
index 000000000..ac7d1b37a
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/WorkQueueItemQt.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 WorkQueueItemQt_h
+#define WorkQueueItemQt_h
+
+#include <QPointer>
+#include <QString>
+#include <qwebframe.h>
+#include <qwebpage.h>
+
+class WorkQueueItem {
+public:
+ WorkQueueItem(QWebPage *page) : m_webPage(page) {}
+ virtual ~WorkQueueItem() { }
+ virtual bool invoke() const = 0;
+
+protected:
+ QPointer<QWebPage> m_webPage;
+};
+
+class LoadItem : public WorkQueueItem {
+public:
+ LoadItem(const QString &url, const QString &target, QWebPage *page)
+ : WorkQueueItem(page)
+ , m_url(url)
+ , m_target(target)
+ {
+ }
+
+ QString url() const { return m_url; }
+ QString target() const { return m_target; }
+
+ virtual bool invoke() const;
+
+private:
+ QString m_url;
+ QString m_target;
+};
+
+class LoadHTMLStringItem : public WorkQueueItem {
+public:
+ LoadHTMLStringItem(const QString& content, const QString &baseURL, QWebPage *page)
+ : WorkQueueItem(page)
+ , m_content(content)
+ , m_baseURL(baseURL)
+ {
+ }
+
+private:
+ virtual bool invoke() const;
+
+ QString m_content;
+ QString m_baseURL;
+};
+
+class LoadAlternateHTMLStringItem : public WorkQueueItem {
+public:
+ LoadAlternateHTMLStringItem(const QString& content, const QString& baseURL, const QString &failingURL, QWebPage *page)
+ : WorkQueueItem(page)
+ , m_content(content)
+ , m_baseURL(baseURL)
+ , m_failingURL(failingURL)
+ {
+ }
+
+private:
+ virtual bool invoke() const;
+
+ QString m_content;
+ QString m_baseURL;
+ QString m_failingURL;
+};
+
+class ReloadItem : public WorkQueueItem {
+public:
+ ReloadItem(QWebPage *page)
+ : WorkQueueItem(page)
+ {
+ }
+ virtual bool invoke() const;
+};
+
+class ScriptItem : public WorkQueueItem {
+public:
+ ScriptItem(const QString &script, QWebPage *page)
+ : WorkQueueItem(page)
+ , m_script(script)
+ {
+ }
+
+ QString script() const { return m_script; }
+
+ virtual bool invoke() const;
+
+private:
+ QString m_script;
+};
+
+class LoadingScriptItem : public ScriptItem {
+public:
+ LoadingScriptItem(const QString& script, QWebPage* page)
+ : ScriptItem(script, page)
+ {
+ }
+
+ virtual bool invoke() const { return ScriptItem::invoke(); }
+};
+
+class NonLoadingScriptItem : public ScriptItem {
+public:
+ NonLoadingScriptItem(const QString& script, QWebPage* page)
+ : ScriptItem(script, page)
+ {
+ }
+
+ virtual bool invoke() const { ScriptItem::invoke(); return false; }
+};
+
+
+class BackForwardItem : public WorkQueueItem {
+public:
+ virtual bool invoke() const;
+
+protected:
+ BackForwardItem(int howFar, QWebPage *page)
+ : WorkQueueItem(page)
+ , m_howFar(howFar)
+ {
+ }
+
+ int m_howFar;
+};
+
+class BackItem : public BackForwardItem {
+public:
+ BackItem(unsigned howFar, QWebPage *page)
+ : BackForwardItem(-howFar, page)
+ {
+ }
+};
+
+class ForwardItem : public BackForwardItem {
+public:
+ ForwardItem(unsigned howFar, QWebPage *page)
+ : BackForwardItem(howFar, page)
+ {
+ }
+};
+
+#endif // !defined(WorkQueueItemQt_h)
diff --git a/Tools/DumpRenderTree/qt/fonts.conf b/Tools/DumpRenderTree/qt/fonts.conf
new file mode 100644
index 000000000..3540c479f
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/fonts.conf
@@ -0,0 +1,258 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<fontconfig>
+
+<!--
+ Accept deprecated 'mono' alias, replacing it with 'monospace'
+-->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>mono</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>monospace</string>
+ </edit>
+ </match>
+
+<!--
+ Accept alternate 'sans serif' spelling, replacing it with 'sans-serif'
+-->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>sans-serif</string>
+ </edit>
+ </match>
+
+<!--
+ Accept deprecated 'sans' alias, replacing it with 'sans-serif'
+-->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>sans-serif</string>
+ </edit>
+ </match>
+
+
+ <config>
+<!--
+ These are the default Unicode chars that are expected to be blank
+ in fonts. All other blank chars are assumed to be broken and
+ won't appear in the resulting charsets
+ -->
+ <blank>
+ <int>0x0020</int> <!-- SPACE -->
+ <int>0x00A0</int> <!-- NO-BREAK SPACE -->
+ <int>0x00AD</int> <!-- SOFT HYPHEN -->
+ <int>0x034F</int> <!-- COMBINING GRAPHEME JOINER -->
+ <int>0x0600</int> <!-- ARABIC NUMBER SIGN -->
+ <int>0x0601</int> <!-- ARABIC SIGN SANAH -->
+ <int>0x0602</int> <!-- ARABIC FOOTNOTE MARKER -->
+ <int>0x0603</int> <!-- ARABIC SIGN SAFHA -->
+ <int>0x06DD</int> <!-- ARABIC END OF AYAH -->
+ <int>0x070F</int> <!-- SYRIAC ABBREVIATION MARK -->
+ <int>0x115F</int> <!-- HANGUL CHOSEONG FILLER -->
+ <int>0x1160</int> <!-- HANGUL JUNGSEONG FILLER -->
+ <int>0x1680</int> <!-- OGHAM SPACE MARK -->
+ <int>0x17B4</int> <!-- KHMER VOWEL INHERENT AQ -->
+ <int>0x17B5</int> <!-- KHMER VOWEL INHERENT AA -->
+ <int>0x180E</int> <!-- MONGOLIAN VOWEL SEPARATOR -->
+ <int>0x2000</int> <!-- EN QUAD -->
+ <int>0x2001</int> <!-- EM QUAD -->
+ <int>0x2002</int> <!-- EN SPACE -->
+ <int>0x2003</int> <!-- EM SPACE -->
+ <int>0x2004</int> <!-- THREE-PER-EM SPACE -->
+ <int>0x2005</int> <!-- FOUR-PER-EM SPACE -->
+ <int>0x2006</int> <!-- SIX-PER-EM SPACE -->
+ <int>0x2007</int> <!-- FIGURE SPACE -->
+ <int>0x2008</int> <!-- PUNCTUATION SPACE -->
+ <int>0x2009</int> <!-- THIN SPACE -->
+ <int>0x200A</int> <!-- HAIR SPACE -->
+ <int>0x200B</int> <!-- ZERO WIDTH SPACE -->
+ <int>0x200C</int> <!-- ZERO WIDTH NON-JOINER -->
+ <int>0x200D</int> <!-- ZERO WIDTH JOINER -->
+ <int>0x200E</int> <!-- LEFT-TO-RIGHT MARK -->
+ <int>0x200F</int> <!-- RIGHT-TO-LEFT MARK -->
+ <int>0x2028</int> <!-- LINE SEPARATOR -->
+ <int>0x2029</int> <!-- PARAGRAPH SEPARATOR -->
+ <int>0x202A</int> <!-- LEFT-TO-RIGHT EMBEDDING -->
+ <int>0x202B</int> <!-- RIGHT-TO-LEFT EMBEDDING -->
+ <int>0x202C</int> <!-- POP DIRECTIONAL FORMATTING -->
+ <int>0x202D</int> <!-- LEFT-TO-RIGHT OVERRIDE -->
+ <int>0x202E</int> <!-- RIGHT-TO-LEFT OVERRIDE -->
+ <int>0x202F</int> <!-- NARROW NO-BREAK SPACE -->
+ <int>0x205F</int> <!-- MEDIUM MATHEMATICAL SPACE -->
+ <int>0x2060</int> <!-- WORD JOINER -->
+ <int>0x2061</int> <!-- FUNCTION APPLICATION -->
+ <int>0x2062</int> <!-- INVISIBLE TIMES -->
+ <int>0x2063</int> <!-- INVISIBLE SEPARATOR -->
+ <int>0x206A</int> <!-- INHIBIT SYMMETRIC SWAPPING -->
+ <int>0x206B</int> <!-- ACTIVATE SYMMETRIC SWAPPING -->
+ <int>0x206C</int> <!-- INHIBIT ARABIC FORM SHAPING -->
+ <int>0x206D</int> <!-- ACTIVATE ARABIC FORM SHAPING -->
+ <int>0x206E</int> <!-- NATIONAL DIGIT SHAPES -->
+ <int>0x206F</int> <!-- NOMINAL DIGIT SHAPES -->
+ <int>0x3000</int> <!-- IDEOGRAPHIC SPACE -->
+ <int>0x3164</int> <!-- HANGUL FILLER -->
+ <int>0xFEFF</int> <!-- ZERO WIDTH NO-BREAK SPACE -->
+ <int>0xFFA0</int> <!-- HALFWIDTH HANGUL FILLER -->
+ <int>0xFFF9</int> <!-- INTERLINEAR ANNOTATION ANCHOR -->
+ <int>0xFFFA</int> <!-- INTERLINEAR ANNOTATION SEPARATOR -->
+ <int>0xFFFB</int> <!-- INTERLINEAR ANNOTATION TERMINATOR -->
+ </blank>
+<!--
+ Rescan configuration every 30 seconds when FcFontSetList is called
+ -->
+ <rescan>
+ <int>30</int>
+ </rescan>
+ </config>
+
+<!--
+ URW provides metric and shape compatible fonts for these 10 Adobe families.
+
+ However, these fonts are quite ugly and do not render well on-screen,
+ so we avoid matching them if the application said `anymetrics'; in that
+ case, a more generic font with different metrics but better appearance
+ will be used.
+ -->
+ <match target="pattern">
+ <test name="family">
+ <string>Avant Garde</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>URW Gothic L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Bookman</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>URW Bookman L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Courier</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Nimbus Mono L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Helvetica</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Nimbus Sans L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>New Century Schoolbook</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Century Schoolbook L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Palatino</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>URW Palladio L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Times</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Nimbus Roman No9 L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Zapf Chancery</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>URW Chancery L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Zapf Dingbats</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Dingbats</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Symbol</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append" binding="same">
+ <string>Standard Symbols L</string>
+ </edit>
+ </match>
+
+<!--
+ Serif faces
+ -->
+ <alias>
+ <family>Nimbus Roman No9 L</family>
+ <default><family>serif</family></default>
+ </alias>
+<!--
+ Sans-serif faces
+ -->
+ <alias>
+ <family>Nimbus Sans L</family>
+ <default><family>sans-serif</family></default>
+ </alias>
+<!--
+ Monospace faces
+ -->
+ <alias>
+ <family>Nimbus Mono L</family>
+ <default><family>monospace</family></default>
+ </alias>
+
+
+</fontconfig>
diff --git a/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF b/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF
new file mode 100644
index 000000000..ac81cb031
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF
Binary files differ
diff --git a/Tools/DumpRenderTree/qt/main.cpp b/Tools/DumpRenderTree/qt/main.cpp
new file mode 100644
index 000000000..3d9673bee
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/main.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTreeQt.h"
+
+#include <wtf/AlwaysInline.h>
+
+#include <qstringlist.h>
+#include <qapplication.h>
+#include <qurl.h>
+#include <qdir.h>
+#include <qdebug.h>
+#include <qfont.h>
+#include <qwebdatabase.h>
+#include <qtimer.h>
+#include <qwindowsstyle.h>
+
+#ifdef Q_WS_X11
+#include <qx11info_x11.h>
+#endif
+
+#ifdef Q_OS_WIN
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#include <limits.h>
+#include <signal.h>
+
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
+#include <execinfo.h>
+#endif
+
+void messageHandler(QtMsgType type, const char *message)
+{
+ if (type == QtCriticalMsg) {
+ fprintf(stderr, "%s\n", message);
+ return;
+ }
+ // do nothing
+}
+
+// We only support -v or --pixel-tests or --stdout or --stderr or -, all the others will be
+// pass as test case name (even -abc.html is a valid test case name)
+bool isOption(const QString& str)
+{
+ return str == QString("-v") || str == QString("--pixel-tests")
+ || str == QString("--stdout") || str == QString("--stderr")
+ || str == QString("-");
+}
+
+QString takeOptionValue(QStringList& arguments, int index)
+{
+ QString result;
+
+ if (index + 1 < arguments.count() && !isOption(arguments.at(index + 1)))
+ result = arguments.takeAt(index + 1);
+ arguments.removeAt(index);
+
+ return result;
+}
+
+void printUsage()
+{
+ fprintf(stderr, "Usage: DumpRenderTree [-v|--pixel-tests] [--stdout output_filename] [-stderr error_filename] filename [filename2..n]\n");
+ fprintf(stderr, "Or folder containing test files: DumpRenderTree [-v|--pixel-tests] dirpath\n");
+ fflush(stderr);
+}
+
+QString get_backtrace() {
+ QString s;
+
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
+ void* array[256];
+ size_t size; /* number of stack frames */
+
+ size = backtrace(array, 256);
+
+ if (!size)
+ return s;
+
+ char** strings = backtrace_symbols(array, size);
+ for (int i = 0; i < int(size); ++i) {
+ s += QString::number(i) +
+ QLatin1String(": ") +
+ QLatin1String(strings[i]) + QLatin1String("\n");
+ }
+
+ if (strings)
+ free (strings);
+#endif
+
+ return s;
+}
+
+#if HAVE(SIGNAL_H)
+static NO_RETURN void crashHandler(int sig)
+{
+ fprintf(stderr, "%s\n", strsignal(sig));
+ fprintf(stderr, "%s\n", get_backtrace().toLatin1().constData());
+ exit(128 + sig);
+}
+#endif
+
+int main(int argc, char* argv[])
+{
+#ifdef Q_OS_WIN
+ _setmode(1, _O_BINARY);
+ _setmode(2, _O_BINARY);
+#endif
+
+ // Suppress debug output from Qt if not started with -v
+ bool suppressQtDebugOutput = true;
+ for (int i = 1; i < argc; ++i) {
+ if (!qstrcmp(argv[i], "-v")) {
+ suppressQtDebugOutput = false;
+ break;
+ }
+ }
+
+ // Has to be done before QApplication is constructed in case
+ // QApplication itself produces debug output.
+ if (suppressQtDebugOutput)
+ qInstallMsgHandler(messageHandler);
+
+ WebCore::DumpRenderTree::initializeFonts();
+
+ QApplication::setGraphicsSystem("raster");
+ QApplication::setStyle(new QWindowsStyle);
+
+ QApplication app(argc, argv);
+
+#ifdef Q_WS_X11
+ QX11Info::setAppDpiY(0, 96);
+ QX11Info::setAppDpiX(0, 96);
+#endif
+
+ /*
+ * QApplication will initialize the default application font based
+ * on the application DPI at construction time, which might be
+ * different from the DPI we explicitly set using QX11Info above.
+ * See: https://bugreports.qt.nokia.com/browse/QTBUG-21603
+ *
+ * To ensure that the application font DPI matches the application
+ * DPI, we override the application font using the font we get from
+ * a QWidget, which has already been resolved against the existing
+ * default font, but with the correct paint-device DPI.
+ */
+ QApplication::setFont(QWidget().font());
+
+#if HAVE(SIGNAL_H)
+ signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */
+ signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */
+ signal(SIGFPE, crashHandler); /* 8: floating point exception */
+ signal(SIGBUS, crashHandler); /* 10: bus error */
+ signal(SIGSEGV, crashHandler); /* 11: segmentation violation */
+ signal(SIGSYS, crashHandler); /* 12: bad argument to system call */
+ signal(SIGPIPE, crashHandler); /* 13: write on a pipe with no reader */
+ signal(SIGXCPU, crashHandler); /* 24: exceeded CPU time limit */
+ signal(SIGXFSZ, crashHandler); /* 25: exceeded file size limit */
+#endif
+
+ QStringList args = app.arguments();
+ if (args.count() < (!suppressQtDebugOutput ? 3 : 2)) {
+ printUsage();
+ exit(1);
+ }
+
+ // Remove the first arguments, it is application name itself
+ args.removeAt(0);
+
+ WebCore::DumpRenderTree dumper;
+
+ int index = args.indexOf(QLatin1String("--pixel-tests"));
+ if (index != -1) {
+ dumper.setDumpPixels(true);
+ args.removeAt(index);
+ }
+
+ index = args.indexOf(QLatin1String("--stdout"));
+ if (index != -1) {
+ QString fileName = takeOptionValue(args, index);
+ dumper.setRedirectOutputFileName(fileName);
+ if (fileName.isEmpty() || !freopen(qPrintable(fileName), "w", stdout)) {
+ fprintf(stderr, "STDOUT redirection failed.");
+ exit(1);
+ }
+ }
+ index = args.indexOf(QLatin1String("--stderr"));
+ if (index != -1) {
+ QString fileName = takeOptionValue(args, index);
+ dumper.setRedirectErrorFileName(fileName);
+ if (!freopen(qPrintable(fileName), "w", stderr)) {
+ fprintf(stderr, "STDERR redirection failed.");
+ exit(1);
+ }
+ }
+ QWebDatabase::removeAllDatabases();
+
+ index = args.indexOf(QLatin1String("-"));
+ if (index != -1) {
+ args.removeAt(index);
+
+ // Continue waiting in STDIN for more test case after process one test case
+ QObject::connect(&dumper, SIGNAL(ready()), &dumper, SLOT(readLine()), Qt::QueuedConnection);
+
+ // Read and only read the first test case, ignore the others
+ if (args.size() > 0) {
+ // Process the argument first
+ dumper.processLine(args[0]);
+ } else
+ QTimer::singleShot(0, &dumper, SLOT(readLine()));
+ } else {
+ // Go into standalone mode
+ // Standalone mode need at least one test case
+ if (args.count() < 1) {
+ printUsage();
+ exit(1);
+ }
+ dumper.processArgsLine(args);
+ }
+ return app.exec();
+}
diff --git a/Tools/DumpRenderTree/qt/resources/user.css b/Tools/DumpRenderTree/qt/resources/user.css
new file mode 100644
index 000000000..af3981995
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/resources/user.css
@@ -0,0 +1,4 @@
+body {
+ font-size: 50px;
+ background-color: rgb(255, 255, 0);
+} \ No newline at end of file
diff --git a/Tools/DumpRenderTree/qt/testplugin.cpp b/Tools/DumpRenderTree/qt/testplugin.cpp
new file mode 100644
index 000000000..d5b8bc7ee
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/testplugin.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "testplugin.h"
+
+TestPlugin::TestPlugin(QObject *parent)
+ : QWebPluginFactory(parent)
+{
+}
+
+TestPlugin::~TestPlugin()
+{
+}
+
+QList<QWebPluginFactory::Plugin> TestPlugin::plugins() const
+{
+ QWebPluginFactory::Plugin plugin;
+
+ plugin.name = "testplugin";
+ plugin.description = "testdescription";
+ MimeType mimeType;
+ mimeType.name = "testtype";
+ mimeType.fileExtensions.append("testsuffixes");
+ plugin.mimeTypes.append(mimeType);
+
+ plugin.name = "testplugin2";
+ plugin.description = "testdescription2";
+ mimeType.name = "testtype2";
+ mimeType.fileExtensions.append("testsuffixes2");
+ mimeType.fileExtensions.append("testsuffixes3");
+ plugin.mimeTypes.append(mimeType);
+
+ return QList<QWebPluginFactory::Plugin>() << plugin;
+}
+
+QObject *TestPlugin::create(const QString&,
+ const QUrl&,
+ const QStringList&,
+ const QStringList&) const
+{
+ return 0;
+}
+
diff --git a/Tools/DumpRenderTree/qt/testplugin.h b/Tools/DumpRenderTree/qt/testplugin.h
new file mode 100644
index 000000000..3d8a28cf3
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/testplugin.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 <qwebpluginfactory.h>
+
+
+class TestPlugin : public QWebPluginFactory
+{
+public:
+ explicit TestPlugin(QObject *parent = 0);
+ virtual ~TestPlugin();
+
+ virtual QList<Plugin> plugins() const;
+
+ virtual QObject *create(const QString &mimeType,
+ const QUrl &url,
+ const QStringList &argumentNames,
+ const QStringList &argumentValues) const;
+
+};
+
diff --git a/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h
new file mode 100644
index 000000000..627bc97a9
--- /dev/null
+++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h
@@ -0,0 +1 @@
+#include <plugins/npapi.h>
diff --git a/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h
new file mode 100644
index 000000000..54a603dbb
--- /dev/null
+++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h
@@ -0,0 +1 @@
+#include <plugins/npfunctions.h>
diff --git a/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h
new file mode 100644
index 000000000..e435ae2ab
--- /dev/null
+++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h
@@ -0,0 +1 @@
+#include <plugins/npruntime.h>
diff --git a/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp b/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp
new file mode 100644
index 000000000..644efe5f1
--- /dev/null
+++ b/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityController.h"
+
+#include "AccessibilityUIElement.h"
+#include "DumpRenderTree.h"
+#include "FrameLoadDelegate.h"
+#include <JavaScriptCore/Assertions.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <WebCore/COMPtr.h>
+#include <WebKit/WebKit.h>
+#include <oleacc.h>
+#include <string>
+
+using namespace std;
+
+AccessibilityController::AccessibilityController()
+ : m_focusEventHook(0)
+ , m_scrollingStartEventHook(0)
+ , m_valueChangeEventHook(0)
+ , m_allEventsHook(0)
+ , m_notificationsEventHook(0)
+{
+}
+
+AccessibilityController::~AccessibilityController()
+{
+ setLogFocusEvents(false);
+ setLogAccessibilityEvents(false);
+ setLogValueChangeEvents(false);
+
+ if (m_notificationsEventHook)
+ UnhookWinEvent(m_notificationsEventHook);
+
+ for (HashMap<PlatformUIElement, JSObjectRef>::iterator it = m_notificationListeners.begin(); it != m_notificationListeners.end(); ++it)
+ JSValueUnprotect(frame->globalContext(), it->second);
+}
+
+AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y)
+{
+ // FIXME: implement
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityController::focusedElement()
+{
+ COMPtr<IAccessible> rootAccessible = rootElement().platformUIElement();
+
+ VARIANT vFocus;
+ if (FAILED(rootAccessible->get_accFocus(&vFocus)))
+ return 0;
+
+ if (V_VT(&vFocus) == VT_I4) {
+ ASSERT(V_I4(&vFocus) == CHILDID_SELF);
+ // The root accessible object is the focused object.
+ return rootAccessible;
+ }
+
+ ASSERT(V_VT(&vFocus) == VT_DISPATCH);
+ // We have an IDispatch; query for IAccessible.
+ return COMPtr<IAccessible>(Query, V_DISPATCH(&vFocus));
+}
+
+AccessibilityUIElement AccessibilityController::rootElement()
+{
+ COMPtr<IWebView> view;
+ if (FAILED(frame->webView(&view)))
+ return 0;
+
+ COMPtr<IWebViewPrivate> viewPrivate(Query, view);
+ if (!viewPrivate)
+ return 0;
+
+ HWND webViewWindow;
+ if (FAILED(viewPrivate->viewWindow((OLE_HANDLE*)&webViewWindow)))
+ return 0;
+
+ // Get the root accessible object by querying for the accessible object for the
+ // WebView's window.
+ COMPtr<IAccessible> rootAccessible;
+ if (FAILED(AccessibleObjectFromWindow(webViewWindow, static_cast<DWORD>(OBJID_CLIENT), __uuidof(IAccessible), reinterpret_cast<void**>(&rootAccessible))))
+ return 0;
+
+ return rootAccessible;
+}
+
+static void CALLBACK logEventProc(HWINEVENTHOOK, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD, DWORD)
+{
+ // Get the accessible object for this event.
+ COMPtr<IAccessible> parentObject;
+
+ VARIANT vChild;
+ VariantInit(&vChild);
+
+ HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &parentObject, &vChild);
+ ASSERT(SUCCEEDED(hr));
+
+ // Get the name of the focused element, and log it to stdout.
+ BSTR nameBSTR;
+ hr = parentObject->get_accName(vChild, &nameBSTR);
+ ASSERT(SUCCEEDED(hr));
+ wstring name(nameBSTR, ::SysStringLen(nameBSTR));
+ SysFreeString(nameBSTR);
+
+ switch (event) {
+ case EVENT_OBJECT_FOCUS:
+ printf("Received focus event for object '%S'.\n", name.c_str());
+ break;
+
+ case EVENT_OBJECT_SELECTION:
+ printf("Received selection event for object '%S'.\n", name.c_str());
+ break;
+
+ case EVENT_OBJECT_VALUECHANGE: {
+ BSTR valueBSTR;
+ hr = parentObject->get_accValue(vChild, &valueBSTR);
+ ASSERT(SUCCEEDED(hr));
+ wstring value(valueBSTR, ::SysStringLen(valueBSTR));
+ SysFreeString(valueBSTR);
+
+ printf("Received value change event for object '%S', value '%S'.\n", name.c_str(), value.c_str());
+ break;
+ }
+
+ case EVENT_SYSTEM_SCROLLINGSTART:
+ printf("Received scrolling start event for object '%S'.\n", name.c_str());
+ break;
+
+ default:
+ printf("Received unknown event for object '%S'.\n", name.c_str());
+ break;
+ }
+
+ VariantClear(&vChild);
+}
+
+void AccessibilityController::setLogFocusEvents(bool logFocusEvents)
+{
+ if (!!m_focusEventHook == logFocusEvents)
+ return;
+
+ if (!logFocusEvents) {
+ UnhookWinEvent(m_focusEventHook);
+ m_focusEventHook = 0;
+ return;
+ }
+
+ // Ensure that accessibility is initialized for the WebView by querying for
+ // the root accessible object.
+ rootElement();
+
+ m_focusEventHook = SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, GetModuleHandle(0), logEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
+
+ ASSERT(m_focusEventHook);
+}
+
+void AccessibilityController::setLogValueChangeEvents(bool logValueChangeEvents)
+{
+ if (!!m_valueChangeEventHook == logValueChangeEvents)
+ return;
+
+ if (!logValueChangeEvents) {
+ UnhookWinEvent(m_valueChangeEventHook);
+ m_valueChangeEventHook = 0;
+ return;
+ }
+
+ // Ensure that accessibility is initialized for the WebView by querying for
+ // the root accessible object.
+ rootElement();
+
+ m_valueChangeEventHook = SetWinEventHook(EVENT_OBJECT_VALUECHANGE, EVENT_OBJECT_VALUECHANGE, GetModuleHandle(0), logEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
+
+ ASSERT(m_valueChangeEventHook);
+}
+
+void AccessibilityController::setLogScrollingStartEvents(bool logScrollingStartEvents)
+{
+ if (!!m_scrollingStartEventHook == logScrollingStartEvents)
+ return;
+
+ if (!logScrollingStartEvents) {
+ UnhookWinEvent(m_scrollingStartEventHook);
+ m_scrollingStartEventHook = 0;
+ return;
+ }
+
+ // Ensure that accessibility is initialized for the WebView by querying for
+ // the root accessible object.
+ rootElement();
+
+ m_scrollingStartEventHook = SetWinEventHook(EVENT_SYSTEM_SCROLLINGSTART, EVENT_SYSTEM_SCROLLINGSTART, GetModuleHandle(0), logEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
+
+ ASSERT(m_scrollingStartEventHook);
+}
+
+void AccessibilityController::setLogAccessibilityEvents(bool logAccessibilityEvents)
+{
+ if (!!m_allEventsHook == logAccessibilityEvents)
+ return;
+
+ if (!logAccessibilityEvents) {
+ UnhookWinEvent(m_allEventsHook);
+ m_allEventsHook = 0;
+ return;
+ }
+
+ // Ensure that accessibility is initialized for the WebView by querying for
+ // the root accessible object.
+ rootElement();
+
+ m_allEventsHook = SetWinEventHook(EVENT_MIN, EVENT_MAX, GetModuleHandle(0), logEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
+
+ ASSERT(m_allEventsHook);
+}
+
+static string stringEvent(DWORD event)
+{
+ switch(event) {
+ case EVENT_OBJECT_VALUECHANGE:
+ return "value change event";
+ default:
+ return "unknown event";
+ }
+}
+
+static void CALLBACK notificationListenerProc(HWINEVENTHOOK, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD, DWORD)
+{
+ // Get the accessible object for this event.
+ COMPtr<IAccessible> parentObject;
+
+ VARIANT vChild;
+ VariantInit(&vChild);
+
+ HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &parentObject, &vChild);
+ if (FAILED(hr) || !parentObject)
+ return;
+
+ COMPtr<IDispatch> childDispatch;
+ if (FAILED(parentObject->get_accChild(vChild, &childDispatch))) {
+ VariantClear(&vChild);
+ return;
+ }
+
+ COMPtr<IAccessible> childAccessible(Query, childDispatch);
+
+ sharedFrameLoadDelegate->accessibilityController()->winNotificationReceived(childAccessible, stringEvent(event));
+
+ VariantClear(&vChild);
+}
+
+static COMPtr<IAccessibleComparable> comparableObject(const COMPtr<IServiceProvider>& serviceProvider)
+{
+ COMPtr<IAccessibleComparable> comparable;
+ serviceProvider->QueryService(SID_AccessibleComparable, __uuidof(IAccessibleComparable), reinterpret_cast<void**>(&comparable));
+ return comparable;
+}
+
+bool AccessibilityController::addNotificationListener(JSObjectRef functionCallback)
+{
+ return false;
+}
+
+void AccessibilityController::removeNotificationListener()
+{
+}
+
+void AccessibilityController::winNotificationReceived(PlatformUIElement element, const string& eventName)
+{
+ for (HashMap<PlatformUIElement, JSObjectRef>::iterator it = m_notificationListeners.begin(); it != m_notificationListeners.end(); ++it) {
+ COMPtr<IServiceProvider> thisServiceProvider(Query, it->first);
+ if (!thisServiceProvider)
+ continue;
+
+ COMPtr<IAccessibleComparable> thisComparable = comparableObject(thisServiceProvider);
+ if (!thisComparable)
+ continue;
+
+ COMPtr<IServiceProvider> elementServiceProvider(Query, element);
+ if (!elementServiceProvider)
+ continue;
+
+ COMPtr<IAccessibleComparable> elementComparable = comparableObject(elementServiceProvider);
+ if (!elementComparable)
+ continue;
+
+ BOOL isSame = FALSE;
+ thisComparable->isSameObject(elementComparable.get(), &isSame);
+ if (!isSame)
+ continue;
+
+ JSRetainPtr<JSStringRef> jsNotification(Adopt, JSStringCreateWithUTF8CString(eventName.c_str()));
+ JSValueRef argument = JSValueMakeString(frame->globalContext(), jsNotification.get());
+ JSObjectCallAsFunction(frame->globalContext(), it->second, NULL, 1, &argument, NULL);
+ }
+}
+
+void AccessibilityController::winAddNotificationListener(PlatformUIElement element, JSObjectRef functionCallback)
+{
+ if (!m_notificationsEventHook)
+ m_notificationsEventHook = SetWinEventHook(EVENT_MIN, EVENT_MAX, GetModuleHandle(0), notificationListenerProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
+
+ JSValueProtect(frame->globalContext(), functionCallback);
+ m_notificationListeners.add(element, functionCallback);
+}
diff --git a/Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp b/Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
new file mode 100644
index 000000000..2863b5cfd
--- /dev/null
+++ b/Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityUIElement.h"
+
+#include "AccessibilityController.h"
+#include "DumpRenderTree.h"
+#include "FrameLoadDelegate.h"
+#include <JavaScriptCore/JSStringRef.h>
+#include <tchar.h>
+#include <string>
+
+using std::wstring;
+
+static COMPtr<IAccessibleComparable> comparableObject(IAccessible* accessible)
+{
+ COMPtr<IServiceProvider> serviceProvider(Query, accessible);
+ if (!serviceProvider)
+ return 0;
+ COMPtr<IAccessibleComparable> comparable;
+ serviceProvider->QueryService(SID_AccessibleComparable, __uuidof(IAccessibleComparable), reinterpret_cast<void**>(&comparable));
+ return comparable;
+}
+
+AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
+ : m_element(element)
+{
+}
+
+AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
+ : m_element(other.m_element)
+{
+}
+
+AccessibilityUIElement::~AccessibilityUIElement()
+{
+}
+
+bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
+{
+ COMPtr<IAccessibleComparable> comparable = comparableObject(m_element.get());
+ COMPtr<IAccessibleComparable> otherComparable = comparableObject(otherElement->m_element.get());
+ if (!comparable || !otherComparable)
+ return false;
+ BOOL isSame = FALSE;
+ if (FAILED(comparable->isSameObject(otherComparable.get(), &isSame)))
+ return false;
+ return isSame;
+}
+
+void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>&)
+{
+}
+
+void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&)
+{
+}
+
+void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children)
+{
+ long childCount;
+ if (FAILED(m_element->get_accChildCount(&childCount)))
+ return;
+ for (long i = 0; i < childCount; ++i)
+ children.append(getChildAtIndex(i));
+}
+
+void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length)
+{
+ long childCount;
+ unsigned appendedCount = 0;
+ if (FAILED(m_element->get_accChildCount(&childCount)))
+ return;
+ for (long i = location; i < childCount && appendedCount < length; ++i, ++appendedCount)
+ elementVector.append(getChildAtIndex(i));
+}
+
+int AccessibilityUIElement::childrenCount()
+{
+ long childCount;
+ m_element->get_accChildCount(&childCount);
+ return childCount;
+}
+
+int AccessibilityUIElement::rowCount()
+{
+ // FIXME: implement
+ return 0;
+}
+
+int AccessibilityUIElement::columnCount()
+{
+ // FIXME: implement
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
+{
+ // FIXME: implement
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ COMPtr<IDispatch> child;
+ VARIANT vChild;
+ ::VariantInit(&vChild);
+ V_VT(&vChild) = VT_I4;
+ // In MSAA, index 0 is the object itself.
+ V_I4(&vChild) = index + 1;
+ if (FAILED(m_element->get_accChild(vChild, &child)))
+ return 0;
+ return COMPtr<IAccessible>(Query, child);
+}
+
+unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
+{
+ // FIXME: implement
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::allAttributes()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfDocumentLinks()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+AccessibilityUIElement AccessibilityUIElement::titleUIElement()
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::parentElement()
+{
+ COMPtr<IDispatch> parent;
+ m_element->get_accParent(&parent);
+
+ COMPtr<IAccessible> parentAccessible(Query, parent);
+ return parentAccessible;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfChildren()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::parameterizedAttributeNames()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+static VARIANT& self()
+{
+ static VARIANT vSelf;
+ static bool haveInitialized;
+
+ if (!haveInitialized) {
+ ::VariantInit(&vSelf);
+ V_VT(&vSelf) = VT_I4;
+ V_I4(&vSelf) = CHILDID_SELF;
+ }
+ return vSelf;
+}
+
+JSStringRef AccessibilityUIElement::role()
+{
+ VARIANT vRole;
+ if (FAILED(m_element->get_accRole(self(), &vRole)))
+ return JSStringCreateWithCharacters(0, 0);
+
+ ASSERT(V_VT(&vRole) == VT_I4 || V_VT(&vRole) == VT_BSTR);
+
+ wstring result;
+ if (V_VT(&vRole) == VT_I4) {
+ unsigned roleTextLength = ::GetRoleText(V_I4(&vRole), 0, 0) + 1;
+
+ Vector<TCHAR> roleText(roleTextLength);
+
+ ::GetRoleText(V_I4(&vRole), roleText.data(), roleTextLength);
+
+ result = roleText.data();
+ } else if (V_VT(&vRole) == VT_BSTR)
+ result = wstring(V_BSTR(&vRole), ::SysStringLen(V_BSTR(&vRole)));
+
+ ::VariantClear(&vRole);
+
+ return JSStringCreateWithCharacters(result.data(), result.length());
+}
+
+JSStringRef AccessibilityUIElement::subrole()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::roleDescription()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::title()
+{
+ BSTR titleBSTR;
+ if (FAILED(m_element->get_accName(self(), &titleBSTR)) || !titleBSTR)
+ return JSStringCreateWithCharacters(0, 0);
+ wstring title(titleBSTR, SysStringLen(titleBSTR));
+ ::SysFreeString(titleBSTR);
+ return JSStringCreateWithCharacters(title.data(), title.length());
+}
+
+JSStringRef AccessibilityUIElement::description()
+{
+ BSTR descriptionBSTR;
+ if (FAILED(m_element->get_accDescription(self(), &descriptionBSTR)) || !descriptionBSTR)
+ return JSStringCreateWithCharacters(0, 0);
+ wstring description(descriptionBSTR, SysStringLen(descriptionBSTR));
+ ::SysFreeString(descriptionBSTR);
+ return JSStringCreateWithCharacters(description.data(), description.length());
+}
+
+JSStringRef AccessibilityUIElement::stringValue()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::language()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::helpText() const
+{
+ return 0;
+}
+
+double AccessibilityUIElement::x()
+{
+ long x, y, width, height;
+ if (FAILED(m_element->accLocation(&x, &y, &width, &height, self())))
+ return 0;
+ return x;
+}
+
+double AccessibilityUIElement::y()
+{
+ long x, y, width, height;
+ if (FAILED(m_element->accLocation(&x, &y, &width, &height, self())))
+ return 0;
+ return y;
+}
+
+double AccessibilityUIElement::width()
+{
+ long x, y, width, height;
+ if (FAILED(m_element->accLocation(&x, &y, &width, &height, self())))
+ return 0;
+ return width;
+}
+
+double AccessibilityUIElement::height()
+{
+ long x, y, width, height;
+ if (FAILED(m_element->accLocation(&x, &y, &width, &height, self())))
+ return 0;
+ return height;
+}
+
+double AccessibilityUIElement::clickPointX()
+{
+ return 0;
+}
+
+double AccessibilityUIElement::clickPointY()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::valueDescription()
+{
+ return 0;
+}
+
+static DWORD accessibilityState(COMPtr<IAccessible> element)
+{
+ VARIANT state;
+ element->get_accState(self(), &state);
+
+ ASSERT(V_VT(&state) == VT_I4);
+
+ DWORD result = state.lVal;
+ VariantClear(&state);
+
+ return result;
+}
+
+bool AccessibilityUIElement::isFocused() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isSelected() const
+{
+ DWORD state = accessibilityState(m_element);
+ return (state & STATE_SYSTEM_SELECTED) == STATE_SYSTEM_SELECTED;
+}
+
+int AccessibilityUIElement::hierarchicalLevel() const
+{
+ return 0;
+}
+
+bool AccessibilityUIElement::ariaIsGrabbed() const
+{
+ return false;
+}
+
+JSStringRef AccessibilityUIElement::ariaDropEffects() const
+{
+ return 0;
+}
+
+bool AccessibilityUIElement::isExpanded() const
+{
+ return false;
+}
+
+bool AccessibilityUIElement::isChecked() const
+{
+ VARIANT vState;
+ if (FAILED(m_element->get_accState(self(), &vState)))
+ return false;
+
+ return vState.lVal & STATE_SYSTEM_CHECKED;
+}
+
+JSStringRef AccessibilityUIElement::orientation() const
+{
+ return 0;
+}
+
+double AccessibilityUIElement::intValue() const
+{
+ BSTR valueBSTR;
+ if (FAILED(m_element->get_accValue(self(), &valueBSTR)) || !valueBSTR)
+ return 0;
+ wstring value(valueBSTR, SysStringLen(valueBSTR));
+ ::SysFreeString(valueBSTR);
+ TCHAR* ignored;
+ return _tcstod(value.data(), &ignored);
+}
+
+double AccessibilityUIElement::minValue()
+{
+ return 0;
+}
+
+double AccessibilityUIElement::maxValue()
+{
+ return 0;
+}
+
+bool AccessibilityUIElement::isActionSupported(JSStringRef action)
+{
+ return false;
+}
+
+bool AccessibilityUIElement::isEnabled()
+{
+ DWORD state = accessibilityState(m_element);
+ return (state & STATE_SYSTEM_UNAVAILABLE) != STATE_SYSTEM_UNAVAILABLE;
+}
+
+bool AccessibilityUIElement::isRequired() const
+{
+ return false;
+}
+
+
+int AccessibilityUIElement::insertionPointLineNumber()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::attributesOfColumnHeaders()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfRowHeaders()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfColumns()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfRows()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfVisibleCells()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributesOfHeader()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+int AccessibilityUIElement::indexInTable()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::rowIndexRange()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::columnIndexRange()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+int AccessibilityUIElement::lineForIndex(int)
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned)
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned)
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned)
+{
+ return false;
+}
+
+AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(AccessibilityUIElement* startElement, bool isDirectionNext, JSStringRef searchKey, JSStringRef searchText)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row)
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::selectedTextRange()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
+{
+}
+
+JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
+{
+ // FIXME: implement
+ return 0;
+}
+
+bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
+{
+ return false;
+}
+
+bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
+{
+ return false;
+}
+
+void AccessibilityUIElement::increment()
+{
+}
+
+void AccessibilityUIElement::decrement()
+{
+}
+
+void AccessibilityUIElement::showMenu()
+{
+ ASSERT(hasPopup());
+ m_element->accDoDefaultAction(self());
+}
+
+void AccessibilityUIElement::press()
+{
+ // FIXME: implement
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::accessibilityValue() const
+{
+ BSTR valueBSTR;
+ if (FAILED(m_element->get_accValue(self(), &valueBSTR)) || !valueBSTR)
+ return JSStringCreateWithCharacters(0, 0);
+
+ wstring value(valueBSTR, SysStringLen(valueBSTR));
+ ::SysFreeString(valueBSTR);
+
+ return JSStringCreateWithCharacters(value.data(), value.length());
+}
+
+
+JSStringRef AccessibilityUIElement::documentEncoding()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::documentURI()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::url()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
+{
+ if (!functionCallback)
+ return false;
+
+ sharedFrameLoadDelegate->accessibilityController()->winAddNotificationListener(m_element, functionCallback);
+ return true;
+}
+
+void AccessibilityUIElement::removeNotificationListener()
+{
+ // FIXME: implement
+}
+
+bool AccessibilityUIElement::isFocusable() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isSelectable() const
+{
+ DWORD state = accessibilityState(m_element);
+ return (state & STATE_SYSTEM_SELECTABLE) == STATE_SYSTEM_SELECTABLE;
+}
+
+bool AccessibilityUIElement::isMultiSelectable() const
+{
+ DWORD multiSelectable = STATE_SYSTEM_EXTSELECTABLE | STATE_SYSTEM_MULTISELECTABLE;
+ DWORD state = accessibilityState(m_element);
+ return (state & multiSelectable) == multiSelectable;
+}
+
+bool AccessibilityUIElement::isSelectedOptionActive() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isVisible() const
+{
+ DWORD state = accessibilityState(m_element);
+ return (state & STATE_SYSTEM_INVISIBLE) != STATE_SYSTEM_INVISIBLE;
+}
+
+bool AccessibilityUIElement::isOffScreen() const
+{
+ DWORD state = accessibilityState(m_element);
+ return (state & STATE_SYSTEM_OFFSCREEN) == STATE_SYSTEM_OFFSCREEN;
+}
+
+bool AccessibilityUIElement::isCollapsed() const
+{
+ DWORD state = accessibilityState(m_element);
+ return (state & STATE_SYSTEM_COLLAPSED) == STATE_SYSTEM_COLLAPSED;
+}
+
+bool AccessibilityUIElement::isIgnored() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::hasPopup() const
+{
+ DWORD state = accessibilityState(m_element);
+ return (state & STATE_SYSTEM_HASPOPUP) == STATE_SYSTEM_HASPOPUP;
+}
+
+void AccessibilityUIElement::takeFocus()
+{
+ m_element->accSelect(SELFLAG_TAKEFOCUS, self());
+}
+
+void AccessibilityUIElement::takeSelection()
+{
+ m_element->accSelect(SELFLAG_TAKESELECTION, self());
+}
+
+void AccessibilityUIElement::addSelection()
+{
+ m_element->accSelect(SELFLAG_ADDSELECTION, self());
+}
+
+void AccessibilityUIElement::removeSelection()
+{
+ m_element->accSelect(SELFLAG_REMOVESELECTION, self());
+}
diff --git a/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp b/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp
new file mode 100644
index 000000000..1bc4678b1
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DRTDesktopNotificationPresenter.h"
+
+#include "DumpRenderTree.h"
+#include "LayoutTestController.h"
+#include <JavaScriptCore/JSStringRef.h>
+#include <JavaScriptCore/JSStringRefBSTR.h>
+#include <WebCore/NotificationPresenter.h>
+
+DRTDesktopNotificationPresenter::DRTDesktopNotificationPresenter()
+ : m_refCount(1) {}
+
+HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::QueryInterface(REFIID riid, void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IsEqualGUID(riid, IID_IUnknown))
+ *ppvObject = static_cast<DRTDesktopNotificationPresenter*>(this);
+ else if (IsEqualGUID(riid, IID_IWebDesktopNotificationsDelegate))
+ *ppvObject = static_cast<DRTDesktopNotificationPresenter*>(this);
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE DRTDesktopNotificationPresenter::AddRef()
+{
+ return ++m_refCount;
+}
+
+ULONG STDMETHODCALLTYPE DRTDesktopNotificationPresenter::Release()
+{
+ ULONG newRef = --m_refCount;
+ if (!newRef)
+ delete(this);
+
+ return newRef;
+}
+
+HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::showDesktopNotification(
+ /* [in] */ IWebDesktopNotification* notification)
+{
+ BSTR title, text, url;
+ BOOL html;
+
+ if (!notification->isHTML(&html) && html) {
+ notification->contentsURL(&url);
+ printf("DESKTOP NOTIFICATION: contents at %S\n", url ? url : L"");
+ } else {
+ notification->iconURL(&url);
+ notification->title(&title);
+ notification->text(&text);
+ printf("DESKTOP NOTIFICATION: icon %S, title %S, text %S\n",
+ url ? url : L"",
+ title ? title : L"",
+ text ? text : L"");
+ }
+
+ // In this stub implementation, the notification is displayed immediately;
+ // we dispatch the display event to mimic that.
+ notification->notifyDisplay();
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::cancelDesktopNotification(
+ /* [in] */ IWebDesktopNotification* notification)
+{
+ BSTR identifier;
+ BOOL html;
+ notification->isHTML(&html);
+ if (html)
+ notification->contentsURL(&identifier);
+ else
+ notification->title(&identifier);
+
+ printf("DESKTOP NOTIFICATION CLOSED: %S\n", identifier ? identifier : L"");
+ notification->notifyClose(false);
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::notificationDestroyed(
+ /* [in] */ IWebDesktopNotification* notification)
+{
+ // Since in these tests events happen immediately, we don't hold on to
+ // Notification pointers. So there's no cleanup to do.
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::checkNotificationPermission(
+ /* [in] */ BSTR origin,
+ /* [out, retval] */ int* result)
+{
+#if ENABLE(NOTIFICATIONS)
+ JSStringRef jsOrigin = JSStringCreateWithBSTR(origin);
+ bool allowed = ::gLayoutTestController->checkDesktopNotificationPermission(jsOrigin);
+
+ if (allowed)
+ *result = WebCore::NotificationPresenter::PermissionAllowed;
+ else
+ *result = WebCore::NotificationPresenter::PermissionDenied;
+
+ JSStringRelease(jsOrigin);
+#endif
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE DRTDesktopNotificationPresenter::requestNotificationPermission(
+ /* [in] */ BSTR origin)
+{
+ printf("DESKTOP NOTIFICATION PERMISSION REQUESTED: %S\n", origin ? origin : L"");
+ return S_OK;
+}
diff --git a/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.h b/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.h
new file mode 100644
index 000000000..567984503
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DRTDesktopNotificationPresenter.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 DRTDesktopNotificationPresenter_h
+#define DRTDesktopNotificationPresenter_h
+
+#include <WebKit/WebKit.h>
+#include <wtf/OwnPtr.h>
+#include <windef.h>
+
+class DRTDesktopNotificationPresenter : public IWebDesktopNotificationsDelegate {
+public:
+ DRTDesktopNotificationPresenter();
+
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // IWebDesktopNotificationsDelegate
+ virtual HRESULT STDMETHODCALLTYPE showDesktopNotification(
+ /* [in] */ IWebDesktopNotification* notification);
+
+ virtual HRESULT STDMETHODCALLTYPE cancelDesktopNotification(
+ /* [in] */ IWebDesktopNotification* notification);
+
+ virtual HRESULT STDMETHODCALLTYPE notificationDestroyed(
+ /* [in] */ IWebDesktopNotification* notification);
+
+ virtual HRESULT STDMETHODCALLTYPE checkNotificationPermission(
+ /* [in] */ BSTR origin,
+ /* [out, retval] */ int* result);
+
+ virtual HRESULT STDMETHODCALLTYPE requestNotificationPermission(
+ /* [in] */ BSTR origin);
+
+private:
+ ULONG m_refCount;
+};
+
+#endif
diff --git a/Tools/DumpRenderTree/win/DraggingInfo.h b/Tools/DumpRenderTree/win/DraggingInfo.h
new file mode 100644
index 000000000..98982bc16
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DraggingInfo.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 DraggingInfo_h
+#define DraggingInfo_h
+
+#include <objidl.h>
+
+class DraggingInfo {
+public:
+ DraggingInfo(IDataObject* object, IDropSource* source)
+ : m_object(object)
+ , m_source(source)
+ , m_performedDropEffect(DROPEFFECT_NONE)
+ {
+ m_object->AddRef();
+ m_source->AddRef();
+ }
+
+ ~DraggingInfo()
+ {
+ if (m_object)
+ m_object->Release();
+ m_object = 0;
+ if (m_source)
+ m_source->Release();
+ m_source = 0;
+ }
+
+ IDataObject* dataObject() const { return m_object; }
+ IDropSource* dropSource() const { return m_source; }
+
+ DWORD performedDropEffect() const { return m_performedDropEffect; }
+ void setPerformedDropEffect(DWORD effect) { m_performedDropEffect = effect; }
+
+private:
+ IDataObject* m_object;
+ IDropSource* m_source;
+ DWORD m_performedDropEffect;
+};
+
+#endif // !defined(DraggingInfo_h)
diff --git a/Tools/DumpRenderTree/win/DumpRenderTree.cpp b/Tools/DumpRenderTree/win/DumpRenderTree.cpp
new file mode 100644
index 000000000..1ec5c5e60
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTree.cpp
@@ -0,0 +1,1459 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h"
+
+#include "EditingDelegate.h"
+#include "FrameLoadDelegate.h"
+#include "HistoryDelegate.h"
+#include "LayoutTestController.h"
+#include "PixelDumpSupport.h"
+#include "PolicyDelegate.h"
+#include "ResourceLoadDelegate.h"
+#include "UIDelegate.h"
+#include "WorkQueueItem.h"
+#include "WorkQueue.h"
+
+#include <comutil.h>
+#include <fcntl.h>
+#include <io.h>
+#include <math.h>
+#include <pthread.h>
+#include <shlwapi.h>
+#include <stdio.h>
+#include <string.h>
+#include <tchar.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <windows.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <WebKit/WebKit.h>
+#include <WebKit/WebKitCOMAPI.h>
+
+#if USE(CFNETWORK)
+#include <CFNetwork/CFURLCachePriv.h>
+#endif
+
+#if USE(CFNETWORK)
+#include <CFNetwork/CFHTTPCookiesPriv.h>
+#endif
+
+using namespace std;
+
+#ifdef DEBUG_ALL
+const LPWSTR TestPluginDir = L"TestNetscapePlugin_Debug";
+#else
+const LPWSTR TestPluginDir = L"TestNetscapePlugin";
+#endif
+
+static LPCWSTR fontsEnvironmentVariable = L"WEBKIT_TESTFONTS";
+#define USE_MAC_FONTS
+
+const LPCWSTR kDumpRenderTreeClassName = L"DumpRenderTreeWindow";
+
+static bool dumpTree = true;
+static bool dumpPixels;
+static bool dumpAllPixels;
+static bool printSeparators;
+static bool leakChecking = false;
+static bool threaded = false;
+static bool forceComplexText = false;
+static bool printSupportedFeatures = false;
+static RetainPtr<CFStringRef> persistentUserStyleSheetLocation;
+
+volatile bool done;
+// This is the topmost frame that is loading, during a given load, or nil when no load is
+// in progress. Usually this is the same as the main frame, but not always. In the case
+// where a frameset is loaded, and then new content is loaded into one of the child frames,
+// that child frame is the "topmost frame that is loading".
+IWebFrame* topLoadingFrame; // !nil iff a load is in progress
+static COMPtr<IWebHistoryItem> prevTestBFItem; // current b/f item at the end of the previous test
+PolicyDelegate* policyDelegate;
+COMPtr<FrameLoadDelegate> sharedFrameLoadDelegate;
+COMPtr<UIDelegate> sharedUIDelegate;
+COMPtr<EditingDelegate> sharedEditingDelegate;
+COMPtr<HistoryDelegate> sharedHistoryDelegate;
+
+IWebFrame* frame;
+HWND webViewWindow;
+
+RefPtr<LayoutTestController> gLayoutTestController;
+
+UINT_PTR waitToDumpWatchdog = 0;
+
+void setPersistentUserStyleSheetLocation(CFStringRef url)
+{
+ persistentUserStyleSheetLocation = url;
+}
+
+bool setAlwaysAcceptCookies(bool alwaysAcceptCookies)
+{
+#if USE(CFNETWORK)
+ COMPtr<IWebCookieManager> cookieManager;
+ if (FAILED(WebKitCreateInstance(CLSID_WebCookieManager, 0, IID_IWebCookieManager, reinterpret_cast<void**>(&cookieManager))))
+ return false;
+ CFHTTPCookieStorageRef cookieStorage = 0;
+ if (FAILED(cookieManager->cookieStorage(&cookieStorage)) || !cookieStorage)
+ return false;
+
+ WebKitCookieStorageAcceptPolicy cookieAcceptPolicy = alwaysAcceptCookies ? WebKitCookieStorageAcceptPolicyAlways : WebKitCookieStorageAcceptPolicyOnlyFromMainDocumentDomain;
+ CFHTTPCookieStorageSetCookieAcceptPolicy(cookieStorage, cookieAcceptPolicy);
+ return true;
+#else
+ // FIXME: Implement!
+ return false;
+#endif
+}
+
+static RetainPtr<CFStringRef> substringFromIndex(CFStringRef string, CFIndex index)
+{
+ return RetainPtr<CFStringRef>(AdoptCF, CFStringCreateWithSubstring(kCFAllocatorDefault, string, CFRangeMake(index, CFStringGetLength(string) - index)));
+}
+
+wstring urlSuitableForTestResult(const wstring& urlString)
+{
+ RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(urlString.c_str()), urlString.length() * sizeof(wstring::value_type), kCFStringEncodingUTF16, 0));
+
+ RetainPtr<CFStringRef> scheme(AdoptCF, CFURLCopyScheme(url.get()));
+ if (scheme && CFStringCompare(scheme.get(), CFSTR("file"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)
+ return urlString;
+
+ COMPtr<IWebDataSource> dataSource;
+ if (FAILED(frame->dataSource(&dataSource))) {
+ if (FAILED(frame->provisionalDataSource(&dataSource)))
+ return urlString;
+ }
+
+ COMPtr<IWebMutableURLRequest> request;
+ if (FAILED(dataSource->request(&request)))
+ return urlString;
+
+ _bstr_t requestURLString;
+ if (FAILED(request->URL(requestURLString.GetAddress())))
+ return urlString;
+
+ RetainPtr<CFURLRef> requestURL(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(requestURLString.GetBSTR()), requestURLString.length() * sizeof(OLECHAR), kCFStringEncodingUTF16, 0));
+ RetainPtr<CFURLRef> baseURL(AdoptCF, CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, requestURL.get()));
+
+ RetainPtr<CFStringRef> basePath(AdoptCF, CFURLCopyPath(baseURL.get()));
+ RetainPtr<CFStringRef> path(AdoptCF, CFURLCopyPath(url.get()));
+
+ return cfStringRefToWString(substringFromIndex(path.get(), CFStringGetLength(basePath.get())).get());
+}
+
+wstring lastPathComponent(const wstring& urlString)
+{
+ if (urlString.empty())
+ return urlString;
+
+ RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(urlString.c_str()), urlString.length() * sizeof(wstring::value_type), kCFStringEncodingUTF16, 0));
+ RetainPtr<CFStringRef> lastPathComponent(CFURLCopyLastPathComponent(url.get()));
+
+ return cfStringRefToWString(lastPathComponent.get());
+}
+
+static string toUTF8(const wchar_t* wideString, size_t length)
+{
+ int result = WideCharToMultiByte(CP_UTF8, 0, wideString, length + 1, 0, 0, 0, 0);
+ Vector<char> utf8Vector(result);
+ result = WideCharToMultiByte(CP_UTF8, 0, wideString, length + 1, utf8Vector.data(), result, 0, 0);
+ if (!result)
+ return string();
+
+ return string(utf8Vector.data(), utf8Vector.size() - 1);
+}
+
+string toUTF8(BSTR bstr)
+{
+ return toUTF8(bstr, SysStringLen(bstr));
+}
+
+string toUTF8(const wstring& wideString)
+{
+ return toUTF8(wideString.c_str(), wideString.length());
+}
+
+wstring cfStringRefToWString(CFStringRef cfStr)
+{
+ Vector<wchar_t> v(CFStringGetLength(cfStr));
+ CFStringGetCharacters(cfStr, CFRangeMake(0, CFStringGetLength(cfStr)), (UniChar *)v.data());
+
+ return wstring(v.data(), v.size());
+}
+
+static LRESULT CALLBACK DumpRenderTreeWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_DESTROY:
+ for (unsigned i = openWindows().size() - 1; i >= 0; --i) {
+ if (openWindows()[i] == hWnd) {
+ openWindows().remove(i);
+ windowToWebViewMap().remove(hWnd);
+ break;
+ }
+ }
+ return 0;
+ break;
+ default:
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+ }
+}
+
+static const wstring& exePath()
+{
+ static wstring path;
+ static bool initialized;
+
+ if (initialized)
+ return path;
+ initialized = true;
+
+ TCHAR buffer[MAX_PATH];
+ GetModuleFileName(GetModuleHandle(0), buffer, ARRAYSIZE(buffer));
+ path = buffer;
+ int lastSlash = path.rfind('\\');
+ if (lastSlash != -1 && lastSlash + 1 < path.length())
+ path = path.substr(0, lastSlash + 1);
+
+ return path;
+}
+
+static const wstring& fontsPath()
+{
+ static wstring path;
+ static bool initialized;
+
+ if (initialized)
+ return path;
+ initialized = true;
+
+ DWORD size = GetEnvironmentVariable(fontsEnvironmentVariable, 0, 0);
+ Vector<TCHAR> buffer(size);
+ if (GetEnvironmentVariable(fontsEnvironmentVariable, buffer.data(), buffer.size())) {
+ path = buffer.data();
+ if (path[path.length() - 1] != '\\')
+ path.append(L"\\");
+ return path;
+ }
+
+ path = exePath() + TEXT("DumpRenderTree.resources\\");
+ return path;
+}
+
+static void addQTDirToPATH()
+{
+ static LPCWSTR pathEnvironmentVariable = L"PATH";
+ static LPCWSTR quickTimeKeyName = L"Software\\Apple Computer, Inc.\\QuickTime";
+ static LPCWSTR quickTimeSysDir = L"QTSysDir";
+ static bool initialized;
+
+ if (initialized)
+ return;
+ initialized = true;
+
+ // Get the QuickTime dll directory from the registry. The key can be in either HKLM or HKCU.
+ WCHAR qtPath[MAX_PATH];
+ DWORD qtPathBufferLen = sizeof(qtPath);
+ DWORD keyType;
+ HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen);
+ if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ) {
+ qtPathBufferLen = sizeof(qtPath);
+ result = SHGetValue(HKEY_CURRENT_USER, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen);
+ if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ)
+ return;
+ }
+
+ // Read the current PATH.
+ DWORD pathSize = GetEnvironmentVariableW(pathEnvironmentVariable, 0, 0);
+ Vector<WCHAR> oldPath(pathSize);
+ if (!GetEnvironmentVariableW(pathEnvironmentVariable, oldPath.data(), oldPath.size()))
+ return;
+
+ // And add the QuickTime dll.
+ wstring newPath;
+ newPath.append(qtPath);
+ newPath.append(L";");
+ newPath.append(oldPath.data(), oldPath.size());
+ SetEnvironmentVariableW(pathEnvironmentVariable, newPath.data());
+}
+
+#ifdef DEBUG_ALL
+#define WEBKITDLL TEXT("WebKit_debug.dll")
+#else
+#define WEBKITDLL TEXT("WebKit.dll")
+#endif
+
+static void initialize()
+{
+ if (HMODULE webKitModule = LoadLibrary(WEBKITDLL))
+ if (FARPROC dllRegisterServer = GetProcAddress(webKitModule, "DllRegisterServer"))
+ dllRegisterServer();
+
+ // Init COM
+ OleInitialize(0);
+
+ static LPCTSTR fontsToInstall[] = {
+ TEXT("AHEM____.ttf"),
+ TEXT("Apple Chancery.ttf"),
+ TEXT("Courier Bold.ttf"),
+ TEXT("Courier.ttf"),
+ TEXT("Helvetica Bold Oblique.ttf"),
+ TEXT("Helvetica Bold.ttf"),
+ TEXT("Helvetica Oblique.ttf"),
+ TEXT("Helvetica.ttf"),
+ TEXT("Helvetica Neue Bold Italic.ttf"),
+ TEXT("Helvetica Neue Bold.ttf"),
+ TEXT("Helvetica Neue Condensed Black.ttf"),
+ TEXT("Helvetica Neue Condensed Bold.ttf"),
+ TEXT("Helvetica Neue Italic.ttf"),
+ TEXT("Helvetica Neue Light Italic.ttf"),
+ TEXT("Helvetica Neue Light.ttf"),
+ TEXT("Helvetica Neue UltraLight Italic.ttf"),
+ TEXT("Helvetica Neue UltraLight.ttf"),
+ TEXT("Helvetica Neue.ttf"),
+ TEXT("Lucida Grande.ttf"),
+ TEXT("Lucida Grande Bold.ttf"),
+ TEXT("Monaco.ttf"),
+ TEXT("Papyrus.ttf"),
+ TEXT("Times Bold Italic.ttf"),
+ TEXT("Times Bold.ttf"),
+ TEXT("Times Italic.ttf"),
+ TEXT("Times Roman.ttf"),
+ TEXT("WebKit Layout Tests 2.ttf"),
+ TEXT("WebKit Layout Tests.ttf"),
+ TEXT("WebKitWeightWatcher100.ttf"),
+ TEXT("WebKitWeightWatcher200.ttf"),
+ TEXT("WebKitWeightWatcher300.ttf"),
+ TEXT("WebKitWeightWatcher400.ttf"),
+ TEXT("WebKitWeightWatcher500.ttf"),
+ TEXT("WebKitWeightWatcher600.ttf"),
+ TEXT("WebKitWeightWatcher700.ttf"),
+ TEXT("WebKitWeightWatcher800.ttf"),
+ TEXT("WebKitWeightWatcher900.ttf")
+ };
+
+ wstring resourcesPath = fontsPath();
+
+ COMPtr<IWebTextRenderer> textRenderer;
+ if (SUCCEEDED(WebKitCreateInstance(CLSID_WebTextRenderer, 0, IID_IWebTextRenderer, (void**)&textRenderer)))
+ for (int i = 0; i < ARRAYSIZE(fontsToInstall); ++i)
+ textRenderer->registerPrivateFont(wstring(resourcesPath + fontsToInstall[i]).c_str());
+
+ // Add the QuickTime dll directory to PATH or QT 7.6 will fail to initialize on systems
+ // linked with older versions of qtmlclientlib.dll.
+ addQTDirToPATH();
+
+ // Register a host window
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = DumpRenderTreeWndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = GetModuleHandle(0);
+ wcex.hIcon = 0;
+ wcex.hCursor = LoadCursor(0, IDC_ARROW);
+ wcex.hbrBackground = 0;
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = kDumpRenderTreeClassName;
+ wcex.hIconSm = 0;
+
+ RegisterClassEx(&wcex);
+}
+
+void displayWebView()
+{
+ ::InvalidateRect(webViewWindow, 0, TRUE);
+ ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
+}
+
+void dumpFrameScrollPosition(IWebFrame* frame)
+{
+ if (!frame)
+ return;
+
+ COMPtr<IWebFramePrivate> framePrivate;
+ if (FAILED(frame->QueryInterface(&framePrivate)))
+ return;
+
+ SIZE scrollPosition;
+ if (FAILED(framePrivate->scrollOffset(&scrollPosition)))
+ return;
+
+ if (abs(scrollPosition.cx) > 0.00000001 || abs(scrollPosition.cy) > 0.00000001) {
+ COMPtr<IWebFrame> parent;
+ if (FAILED(frame->parentFrame(&parent)))
+ return;
+ if (parent) {
+ BSTR name;
+ if (FAILED(frame->name(&name)))
+ return;
+ printf("frame '%S' ", name ? name : L"");
+ SysFreeString(name);
+ }
+ printf("scrolled to %.f,%.f\n", (double)scrollPosition.cx, (double)scrollPosition.cy);
+ }
+
+ if (::gLayoutTestController->dumpChildFrameScrollPositions()) {
+ COMPtr<IEnumVARIANT> enumKids;
+ if (FAILED(frame->childFrames(&enumKids)))
+ return;
+ VARIANT var;
+ VariantInit(&var);
+ while (enumKids->Next(1, &var, 0) == S_OK) {
+ ASSERT(V_VT(&var) == VT_UNKNOWN);
+ COMPtr<IWebFrame> framePtr;
+ V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
+ dumpFrameScrollPosition(framePtr.get());
+ VariantClear(&var);
+ }
+ }
+}
+
+static wstring dumpFramesAsText(IWebFrame* frame)
+{
+ if (!frame)
+ return L"";
+
+ COMPtr<IDOMDocument> document;
+ if (FAILED(frame->DOMDocument(&document)))
+ return L"";
+
+ COMPtr<IDOMElement> documentElement;
+ if (FAILED(document->documentElement(&documentElement)))
+ return L"";
+
+ wstring result;
+
+ // Add header for all but the main frame.
+ COMPtr<IWebFrame> parent;
+ if (FAILED(frame->parentFrame(&parent)))
+ return L"";
+ if (parent) {
+ BSTR name = L"";
+ if (FAILED(frame->name(&name)))
+ return L"";
+
+ result.append(L"\n--------\nFrame: '");
+ result.append(name ? name : L"", SysStringLen(name));
+ result.append(L"'\n--------\n");
+
+ SysFreeString(name);
+ }
+
+ BSTR innerText = 0;
+ COMPtr<IDOMElementPrivate> docPrivate;
+ if (SUCCEEDED(documentElement->QueryInterface(&docPrivate)))
+ docPrivate->innerText(&innerText);
+
+ result.append(innerText ? innerText : L"", SysStringLen(innerText));
+ result.append(L"\n");
+
+ SysFreeString(innerText);
+
+ if (::gLayoutTestController->dumpChildFramesAsText()) {
+ COMPtr<IEnumVARIANT> enumKids;
+ if (FAILED(frame->childFrames(&enumKids)))
+ return L"";
+ VARIANT var;
+ VariantInit(&var);
+ while (enumKids->Next(1, &var, 0) == S_OK) {
+ ASSERT(V_VT(&var) == VT_UNKNOWN);
+ COMPtr<IWebFrame> framePtr;
+ V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
+ result.append(dumpFramesAsText(framePtr.get()));
+ VariantClear(&var);
+ }
+ }
+
+ return result;
+}
+
+static int compareHistoryItems(const void* item1, const void* item2)
+{
+ COMPtr<IWebHistoryItemPrivate> itemA;
+ if (FAILED((*(COMPtr<IUnknown>*)item1)->QueryInterface(&itemA)))
+ return 0;
+
+ COMPtr<IWebHistoryItemPrivate> itemB;
+ if (FAILED((*(COMPtr<IUnknown>*)item2)->QueryInterface(&itemB)))
+ return 0;
+
+ BSTR targetA;
+ if (FAILED(itemA->target(&targetA)))
+ return 0;
+
+ BSTR targetB;
+ if (FAILED(itemB->target(&targetB))) {
+ SysFreeString(targetA);
+ return 0;
+ }
+
+ int result = wcsicmp(wstring(targetA, SysStringLen(targetA)).c_str(), wstring(targetB, SysStringLen(targetB)).c_str());
+ SysFreeString(targetA);
+ SysFreeString(targetB);
+ return result;
+}
+
+static void dumpHistoryItem(IWebHistoryItem* item, int indent, bool current)
+{
+ assert(item);
+
+ int start = 0;
+ if (current) {
+ printf("curr->");
+ start = 6;
+ }
+ for (int i = start; i < indent; i++)
+ putchar(' ');
+
+ BSTR url;
+ if (FAILED(item->URLString(&url)))
+ return;
+
+ if (wcsstr(url, L"file:/") == url) {
+ static wchar_t* layoutTestsString = L"/LayoutTests/";
+ static wchar_t* fileTestString = L"(file test):";
+
+ wchar_t* result = wcsstr(url, layoutTestsString);
+ if (result == NULL)
+ return;
+ wchar_t* start = result + wcslen(layoutTestsString);
+
+ BSTR newURL = SysAllocStringLen(NULL, SysStringLen(url));
+ wcscpy(newURL, fileTestString);
+ wcscpy(newURL + wcslen(fileTestString), start);
+
+ SysFreeString(url);
+ url = newURL;
+ }
+
+ printf("%S", url ? url : L"");
+ SysFreeString(url);
+
+ COMPtr<IWebHistoryItemPrivate> itemPrivate;
+ if (FAILED(item->QueryInterface(&itemPrivate)))
+ return;
+
+ BSTR target;
+ if (FAILED(itemPrivate->target(&target)))
+ return;
+ if (SysStringLen(target))
+ printf(" (in frame \"%S\")", target);
+ SysFreeString(target);
+ BOOL isTargetItem = FALSE;
+ if (FAILED(itemPrivate->isTargetItem(&isTargetItem)))
+ return;
+ if (isTargetItem)
+ printf(" **nav target**");
+ putchar('\n');
+
+ unsigned kidsCount;
+ SAFEARRAY* arrPtr;
+ if (FAILED(itemPrivate->children(&kidsCount, &arrPtr)) || !kidsCount)
+ return;
+
+ Vector<COMPtr<IUnknown> > kidsVector;
+
+ LONG lowerBound;
+ if (FAILED(::SafeArrayGetLBound(arrPtr, 1, &lowerBound)))
+ goto exit;
+
+ LONG upperBound;
+ if (FAILED(::SafeArrayGetUBound(arrPtr, 1, &upperBound)))
+ goto exit;
+
+ LONG length = upperBound - lowerBound + 1;
+ if (!length)
+ goto exit;
+ ASSERT(length == kidsCount);
+
+ IUnknown** safeArrayData;
+ if (FAILED(::SafeArrayAccessData(arrPtr, (void**)&safeArrayData)))
+ goto exit;
+
+ for (int i = 0; i < length; ++i)
+ kidsVector.append(safeArrayData[i]);
+ ::SafeArrayUnaccessData(arrPtr);
+
+ // must sort to eliminate arbitrary result ordering which defeats reproducible testing
+ qsort(kidsVector.data(), kidsCount, sizeof(kidsVector[0]), compareHistoryItems);
+
+ for (unsigned i = 0; i < kidsCount; ++i) {
+ COMPtr<IWebHistoryItem> item;
+ kidsVector[i]->QueryInterface(&item);
+ dumpHistoryItem(item.get(), indent + 4, false);
+ }
+
+exit:
+ if (arrPtr && SUCCEEDED(::SafeArrayUnlock(arrPtr)))
+ ::SafeArrayDestroy(arrPtr);
+}
+
+static void dumpBackForwardList(IWebView* webView)
+{
+ ASSERT(webView);
+
+ printf("\n============== Back Forward List ==============\n");
+
+ COMPtr<IWebBackForwardList> bfList;
+ if (FAILED(webView->backForwardList(&bfList)))
+ return;
+
+ // Print out all items in the list after prevTestBFItem, which was from the previous test
+ // Gather items from the end of the list, the print them out from oldest to newest
+
+ Vector<COMPtr<IUnknown> > itemsToPrint;
+
+ int forwardListCount;
+ if (FAILED(bfList->forwardListCount(&forwardListCount)))
+ return;
+
+ for (int i = forwardListCount; i > 0; --i) {
+ COMPtr<IWebHistoryItem> item;
+ if (FAILED(bfList->itemAtIndex(i, &item)))
+ return;
+ // something is wrong if the item from the last test is in the forward part of the b/f list
+ assert(item != prevTestBFItem);
+ COMPtr<IUnknown> itemUnknown;
+ item->QueryInterface(&itemUnknown);
+ itemsToPrint.append(itemUnknown);
+ }
+
+ COMPtr<IWebHistoryItem> currentItem;
+ if (FAILED(bfList->currentItem(&currentItem)))
+ return;
+
+ assert(currentItem != prevTestBFItem);
+ COMPtr<IUnknown> currentItemUnknown;
+ currentItem->QueryInterface(&currentItemUnknown);
+ itemsToPrint.append(currentItemUnknown);
+ int currentItemIndex = itemsToPrint.size() - 1;
+
+ int backListCount;
+ if (FAILED(bfList->backListCount(&backListCount)))
+ return;
+
+ for (int i = -1; i >= -backListCount; --i) {
+ COMPtr<IWebHistoryItem> item;
+ if (FAILED(bfList->itemAtIndex(i, &item)))
+ return;
+ if (item == prevTestBFItem)
+ break;
+ COMPtr<IUnknown> itemUnknown;
+ item->QueryInterface(&itemUnknown);
+ itemsToPrint.append(itemUnknown);
+ }
+
+ for (int i = itemsToPrint.size() - 1; i >= 0; --i) {
+ COMPtr<IWebHistoryItem> historyItemToPrint;
+ itemsToPrint[i]->QueryInterface(&historyItemToPrint);
+ dumpHistoryItem(historyItemToPrint.get(), 8, i == currentItemIndex);
+ }
+
+ printf("===============================================\n");
+}
+
+static void dumpBackForwardListForAllWindows()
+{
+ unsigned count = openWindows().size();
+ for (unsigned i = 0; i < count; i++) {
+ HWND window = openWindows()[i];
+ IWebView* webView = windowToWebViewMap().get(window).get();
+ dumpBackForwardList(webView);
+ }
+}
+
+static void invalidateAnyPreviousWaitToDumpWatchdog()
+{
+ if (!waitToDumpWatchdog)
+ return;
+
+ KillTimer(0, waitToDumpWatchdog);
+ waitToDumpWatchdog = 0;
+}
+
+void dump()
+{
+ invalidateAnyPreviousWaitToDumpWatchdog();
+
+ COMPtr<IWebDataSource> dataSource;
+ if (SUCCEEDED(frame->dataSource(&dataSource))) {
+ COMPtr<IWebURLResponse> response;
+ if (SUCCEEDED(dataSource->response(&response)) && response) {
+ BSTR mimeType;
+ if (SUCCEEDED(response->MIMEType(&mimeType)) && !_tcscmp(mimeType, TEXT("text/plain"))) {
+ ::gLayoutTestController->setDumpAsText(true);
+ ::gLayoutTestController->setGeneratePixelResults(false);
+ }
+ SysFreeString(mimeType);
+ }
+ }
+
+ BSTR resultString = 0;
+
+ if (dumpTree) {
+ if (::gLayoutTestController->dumpAsText()) {
+ ::InvalidateRect(webViewWindow, 0, TRUE);
+ ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
+ wstring result = dumpFramesAsText(frame);
+ resultString = SysAllocStringLen(result.data(), result.size());
+ } else {
+ bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg\\W3C-SVG-1.1") != string::npos);
+ unsigned width;
+ unsigned height;
+ if (isSVGW3CTest) {
+ width = 480;
+ height = 360;
+ } else {
+ width = LayoutTestController::maxViewWidth;
+ height = LayoutTestController::maxViewHeight;
+ }
+
+ ::SetWindowPos(webViewWindow, 0, 0, 0, width, height, SWP_NOMOVE);
+ ::InvalidateRect(webViewWindow, 0, TRUE);
+ ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
+
+ COMPtr<IWebFramePrivate> framePrivate;
+ if (FAILED(frame->QueryInterface(&framePrivate)))
+ goto fail;
+ framePrivate->renderTreeAsExternalRepresentation(gLayoutTestController->isPrinting(), &resultString);
+ }
+
+ if (!resultString)
+ printf("ERROR: nil result from %s", ::gLayoutTestController->dumpAsText() ? "IDOMElement::innerText" : "IFrameViewPrivate::renderTreeAsExternalRepresentation");
+ else {
+ unsigned stringLength = SysStringLen(resultString);
+ int bufferSize = ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, 0, 0, 0, 0);
+ char* buffer = (char*)malloc(bufferSize + 1);
+ ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, buffer, bufferSize + 1, 0, 0);
+ fwrite(buffer, 1, bufferSize, stdout);
+ free(buffer);
+ if (!::gLayoutTestController->dumpAsText())
+ dumpFrameScrollPosition(frame);
+ }
+ if (::gLayoutTestController->dumpBackForwardList())
+ dumpBackForwardListForAllWindows();
+ }
+
+ if (printSeparators) {
+ puts("#EOF"); // terminate the content block
+ fputs("#EOF\n", stderr);
+ fflush(stdout);
+ fflush(stderr);
+ }
+
+ if (dumpPixels
+ && gLayoutTestController->generatePixelResults()
+ && !gLayoutTestController->dumpDOMAsWebArchive()
+ && !gLayoutTestController->dumpSourceAsWebArchive())
+ dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash());
+
+ printf("#EOF\n"); // terminate the (possibly empty) pixels block
+ fflush(stdout);
+
+fail:
+ SysFreeString(resultString);
+ // This will exit from our message loop.
+ PostQuitMessage(0);
+ done = true;
+}
+
+static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "/loading/") || strstr(pathOrURL, "\\loading\\");
+}
+
+static bool shouldLogHistoryDelegates(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "/globalhistory/") || strstr(pathOrURL, "\\globalhistory\\");
+}
+
+static bool shouldOpenWebInspector(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "/inspector/") || strstr(pathOrURL, "\\inspector\\");
+}
+
+static bool shouldDumpAsText(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "/dumpAsText/") || strstr(pathOrURL, "\\dumpAsText\\");
+}
+
+static bool shouldEnableDeveloperExtras(const char* pathOrURL)
+{
+ return true;
+}
+
+static void resetDefaultsToConsistentValues(IWebPreferences* preferences)
+{
+#ifdef USE_MAC_FONTS
+ static BSTR standardFamily = SysAllocString(TEXT("Times"));
+ static BSTR fixedFamily = SysAllocString(TEXT("Courier"));
+ static BSTR sansSerifFamily = SysAllocString(TEXT("Helvetica"));
+ static BSTR cursiveFamily = SysAllocString(TEXT("Apple Chancery"));
+ static BSTR fantasyFamily = SysAllocString(TEXT("Papyrus"));
+ static BSTR pictographFamily = SysAllocString(TEXT("Apple Color Emoji"));
+#else
+ static BSTR standardFamily = SysAllocString(TEXT("Times New Roman"));
+ static BSTR fixedFamily = SysAllocString(TEXT("Courier New"));
+ static BSTR sansSerifFamily = SysAllocString(TEXT("Arial"));
+ static BSTR cursiveFamily = SysAllocString(TEXT("Comic Sans MS")); // Not actually cursive, but it's what IE and Firefox use.
+ static BSTR fantasyFamily = SysAllocString(TEXT("Times New Roman"));
+ static BSTR pictographFamily = SysAllocString(TEXT("Times New Roman"));
+#endif
+
+ preferences->setStandardFontFamily(standardFamily);
+ preferences->setFixedFontFamily(fixedFamily);
+ preferences->setSerifFontFamily(standardFamily);
+ preferences->setSansSerifFontFamily(sansSerifFamily);
+ preferences->setCursiveFontFamily(cursiveFamily);
+ preferences->setFantasyFontFamily(fantasyFamily);
+ preferences->setPictographFontFamily(pictographFamily);
+
+ preferences->setAutosaves(FALSE);
+ preferences->setDefaultFontSize(16);
+ preferences->setDefaultFixedFontSize(13);
+ preferences->setMinimumFontSize(0);
+ preferences->setJavaEnabled(FALSE);
+ preferences->setPlugInsEnabled(TRUE);
+ preferences->setDOMPasteAllowed(TRUE);
+ preferences->setEditableLinkBehavior(WebKitEditableLinkOnlyLiveWithShiftKey);
+ preferences->setFontSmoothing(FontSmoothingTypeStandard);
+ preferences->setUsesPageCache(FALSE);
+ preferences->setPrivateBrowsingEnabled(FALSE);
+ preferences->setJavaScriptCanOpenWindowsAutomatically(TRUE);
+ preferences->setJavaScriptEnabled(TRUE);
+ preferences->setTabsToLinks(FALSE);
+ preferences->setShouldPrintBackgrounds(TRUE);
+ preferences->setLoadsImagesAutomatically(TRUE);
+ preferences->setEditingBehavior(WebKitEditingWinBehavior);
+
+ if (persistentUserStyleSheetLocation) {
+ Vector<wchar_t> urlCharacters(CFStringGetLength(persistentUserStyleSheetLocation.get()));
+ CFStringGetCharacters(persistentUserStyleSheetLocation.get(), CFRangeMake(0, CFStringGetLength(persistentUserStyleSheetLocation.get())), (UniChar *)urlCharacters.data());
+ BSTR url = SysAllocStringLen(urlCharacters.data(), urlCharacters.size());
+ preferences->setUserStyleSheetLocation(url);
+ SysFreeString(url);
+ preferences->setUserStyleSheetEnabled(TRUE);
+ } else
+ preferences->setUserStyleSheetEnabled(FALSE);
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (prefsPrivate) {
+ prefsPrivate->setAllowUniversalAccessFromFileURLs(TRUE);
+ prefsPrivate->setAllowFileAccessFromFileURLs(TRUE);
+ prefsPrivate->setAuthorAndUserStylesEnabled(TRUE);
+ prefsPrivate->setDeveloperExtrasEnabled(FALSE);
+ prefsPrivate->setExperimentalNotificationsEnabled(TRUE);
+ prefsPrivate->setShouldPaintNativeControls(FALSE); // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592>
+ prefsPrivate->setJavaScriptCanAccessClipboard(TRUE);
+ prefsPrivate->setXSSAuditorEnabled(FALSE);
+ prefsPrivate->setFrameFlatteningEnabled(FALSE);
+ prefsPrivate->setOfflineWebApplicationCacheEnabled(TRUE);
+ prefsPrivate->setLoadsSiteIconsIgnoringImageLoadingPreference(FALSE);
+ prefsPrivate->setHixie76WebSocketProtocolEnabled(TRUE);
+ }
+ setAlwaysAcceptCookies(false);
+
+ setlocale(LC_ALL, "");
+}
+
+static void resetWebViewToConsistentStateBeforeTesting()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ webView->setPolicyDelegate(0);
+ policyDelegate->setPermissive(false);
+ policyDelegate->setControllerToNotifyDone(0);
+
+ COMPtr<IWebIBActions> webIBActions(Query, webView);
+ if (webIBActions) {
+ webIBActions->makeTextStandardSize(0);
+ webIBActions->resetPageZoom(0);
+ }
+
+
+ COMPtr<IWebPreferences> preferences;
+ if (SUCCEEDED(webView->preferences(&preferences)))
+ resetDefaultsToConsistentValues(preferences.get());
+
+ COMPtr<IWebViewEditing> viewEditing;
+ if (SUCCEEDED(webView->QueryInterface(&viewEditing)))
+ viewEditing->setSmartInsertDeleteEnabled(TRUE);
+
+ COMPtr<IWebViewPrivate> webViewPrivate(Query, webView);
+ if (!webViewPrivate)
+ return;
+
+ double minimumInterval = 0;
+ if (SUCCEEDED(webViewPrivate->defaultMinimumTimerInterval(&minimumInterval)))
+ webViewPrivate->setMinimumTimerInterval(minimumInterval);
+
+ COMPtr<IWebInspector> inspector;
+ if (SUCCEEDED(webViewPrivate->inspector(&inspector)))
+ inspector->setJavaScriptProfilingEnabled(FALSE);
+
+ HWND viewWindow;
+ if (SUCCEEDED(webViewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))) && viewWindow)
+ SetFocus(viewWindow);
+
+ webViewPrivate->clearMainFrameName();
+ webViewPrivate->resetOriginAccessWhitelists();
+
+ BSTR groupName;
+ if (SUCCEEDED(webView->groupName(&groupName))) {
+ webViewPrivate->removeAllUserContentFromGroup(groupName);
+ SysFreeString(groupName);
+ }
+
+ sharedUIDelegate->resetUndoManager();
+
+ sharedFrameLoadDelegate->resetToConsistentState();
+
+ COMPtr<IWebFramePrivate> framePrivate;
+ if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
+ framePrivate->clearOpener();
+}
+
+static void runTest(const string& testPathOrURL)
+{
+ static BSTR methodBStr = SysAllocString(TEXT("GET"));
+
+ // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows.
+ string pathOrURL(testPathOrURL);
+ string expectedPixelHash;
+
+ size_t separatorPos = pathOrURL.find("'");
+ if (separatorPos != string::npos) {
+ pathOrURL = string(testPathOrURL, 0, separatorPos);
+ expectedPixelHash = string(testPathOrURL, separatorPos + 1);
+ }
+
+ BSTR urlBStr;
+
+ CFStringRef str = CFStringCreateWithCString(0, pathOrURL.c_str(), kCFStringEncodingWindowsLatin1);
+ CFURLRef url = CFURLCreateWithString(0, str, 0);
+
+ if (!url)
+ url = CFURLCreateWithFileSystemPath(0, str, kCFURLWindowsPathStyle, false);
+
+ CFRelease(str);
+
+ str = CFURLGetString(url);
+
+ CFIndex length = CFStringGetLength(str);
+ UniChar* buffer = new UniChar[length];
+
+ CFStringGetCharacters(str, CFRangeMake(0, length), buffer);
+ urlBStr = SysAllocStringLen((OLECHAR*)buffer, length);
+ delete[] buffer;
+
+ CFRelease(url);
+
+ ::gLayoutTestController = LayoutTestController::create(pathOrURL, expectedPixelHash);
+ done = false;
+ topLoadingFrame = 0;
+
+ gLayoutTestController->setIconDatabaseEnabled(false);
+
+ if (shouldLogFrameLoadDelegates(pathOrURL.c_str()))
+ gLayoutTestController->setDumpFrameLoadCallbacks(true);
+
+ COMPtr<IWebView> webView;
+ if (SUCCEEDED(frame->webView(&webView))) {
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (SUCCEEDED(webView->QueryInterface(&viewPrivate))) {
+ if (shouldLogHistoryDelegates(pathOrURL.c_str())) {
+ gLayoutTestController->setDumpHistoryDelegateCallbacks(true);
+ viewPrivate->setHistoryDelegate(sharedHistoryDelegate.get());
+ } else
+ viewPrivate->setHistoryDelegate(0);
+ }
+ }
+ COMPtr<IWebHistory> history;
+ if (SUCCEEDED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
+ history->setOptionalSharedHistory(0);
+
+ resetWebViewToConsistentStateBeforeTesting();
+
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
+ gLayoutTestController->setDeveloperExtrasEnabled(true);
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->showWebInspector();
+ }
+ if (shouldDumpAsText(pathOrURL.c_str())) {
+ gLayoutTestController->setDumpAsText(true);
+ gLayoutTestController->setGeneratePixelResults(false);
+ }
+
+ prevTestBFItem = 0;
+ if (webView) {
+ COMPtr<IWebBackForwardList> bfList;
+ if (SUCCEEDED(webView->backForwardList(&bfList)))
+ bfList->currentItem(&prevTestBFItem);
+ }
+
+ WorkQueue::shared()->clear();
+ WorkQueue::shared()->setFrozen(false);
+
+ HWND hostWindow;
+ webView->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow));
+
+ COMPtr<IWebMutableURLRequest> request;
+ HRESULT hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request);
+ if (FAILED(hr))
+ goto exit;
+
+ request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 60);
+
+ request->setHTTPMethod(methodBStr);
+ frame->loadRequest(request.get());
+
+ MSG msg;
+ while (GetMessage(&msg, 0, 0, 0)) {
+ // We get spurious WM_MOUSELEAVE events which make event handling machinery think that mouse button
+ // is released during dragging (see e.g. fast\dynamic\layer-hit-test-crash.html).
+ // Mouse can never leave WebView during normal DumpRenderTree operation, so we just ignore all such events.
+ if (msg.message == WM_MOUSELEAVE)
+ continue;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
+ gLayoutTestController->closeWebInspector();
+ gLayoutTestController->setDeveloperExtrasEnabled(false);
+ }
+
+ resetWebViewToConsistentStateBeforeTesting();
+
+ frame->stopLoading();
+
+ if (::gLayoutTestController->closeRemainingWindowsWhenComplete()) {
+ Vector<HWND> windows = openWindows();
+ unsigned size = windows.size();
+ for (unsigned i = 0; i < size; i++) {
+ HWND window = windows[i];
+
+ // Don't try to close the main window
+ if (window == hostWindow)
+ continue;
+
+ DestroyWindow(window);
+ }
+ }
+
+exit:
+ SysFreeString(urlBStr);
+ ::gLayoutTestController.clear();
+
+ return;
+}
+
+static Boolean pthreadEqualCallback(const void* value1, const void* value2)
+{
+ return (Boolean)pthread_equal(*(pthread_t*)value1, *(pthread_t*)value2);
+}
+
+static CFDictionaryKeyCallBacks pthreadKeyCallbacks = { 0, 0, 0, 0, pthreadEqualCallback, 0 };
+
+static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool javaScriptThreadsShouldTerminate;
+
+static const int javaScriptThreadsCount = 4;
+static CFMutableDictionaryRef javaScriptThreads()
+{
+ assert(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY);
+ static CFMutableDictionaryRef staticJavaScriptThreads;
+ if (!staticJavaScriptThreads)
+ staticJavaScriptThreads = CFDictionaryCreateMutable(0, 0, &pthreadKeyCallbacks, 0);
+ return staticJavaScriptThreads;
+}
+
+// Loops forever, running a script and randomly respawning, until
+// javaScriptThreadsShouldTerminate becomes true.
+void* runJavaScriptThread(void* arg)
+{
+ const char* const script =
+ " \
+ var array = []; \
+ for (var i = 0; i < 10; i++) { \
+ array.push(String(i)); \
+ } \
+ ";
+
+ while (true) {
+ JSGlobalContextRef ctx = JSGlobalContextCreate(0);
+ JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
+
+ JSValueRef exception = 0;
+ JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
+ assert(!exception);
+
+ JSGlobalContextRelease(ctx);
+ JSStringRelease(scriptRef);
+
+ JSGarbageCollect(ctx);
+
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+
+ // Check for cancellation.
+ if (javaScriptThreadsShouldTerminate) {
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ return 0;
+ }
+
+ // Respawn probabilistically.
+ if (rand() % 5 == 0) {
+ pthread_t pthread;
+ pthread_create(&pthread, 0, &runJavaScriptThread, 0);
+ pthread_detach(pthread);
+
+ pthread_t self = pthread_self();
+ CFDictionaryRemoveValue(javaScriptThreads(), self.p);
+ CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
+
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ return 0;
+ }
+
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ }
+}
+
+static void startJavaScriptThreads(void)
+{
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+
+ for (int i = 0; i < javaScriptThreadsCount; i++) {
+ pthread_t pthread;
+ pthread_create(&pthread, 0, &runJavaScriptThread, 0);
+ pthread_detach(pthread);
+ CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
+ }
+
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+}
+
+static void stopJavaScriptThreads(void)
+{
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+
+ javaScriptThreadsShouldTerminate = true;
+
+ pthread_t* pthreads[javaScriptThreadsCount] = {0};
+ int threadDictCount = CFDictionaryGetCount(javaScriptThreads());
+ assert(threadDictCount == javaScriptThreadsCount);
+ CFDictionaryGetKeysAndValues(javaScriptThreads(), (const void**)pthreads, 0);
+
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+
+ for (int i = 0; i < javaScriptThreadsCount; i++) {
+ pthread_t* pthread = pthreads[i];
+ pthread_join(*pthread, 0);
+ free(pthread);
+ }
+}
+
+Vector<HWND>& openWindows()
+{
+ static Vector<HWND> vector;
+ return vector;
+}
+
+WindowToWebViewMap& windowToWebViewMap()
+{
+ static WindowToWebViewMap map;
+ return map;
+}
+
+IWebView* createWebViewAndOffscreenWindow(HWND* webViewWindow)
+{
+ unsigned maxViewWidth = LayoutTestController::maxViewWidth;
+ unsigned maxViewHeight = LayoutTestController::maxViewHeight;
+ HWND hostWindow = CreateWindowEx(WS_EX_TOOLWINDOW, kDumpRenderTreeClassName, TEXT("DumpRenderTree"), WS_POPUP,
+ -maxViewWidth, -maxViewHeight, maxViewWidth, maxViewHeight, 0, 0, GetModuleHandle(0), 0);
+
+ IWebView* webView;
+
+ HRESULT hr = WebKitCreateInstance(CLSID_WebView, 0, IID_IWebView, (void**)&webView);
+ if (FAILED(hr)) {
+ fprintf(stderr, "Failed to create CLSID_WebView instance, error 0x%x\n", hr);
+ return 0;
+ }
+
+ if (FAILED(webView->setHostWindow((OLE_HANDLE)(ULONG64)hostWindow)))
+ return 0;
+
+ RECT clientRect;
+ clientRect.bottom = clientRect.left = clientRect.top = clientRect.right = 0;
+ BSTR groupName = SysAllocString(L"org.webkit.DumpRenderTree");
+ bool failed = FAILED(webView->initWithFrame(clientRect, 0, groupName));
+ SysFreeString(groupName);
+ if (failed)
+ return 0;
+
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (FAILED(webView->QueryInterface(&viewPrivate)))
+ return 0;
+
+ viewPrivate->setShouldApplyMacFontAscentHack(TRUE);
+ viewPrivate->setAlwaysUsesComplexTextCodePath(forceComplexText);
+
+ BSTR pluginPath = SysAllocStringLen(0, exePath().length() + _tcslen(TestPluginDir));
+ _tcscpy(pluginPath, exePath().c_str());
+ _tcscat(pluginPath, TestPluginDir);
+ failed = FAILED(viewPrivate->addAdditionalPluginDirectory(pluginPath));
+ SysFreeString(pluginPath);
+ if (failed)
+ return 0;
+
+ HWND viewWindow;
+ if (FAILED(viewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))))
+ return 0;
+ if (webViewWindow)
+ *webViewWindow = viewWindow;
+
+ SetWindowPos(viewWindow, 0, 0, 0, maxViewWidth, maxViewHeight, 0);
+ ShowWindow(hostWindow, SW_SHOW);
+
+ if (FAILED(webView->setFrameLoadDelegate(sharedFrameLoadDelegate.get())))
+ return 0;
+
+ if (FAILED(viewPrivate->setFrameLoadDelegatePrivate(sharedFrameLoadDelegate.get())))
+ return 0;
+
+ if (FAILED(webView->setUIDelegate(sharedUIDelegate.get())))
+ return 0;
+
+ COMPtr<IWebViewEditing> viewEditing;
+ if (FAILED(webView->QueryInterface(&viewEditing)))
+ return 0;
+
+ if (FAILED(viewEditing->setEditingDelegate(sharedEditingDelegate.get())))
+ return 0;
+
+ ResourceLoadDelegate* resourceLoadDelegate = new ResourceLoadDelegate();
+ HRESULT result = webView->setResourceLoadDelegate(resourceLoadDelegate);
+ resourceLoadDelegate->Release(); // The delegate is owned by the WebView, so release our reference to it.
+ if (FAILED(result))
+ return 0;
+
+ openWindows().append(hostWindow);
+ windowToWebViewMap().set(hostWindow, webView);
+ return webView;
+}
+
+#if USE(CFNETWORK)
+RetainPtr<CFURLCacheRef> sharedCFURLCache()
+{
+#ifndef DEBUG_ALL
+ HMODULE module = GetModuleHandle(TEXT("CFNetwork.dll"));
+#else
+ HMODULE module = GetModuleHandle(TEXT("CFNetwork_debug.dll"));
+#endif
+ if (!module)
+ return 0;
+
+ typedef CFURLCacheRef (*CFURLCacheCopySharedURLCacheProcPtr)(void);
+ if (CFURLCacheCopySharedURLCacheProcPtr copyCache = reinterpret_cast<CFURLCacheCopySharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheCopySharedURLCache")))
+ return RetainPtr<CFURLCacheRef>(AdoptCF, copyCache());
+
+ typedef CFURLCacheRef (*CFURLCacheSharedURLCacheProcPtr)(void);
+ if (CFURLCacheSharedURLCacheProcPtr sharedCache = reinterpret_cast<CFURLCacheSharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheSharedURLCache")))
+ return sharedCache();
+
+ return 0;
+}
+#endif
+
+static LONG WINAPI exceptionFilter(EXCEPTION_POINTERS*)
+{
+ fputs("#CRASHED\n", stderr);
+ fflush(stderr);
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
+{
+ // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
+ // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
+ // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
+ ::SetErrorMode(0);
+
+ ::SetUnhandledExceptionFilter(exceptionFilter);
+
+ leakChecking = false;
+
+ _setmode(1, _O_BINARY);
+ _setmode(2, _O_BINARY);
+
+ initialize();
+
+ Vector<const char*> tests;
+
+ for (int i = 1; i < argc; ++i) {
+ if (!stricmp(argv[i], "--threaded")) {
+ threaded = true;
+ continue;
+ }
+
+ if (!stricmp(argv[i], "--dump-all-pixels")) {
+ dumpAllPixels = true;
+ continue;
+ }
+
+ if (!stricmp(argv[i], "--pixel-tests")) {
+ dumpPixels = true;
+ continue;
+ }
+
+ if (!stricmp(argv[i], "--complex-text")) {
+ forceComplexText = true;
+ continue;
+ }
+
+ if (!stricmp(argv[i], "--print-supported-features")) {
+ printSupportedFeatures = true;
+ continue;
+ }
+
+ tests.append(argv[i]);
+ }
+
+ policyDelegate = new PolicyDelegate();
+ sharedFrameLoadDelegate.adoptRef(new FrameLoadDelegate);
+ sharedUIDelegate.adoptRef(new UIDelegate);
+ sharedEditingDelegate.adoptRef(new EditingDelegate);
+ sharedHistoryDelegate.adoptRef(new HistoryDelegate);
+
+ // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592>
+ COMPtr<IWebPreferences> tmpPreferences;
+ if (FAILED(WebKitCreateInstance(CLSID_WebPreferences, 0, IID_IWebPreferences, reinterpret_cast<void**>(&tmpPreferences))))
+ return -1;
+ COMPtr<IWebPreferences> standardPreferences;
+ if (FAILED(tmpPreferences->standardPreferences(&standardPreferences)))
+ return -1;
+ COMPtr<IWebPreferencesPrivate> standardPreferencesPrivate;
+ if (FAILED(standardPreferences->QueryInterface(&standardPreferencesPrivate)))
+ return -1;
+ standardPreferencesPrivate->setShouldPaintNativeControls(FALSE);
+ standardPreferences->setJavaScriptEnabled(TRUE);
+ standardPreferences->setDefaultFontSize(16);
+ standardPreferences->setAcceleratedCompositingEnabled(true);
+ standardPreferences->setContinuousSpellCheckingEnabled(TRUE);
+
+ if (printSupportedFeatures) {
+ BOOL acceleratedCompositingAvailable;
+ standardPreferences->acceleratedCompositingEnabled(&acceleratedCompositingAvailable);
+
+#if ENABLE(3D_RENDERING)
+ // In theory, we could have a software-based 3D rendering implementation that we use when
+ // hardware-acceleration is not available. But we don't have any such software
+ // implementation, so 3D rendering is only available when hardware-acceleration is.
+ BOOL threeDRenderingAvailable = acceleratedCompositingAvailable;
+#else
+ BOOL threeDRenderingAvailable = FALSE;
+#endif
+
+ printf("SupportedFeatures:%s %s\n", acceleratedCompositingAvailable ? "AcceleratedCompositing" : "", threeDRenderingAvailable ? "3DRendering" : "");
+ return 0;
+ }
+
+ COMPtr<IWebView> webView(AdoptCOM, createWebViewAndOffscreenWindow(&webViewWindow));
+ if (!webView)
+ return -1;
+
+ COMPtr<IWebIconDatabase> iconDatabase;
+ COMPtr<IWebIconDatabase> tmpIconDatabase;
+ if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
+ return -1;
+ if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
+ return -1;
+
+ if (FAILED(webView->mainFrame(&frame)))
+ return -1;
+
+#if USE(CFNETWORK)
+ RetainPtr<CFURLCacheRef> urlCache = sharedCFURLCache();
+ CFURLCacheRemoveAllCachedResponses(urlCache.get());
+#endif
+
+#ifdef _DEBUG
+ _CrtMemState entryToMainMemCheckpoint;
+ if (leakChecking)
+ _CrtMemCheckpoint(&entryToMainMemCheckpoint);
+#endif
+
+ if (threaded)
+ startJavaScriptThreads();
+
+ if (tests.size() == 1 && !strcmp(tests[0], "-")) {
+ char filenameBuffer[2048];
+ printSeparators = true;
+ while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
+ char* newLineCharacter = strchr(filenameBuffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (strlen(filenameBuffer) == 0)
+ continue;
+
+ runTest(filenameBuffer);
+ }
+ } else {
+ printSeparators = tests.size() > 1;
+ for (int i = 0; i < tests.size(); i++)
+ runTest(tests[i]);
+ }
+
+ if (threaded)
+ stopJavaScriptThreads();
+
+ delete policyDelegate;
+ frame->Release();
+
+#ifdef _DEBUG
+ if (leakChecking) {
+ // dump leaks to stderr
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtMemDumpAllObjectsSince(&entryToMainMemCheckpoint);
+ }
+#endif
+
+ shutDownWebKit();
+
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/win/DumpRenderTree.vcproj b/Tools/DumpRenderTree/win/DumpRenderTree.vcproj
new file mode 100644
index 000000000..d22ddfa7d
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTree.vcproj
@@ -0,0 +1,728 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTree"
+ ProjectGUID="{6567DFD4-D6DE-4CD5-825D-17E353D160E1}"
+ RootNamespace="DumpRenderTree"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\DumpRenderTreeDebug.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\DumpRenderTreeRelease.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_Cairo_CFLite|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\DumpRenderTreeDebugCairoCFLite.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_Cairo_CFLite|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\DumpRenderTreeReleaseCairoCFLite.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\DumpRenderTreeDebugAll.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Production|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\DumpRenderTreeProduction.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Controllers"
+ >
+ <File
+ RelativePath="..\AccessibilityController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\AccessibilityController.h"
+ >
+ </File>
+ <File
+ RelativePath=".\AccessibilityControllerWin.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\EventSender.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\EventSender.h"
+ >
+ </File>
+ <File
+ RelativePath="..\GCController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\GCController.h"
+ >
+ </File>
+ <File
+ RelativePath=".\GCControllerWin.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\LayoutTestController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\LayoutTestController.h"
+ >
+ </File>
+ <File
+ RelativePath=".\LayoutTestControllerWin.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Delegates"
+ >
+ <File
+ RelativePath=".\DRTDesktopNotificationPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\DRTDesktopNotificationPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\EditingDelegate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\EditingDelegate.h"
+ >
+ </File>
+ <File
+ RelativePath=".\FrameLoadDelegate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\FrameLoadDelegate.h"
+ >
+ </File>
+ <File
+ RelativePath=".\HistoryDelegate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\HistoryDelegate.h"
+ >
+ </File>
+ <File
+ RelativePath=".\PolicyDelegate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\PolicyDelegate.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ResourceLoadDelegate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ResourceLoadDelegate.h"
+ >
+ </File>
+ <File
+ RelativePath=".\UIDelegate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\UIDelegate.h"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath="..\AccessibilityTextMarker.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\AccessibilityTextMarker.h"
+ >
+ </File>
+ <File
+ RelativePath="..\AccessibilityUIElement.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\AccessibilityUIElement.h"
+ >
+ </File>
+ <File
+ RelativePath=".\AccessibilityUIElementWin.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\CyclicRedundancyCheck.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\CyclicRedundancyCheck.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DraggingInfo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DumpRenderTree.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\DumpRenderTree.h"
+ >
+ </File>
+ <File
+ RelativePath="..\DumpRenderTreePrefix.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DumpRenderTreeWin.h"
+ >
+ </File>
+ <File
+ RelativePath=".\MD5.cpp"
+ >
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\MD5.h"
+ >
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\PixelDumpSupport.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\PixelDumpSupport.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cairo\PixelDumpSupportCairo.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Production|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cairo\PixelDumpSupportCairo.h"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Production|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cg\PixelDumpSupportCG.cpp"
+ >
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cg\PixelDumpSupportCG.h"
+ >
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\PixelDumpSupportWin.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\WorkQueue.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\WorkQueue.h"
+ >
+ </File>
+ <File
+ RelativePath="..\WorkQueueItem.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WorkQueueItemWin.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeApple.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeApple.vsprops
new file mode 100644
index 000000000..f126689e1
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeApple.vsprops
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeApple"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\cg&quot;;"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="CoreGraphics$(LibraryConfigSuffix).lib CoreFoundation$(LibraryConfigSuffix).lib CFNetwork$(LibraryConfigSuffix).lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeCFLite.vsprops
new file mode 100644
index 000000000..209b3ea06
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeCFLite.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeCFLite"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="CFLite$(LibraryConfigSuffix).lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeCairo.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeCairo.vsprops
new file mode 100644
index 000000000..6d44dec4a
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeCairo.vsprops
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeCairo"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\cairo&quot;;"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="cairo.lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops
new file mode 100644
index 000000000..ac5003cba
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)\.&quot;;&quot;$(ProjectDir)\..&quot;;&quot;$(ConfigurationBuildDir)\Include&quot;;&quot;$(ConfigurationBuildDir)\Include\private&quot;;&quot;$(ConfigurationBuildDir)\Include\DumpRenderTree\ForwardingHeaders&quot;;&quot;$(ConfigurationBuildDir)\Include\JavaScriptCore&quot;;&quot;$(ConfigurationBuildDir)\Include\private\JavaScriptCore&quot;;&quot;$(ConfigurationBuildDir)\Include\WebCoreTestSupport&quot;;&quot;$(WebKitLibrariesDir)\Include&quot;;&quot;$(WebKitLibrariesDir)\Include\private&quot;;&quot;$(WebKitLibrariesDir)\include\pthreads&quot;;&quot;$(ConfigurationBuildDir)\Include\WebCore&quot;;&quot;$(WebKitLibrariesDir)\Include\WebCore&quot;"
+ PreprocessorDefinitions="_CONSOLE"
+ DisableSpecificWarnings="4146"
+ ForcedIncludeFiles="DumpRenderTreePrefix.h"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/NXCOMPAT"
+ AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib WebKitGUID$(WebKitConfigSuffix).lib WebKit$(WebKitDLLConfigSuffix).lib WebCoreTestSupport$(WebKitConfigSuffix).lib pthreadVC2$(LibraryConfigSuffix).lib gdi32.lib ole32.lib oleaut32.lib user32.lib shlwapi.lib oleacc.lib comsuppw.lib"
+ OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix).dll"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeDebug.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeDebug.vsprops
new file mode 100644
index 000000000..11db1cd97
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeDebug.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeDebug"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeDebugAll.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeDebugAll.vsprops
new file mode 100644
index 000000000..38327ed12
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeDebugAll.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeDebugAll"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeDebugCairoCFLite.vsprops
new file mode 100644
index 000000000..ea3a15c49
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeDebugCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeDebugCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefinesCairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\cURL.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeCairo.vsprops;.\DumpRenderTreeCFLite.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncher.vcproj b/Tools/DumpRenderTree/win/DumpRenderTreeLauncher.vcproj
new file mode 100644
index 000000000..72050b14b
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncher.vcproj
@@ -0,0 +1,396 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeLauncher"
+ ProjectGUID="{2974EA02-840B-4995-8719-8920A61006F1}"
+ RootNamespace="DumpRenderTreeLauncher"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\DumpRenderTreeLauncherDebug.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\DumpRenderTreeLauncherRelease.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_Cairo_CFLite|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\DumpRenderTreeLauncherDebugCairoCFLite.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\DumpRenderTreeLauncherDebugAll.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Production|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\DumpRenderTreeLauncherProduction.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_Cairo_CFLite|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\DumpRenderTreeLauncherReleaseCairoCFLite.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\win\DLLLauncher\DLLLauncherMain.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherCommon.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherCommon.vsprops
new file mode 100644
index 000000000..033665aec
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherCommon.vsprops
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeLauncherCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="USE_CONSOLE_ENTRY_POINT"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="shlwapi.lib"
+ OutputFile="$(OutDir)\DumpRenderTree$(WebKitConfigSuffix).exe"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName)Launcher.pdb"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebug.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebug.vsprops
new file mode 100644
index 000000000..3ec09ffbe
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebug.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeLauncherDebug"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\DumpRenderTreeLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugAll.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugAll.vsprops
new file mode 100644
index 000000000..d1c2cb5d4
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugAll.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeLauncherDebugAll"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\DumpRenderTreeLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugCairoCFLite.vsprops
new file mode 100644
index 000000000..e70732efd
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherDebugCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeDebugCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherProduction.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherProduction.vsprops
new file mode 100644
index 000000000..bf3360136
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherProduction.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeLauncherProduction"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\DumpRenderTreeLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherRelease.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherRelease.vsprops
new file mode 100644
index 000000000..535e18fb3
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherRelease.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeLauncherRelease"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\DumpRenderTreeLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeLauncherReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherReleaseCairoCFLite.vsprops
new file mode 100644
index 000000000..cf2a0db5b
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeLauncherReleaseCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeLauncherReleaseCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\DumpRenderTreeLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd b/Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd
new file mode 100644
index 000000000..464502c21
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd
@@ -0,0 +1,62 @@
+if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed"
+
+if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)
+
+mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\bin"
+
+if not exist "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.dll" GOTO:CFLITE
+
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreVideo%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreVideo%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CFNetwork.resources" "%CONFIGURATIONBUILDDIR%\bin\CFNetwork.resources"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CoreFoundation.resources" "%CONFIGURATIONBUILDDIR%\bin\CoreFoundation.resources"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt40.dll" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt42.dll" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt42.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt42%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxml2%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxslt%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+exit /b
+
+:CFLITE
+if not exist "%WEBKITLIBRARIESDIR%\bin\CFLite%LIBRARYCONFIGSUFFIX%.dll" exit /b
+
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFLite%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFLite%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CFLite.resources" "%CONFIGURATIONBUILDDIR%\bin\CFLite.resources"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libcurl.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libeay32.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\ssleay32.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\cairo.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt46.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libicuuc.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libicuin.dll" "%CONFIGURATIONBUILDDIR%\bin"
+
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxml2%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxslt%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.pdb" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.pdb" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.dll" "%CONFIGURATIONBUILDDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.pdb" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.pdb" "%CONFIGURATIONBUILDDIR%\bin"
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd b/Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd
new file mode 100644
index 000000000..c2f85c790
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd
@@ -0,0 +1,20 @@
+%SystemDrive%\cygwin\bin\which.exe bash
+if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
+cmd /c
+if exist "%CONFIGURATIONBUILDDIR%\buildfailed" grep XX%PROJECTNAME%XX "%CONFIGURATIONBUILDDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed"
+
+mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree"
+mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders"
+mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\runtime"
+mkdir 2>NUL "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\wtf"
+
+xcopy /y /d "%PROJECTDIR%\..\ForwardingHeaders\wtf\*.h" "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\wtf"
+xcopy /y /d "%PROJECTDIR%\..\ForwardingHeaders\runtime\*.h" "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\runtime"
+
+if "%CONFIGURATIONNAME%"=="Debug_Cairo_CFLite" xcopy /y /d "%CONFIGURATIONBUILDDIR%\include\WebCore\ForwardingHeaders\wtf\MD5.h" "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\wtf"
+if "%CONFIGURATIONNAME%"=="Release_Cairo_CFLite" xcopy /y /d "%CONFIGURATIONBUILDDIR%\include\WebCore\ForwardingHeaders\wtf\MD5.h" "%CONFIGURATIONBUILDDIR%\include\DumpRenderTree\ForwardingHeaders\wtf"
+
+if "%CONFIGURATIONNAME%"=="Debug_Cairo" xcopy /y /d "%TARGETDIR%\..\include\WebCore\ForwardingHeaders\wtf\MD5.h"
+if "%CONFIGURATIONNAME%"=="Release_Cairo" xcopy /y /d "%TARGETDIR%\..\include\WebCore\ForwardingHeaders\wtf\MD5.h"
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops
new file mode 100644
index 000000000..ee29e00e2
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeProduction"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops
new file mode 100644
index 000000000..3e8e857d8
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeRelease"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops
new file mode 100644
index 000000000..aef8e0d9a
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeReleaseCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefinesCairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\cURL.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeCairo.vsprops;.\DumpRenderTreeCFLite.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeWin.h b/Tools/DumpRenderTree/win/DumpRenderTreeWin.h
new file mode 100644
index 000000000..c64c3bf50
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeWin.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeWin_h
+#define DumpRenderTreeWin_h
+
+struct IWebFrame;
+struct IWebScriptWorld;
+struct IWebView;
+struct FrameLoadDelegate;
+struct PolicyDelegate;
+typedef const struct __CFString* CFStringRef;
+typedef struct HWND__* HWND;
+
+extern IWebFrame* topLoadingFrame;
+extern IWebFrame* frame;
+extern PolicyDelegate* policyDelegate;
+
+extern HWND webViewWindow;
+
+#include <WebCore/COMPtr.h>
+#include <string>
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+std::wstring urlSuitableForTestResult(const std::wstring& url);
+std::wstring lastPathComponent(const std::wstring&);
+std::string toUTF8(BSTR);
+std::string toUTF8(const std::wstring&);
+std::wstring cfStringRefToWString(CFStringRef);
+
+IWebView* createWebViewAndOffscreenWindow(HWND* webViewWindow = 0);
+Vector<HWND>& openWindows();
+typedef HashMap<HWND, COMPtr<IWebView> > WindowToWebViewMap;
+WindowToWebViewMap& windowToWebViewMap();
+
+void setPersistentUserStyleSheetLocation(CFStringRef);
+bool setAlwaysAcceptCookies(bool alwaysAcceptCookies);
+
+unsigned worldIDForWorld(IWebScriptWorld*);
+
+extern UINT_PTR waitToDumpWatchdog;
+
+extern COMPtr<FrameLoadDelegate> sharedFrameLoadDelegate;
+
+#endif // DumpRenderTreeWin_h
diff --git a/Tools/DumpRenderTree/win/EditingDelegate.cpp b/Tools/DumpRenderTree/win/EditingDelegate.cpp
new file mode 100644
index 000000000..3552ecd17
--- /dev/null
+++ b/Tools/DumpRenderTree/win/EditingDelegate.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "EditingDelegate.h"
+
+#include "DumpRenderTree.h"
+#include "LayoutTestController.h"
+#include <WebCore/COMPtr.h>
+#include <wtf/Platform.h>
+#include <JavaScriptCore/Assertions.h>
+#include <string>
+#include <tchar.h>
+
+using std::wstring;
+
+EditingDelegate::EditingDelegate()
+ : m_refCount(1)
+ , m_acceptsEditing(true)
+{
+}
+
+// IUnknown
+HRESULT STDMETHODCALLTYPE EditingDelegate::QueryInterface(REFIID riid, void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IsEqualGUID(riid, IID_IUnknown))
+ *ppvObject = static_cast<IWebEditingDelegate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebEditingDelegate))
+ *ppvObject = static_cast<IWebEditingDelegate*>(this);
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE EditingDelegate::AddRef(void)
+{
+ return ++m_refCount;
+}
+
+ULONG STDMETHODCALLTYPE EditingDelegate::Release(void)
+{
+ ULONG newRef = --m_refCount;
+ if (!newRef)
+ delete this;
+
+ return newRef;
+}
+
+static wstring dumpPath(IDOMNode* node)
+{
+ ASSERT(node);
+
+ wstring result;
+
+ BSTR name;
+ if (FAILED(node->nodeName(&name)))
+ return result;
+ result.assign(name, SysStringLen(name));
+ SysFreeString(name);
+
+ COMPtr<IDOMNode> parent;
+ if (SUCCEEDED(node->parentNode(&parent)))
+ result += TEXT(" > ") + dumpPath(parent.get());
+
+ return result;
+}
+
+static wstring dump(IDOMRange* range)
+{
+ ASSERT(range);
+
+ int startOffset;
+ if (FAILED(range->startOffset(&startOffset)))
+ return 0;
+
+ int endOffset;
+ if (FAILED(range->endOffset(&endOffset)))
+ return 0;
+
+ COMPtr<IDOMNode> startContainer;
+ if (FAILED(range->startContainer(&startContainer)))
+ return 0;
+
+ COMPtr<IDOMNode> endContainer;
+ if (FAILED(range->endContainer(&endContainer)))
+ return 0;
+
+ wchar_t buffer[1024];
+ _snwprintf(buffer, ARRAYSIZE(buffer), L"range from %ld of %s to %ld of %s", startOffset, dumpPath(startContainer.get()), endOffset, dumpPath(endContainer.get()));
+ return buffer;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::shouldBeginEditingInDOMRange(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IDOMRange* range,
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result) {
+ ASSERT_NOT_REACHED();
+ return E_POINTER;
+ }
+
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done)
+ _tprintf(TEXT("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n"), dump(range));
+
+ *result = m_acceptsEditing;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::shouldEndEditingInDOMRange(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IDOMRange* range,
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result) {
+ ASSERT_NOT_REACHED();
+ return E_POINTER;
+ }
+
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done)
+ _tprintf(TEXT("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n"), dump(range));
+
+ *result = m_acceptsEditing;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::shouldInsertNode(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IDOMNode* node,
+ /* [in] */ IDOMRange* range,
+ /* [in] */ WebViewInsertAction action)
+{
+ static LPCTSTR insertactionstring[] = {
+ TEXT("WebViewInsertActionTyped"),
+ TEXT("WebViewInsertActionPasted"),
+ TEXT("WebViewInsertActionDropped"),
+ };
+
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done)
+ _tprintf(TEXT("EDITING DELEGATE: shouldInsertNode:%s replacingDOMRange:%s givenAction:%s\n"), dumpPath(node), dump(range), insertactionstring[action]);
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::shouldInsertText(
+ /* [in] */ IWebView* webView,
+ /* [in] */ BSTR text,
+ /* [in] */ IDOMRange* range,
+ /* [in] */ WebViewInsertAction action,
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result) {
+ ASSERT_NOT_REACHED();
+ return E_POINTER;
+ }
+
+ static LPCTSTR insertactionstring[] = {
+ TEXT("WebViewInsertActionTyped"),
+ TEXT("WebViewInsertActionPasted"),
+ TEXT("WebViewInsertActionDropped"),
+ };
+
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done)
+ _tprintf(TEXT("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:%s givenAction:%s\n"), text ? text : TEXT(""), dump(range), insertactionstring[action]);
+
+ *result = m_acceptsEditing;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::shouldDeleteDOMRange(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IDOMRange* range,
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result) {
+ ASSERT_NOT_REACHED();
+ return E_POINTER;
+ }
+
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done)
+ _tprintf(TEXT("EDITING DELEGATE: shouldDeleteDOMRange:%s\n"), dump(range));
+
+ *result = m_acceptsEditing;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::shouldChangeSelectedDOMRange(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IDOMRange* currentRange,
+ /* [in] */ IDOMRange* proposedRange,
+ /* [in] */ WebSelectionAffinity selectionAffinity,
+ /* [in] */ BOOL stillSelecting,
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result) {
+ ASSERT_NOT_REACHED();
+ return E_POINTER;
+ }
+
+ static LPCTSTR affinitystring[] = {
+ TEXT("NSSelectionAffinityUpstream"),
+ TEXT("NSSelectionAffinityDownstream")
+ };
+ static LPCTSTR boolstring[] = {
+ TEXT("FALSE"),
+ TEXT("TRUE")
+ };
+
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done)
+ _tprintf(TEXT("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s toDOMRange:%s affinity:%s stillSelecting:%s\n"), dump(currentRange), dump(proposedRange), affinitystring[selectionAffinity], boolstring[stillSelecting]);
+
+ *result = m_acceptsEditing;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::shouldApplyStyle(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IDOMCSSStyleDeclaration* style,
+ /* [in] */ IDOMRange* range,
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result) {
+ ASSERT_NOT_REACHED();
+ return E_POINTER;
+ }
+
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done)
+ _tprintf(TEXT("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n"), TEXT("'style description'")/*[[style description] UTF8String]*/, dump(range));
+
+ *result = m_acceptsEditing;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::shouldChangeTypingStyle(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IDOMCSSStyleDeclaration* currentStyle,
+ /* [in] */ IDOMCSSStyleDeclaration* proposedStyle,
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result) {
+ ASSERT_NOT_REACHED();
+ return E_POINTER;
+ }
+
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done)
+ _tprintf(TEXT("EDITING DELEGATE: shouldChangeTypingStyle:%s toStyle:%s\n"), TEXT("'currentStyle description'"), TEXT("'proposedStyle description'"));
+
+ *result = m_acceptsEditing;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::doPlatformCommand(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR command,
+ /* [retval][out] */ BOOL *result)
+{
+ if (!result) {
+ ASSERT_NOT_REACHED();
+ return E_POINTER;
+ }
+
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done)
+ _tprintf(TEXT("EDITING DELEGATE: doPlatformCommand:%s\n"), command ? command : TEXT(""));
+
+ *result = m_acceptsEditing;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidBeginEditing(
+ /* [in] */ IWebNotification* notification)
+{
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
+ BSTR name;
+ notification->name(&name);
+ _tprintf(TEXT("EDITING DELEGATE: webViewDidBeginEditing:%s\n"), name ? name : TEXT(""));
+ SysFreeString(name);
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidChange(
+ /* [in] */ IWebNotification *notification)
+{
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
+ BSTR name;
+ notification->name(&name);
+ _tprintf(TEXT("EDITING DELEGATE: webViewDidBeginEditing:%s\n"), name ? name : TEXT(""));
+ SysFreeString(name);
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidEndEditing(
+ /* [in] */ IWebNotification *notification)
+{
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
+ BSTR name;
+ notification->name(&name);
+ _tprintf(TEXT("EDITING DELEGATE: webViewDidEndEditing:%s\n"), name ? name : TEXT(""));
+ SysFreeString(name);
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidChangeTypingStyle(
+ /* [in] */ IWebNotification *notification)
+{
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
+ BSTR name;
+ notification->name(&name);
+ _tprintf(TEXT("EDITING DELEGATE: webViewDidChangeTypingStyle:%s\n"), name ? name : TEXT(""));
+ SysFreeString(name);
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidChangeSelection(
+ /* [in] */ IWebNotification *notification)
+{
+ if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
+ BSTR name;
+ notification->name(&name);
+ _tprintf(TEXT("EDITING DELEGATE: webViewDidChangeSelection:%s\n"), name ? name : TEXT(""));
+ SysFreeString(name);
+ }
+ return S_OK;
+}
+
+static int indexOfFirstWordCharacter(const TCHAR* text)
+{
+ const TCHAR* cursor = text;
+ while (*cursor && !iswalpha(*cursor))
+ ++cursor;
+ return *cursor ? (cursor - text) : -1;
+};
+
+static int wordLength(const TCHAR* text)
+{
+ const TCHAR* cursor = text;
+ while (*cursor && iswalpha(*cursor))
+ ++cursor;
+ return cursor - text;
+};
+
+HRESULT STDMETHODCALLTYPE EditingDelegate::checkSpellingOfString(
+ /* [in] */ IWebView* view,
+ /* [in] */ LPCTSTR text,
+ /* [in] */ int length,
+ /* [out] */ int* misspellingLocation,
+ /* [out] */ int* misspellingLength)
+{
+ static const TCHAR* misspelledWords[] = {
+ // These words are known misspelled words in webkit tests.
+ // If there are other misspelled words in webkit tests, please add them in
+ // this array.
+ TEXT("foo"),
+ TEXT("Foo"),
+ TEXT("baz"),
+ TEXT("fo"),
+ TEXT("LibertyF"),
+ TEXT("chello"),
+ TEXT("xxxtestxxx"),
+ TEXT("XXxxx"),
+ TEXT("Textx"),
+ TEXT("blockquoted"),
+ TEXT("asd"),
+ TEXT("Lorem"),
+ TEXT("Nunc"),
+ TEXT("Curabitur"),
+ TEXT("eu"),
+ TEXT("adlj"),
+ TEXT("adaasj"),
+ TEXT("sdklj"),
+ TEXT("jlkds"),
+ TEXT("jsaada"),
+ TEXT("jlda"),
+ TEXT("zz"),
+ TEXT("contentEditable"),
+ 0,
+ };
+
+ wstring textString(text, length);
+ int wordStart = indexOfFirstWordCharacter(textString.c_str());
+ if (-1 == wordStart)
+ return S_OK;
+ wstring word = textString.substr(wordStart, wordLength(textString.c_str() + wordStart));
+ for (size_t i = 0; misspelledWords[i]; ++i) {
+ if (word == misspelledWords[i]) {
+ *misspellingLocation = wordStart;
+ *misspellingLength = word.size();
+ break;
+ }
+ }
+
+ return S_OK;
+}
diff --git a/Tools/DumpRenderTree/win/EditingDelegate.h b/Tools/DumpRenderTree/win/EditingDelegate.h
new file mode 100644
index 000000000..7b7f418aa
--- /dev/null
+++ b/Tools/DumpRenderTree/win/EditingDelegate.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 EditingDelegate_h
+#define EditingDelegate_h
+
+#include <WebKit/WebKit.h>
+
+class __declspec(uuid("265DCD4B-79C3-44a2-84BC-511C3EDABD6F")) EditingDelegate : public IWebEditingDelegate {
+public:
+ EditingDelegate();
+
+ void setAcceptsEditing(bool b) { m_acceptsEditing = b; }
+
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // IWebEditingDelegate
+ virtual HRESULT STDMETHODCALLTYPE shouldBeginEditingInDOMRange(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IDOMRange *range,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE shouldEndEditingInDOMRange(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IDOMRange *range,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE shouldInsertNode(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IDOMNode *node,
+ /* [in] */ IDOMRange *range,
+ /* [in] */ WebViewInsertAction action);
+
+ virtual HRESULT STDMETHODCALLTYPE shouldInsertText(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR text,
+ /* [in] */ IDOMRange *range,
+ /* [in] */ WebViewInsertAction action,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE shouldDeleteDOMRange(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IDOMRange *range,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE shouldChangeSelectedDOMRange(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IDOMRange *currentRange,
+ /* [in] */ IDOMRange *proposedRange,
+ /* [in] */ WebSelectionAffinity selectionAffinity,
+ /* [in] */ BOOL stillSelecting,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE shouldApplyStyle(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IDOMCSSStyleDeclaration *style,
+ /* [in] */ IDOMRange *range,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE shouldChangeTypingStyle(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IDOMCSSStyleDeclaration *currentStyle,
+ /* [in] */ IDOMCSSStyleDeclaration *proposedStyle,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE doPlatformCommand(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR command,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewDidBeginEditing(
+ /* [in] */ IWebNotification *notification);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewDidChange(
+ /* [in] */ IWebNotification *notification);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewDidEndEditing(
+ /* [in] */ IWebNotification *notification);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewDidChangeTypingStyle(
+ /* [in] */ IWebNotification *notification);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewDidChangeSelection(
+ /* [in] */ IWebNotification *notification);
+
+ virtual HRESULT STDMETHODCALLTYPE undoManagerForWebView(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ IWebUndoManager **undoManager) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE ignoreWordInSpellDocument(
+ /* [in] */ IWebView *view,
+ /* [in] */ BSTR word) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE learnWord(
+ /* [in] */ BSTR word) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE checkSpellingOfString(
+ /* [in] */ IWebView *view,
+ /* [in] */ LPCTSTR text,
+ /* [in] */ int length,
+ /* [out] */ int *misspellingLocation,
+ /* [out] */ int *misspellingLength);
+
+ virtual HRESULT STDMETHODCALLTYPE checkGrammarOfString(
+ /* [in] */ IWebView *view,
+ /* [in] */ LPCTSTR text,
+ /* [in] */ int length,
+ /* [out] */ IEnumWebGrammarDetails **grammarDetails,
+ /* [out] */ int *badGrammarLocation,
+ /* [out] */ int *badGrammarLength) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE updateSpellingUIWithGrammarString(
+ /* [in] */ BSTR string,
+ /* [in] */ int location,
+ /* [in] */ int length,
+ /* [in] */ BSTR userDescription,
+ /* [in] */ BSTR *guesses,
+ /* [in] */ int guessesCount) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE updateSpellingUIWithMisspelledWord(
+ /* [in] */ BSTR word) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE showSpellingUI(
+ /* [in] */ BOOL show) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE spellingUIIsShowing(
+ /* [retval][out] */ BOOL *result) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE guessesForWord(
+ /* [in] */ BSTR word,
+ /* [retval][out] */ IEnumSpellingGuesses **guesses) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE closeSpellDocument(
+ /* [in] */ IWebView *view) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE sharedSpellCheckerExists(
+ /* [retval][out] */ BOOL *exists) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE preflightChosenSpellServer( void) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE updateGrammar( void) { return E_NOTIMPL; }
+
+private:
+ bool m_acceptsEditing;
+ ULONG m_refCount;
+};
+
+#endif // !defined(EditingDelegate_h)
diff --git a/Tools/DumpRenderTree/win/EventSender.cpp b/Tools/DumpRenderTree/win/EventSender.cpp
new file mode 100644
index 000000000..e1c5cd502
--- /dev/null
+++ b/Tools/DumpRenderTree/win/EventSender.cpp
@@ -0,0 +1,693 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "EventSender.h"
+
+#include "DraggingInfo.h"
+#include "DumpRenderTree.h"
+
+#include <WebCore/COMPtr.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/Platform.h>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <JavaScriptCore/Assertions.h>
+#include <WebKit/WebKit.h>
+#include <windows.h>
+
+#define WM_DRT_SEND_QUEUED_EVENT (WM_APP+1)
+
+static bool down;
+static bool dragMode = true;
+static bool replayingSavedEvents;
+static int timeOffset;
+static POINT lastMousePosition;
+
+struct DelayedMessage {
+ MSG msg;
+ unsigned delay;
+};
+
+static DelayedMessage msgQueue[1024];
+static unsigned endOfQueue;
+static unsigned startOfQueue;
+
+static bool didDragEnter;
+DraggingInfo* draggingInfo = 0;
+
+static JSValueRef getDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeBoolean(context, dragMode);
+}
+
+static bool setDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+ dragMode = JSValueToBoolean(context, value);
+ return true;
+}
+
+static JSValueRef getConstantCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+ if (JSStringIsEqualToUTF8CString(propertyName, "WM_KEYDOWN"))
+ return JSValueMakeNumber(context, WM_KEYDOWN);
+ if (JSStringIsEqualToUTF8CString(propertyName, "WM_KEYUP"))
+ return JSValueMakeNumber(context, WM_KEYUP);
+ if (JSStringIsEqualToUTF8CString(propertyName, "WM_CHAR"))
+ return JSValueMakeNumber(context, WM_CHAR);
+ if (JSStringIsEqualToUTF8CString(propertyName, "WM_DEADCHAR"))
+ return JSValueMakeNumber(context, WM_DEADCHAR);
+ if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYDOWN"))
+ return JSValueMakeNumber(context, WM_SYSKEYDOWN);
+ if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYUP"))
+ return JSValueMakeNumber(context, WM_SYSKEYUP);
+ if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSCHAR"))
+ return JSValueMakeNumber(context, WM_SYSCHAR);
+ if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSDEADCHAR"))
+ return JSValueMakeNumber(context, WM_SYSDEADCHAR);
+ ASSERT_NOT_REACHED();
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount > 0) {
+ msgQueue[endOfQueue].delay = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!exception || !*exception);
+ }
+
+ return JSValueMakeUndefined(context);
+}
+
+static DWORD currentEventTime()
+{
+ return ::GetTickCount() + timeOffset;
+}
+
+static MSG makeMsg(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ MSG result = {0};
+ result.hwnd = hwnd;
+ result.message = message;
+ result.wParam = wParam;
+ result.lParam = lParam;
+ result.time = currentEventTime();
+ result.pt = lastMousePosition;
+
+ return result;
+}
+
+static LRESULT dispatchMessage(const MSG* msg)
+{
+ ASSERT(msg);
+ ::TranslateMessage(msg);
+ return ::DispatchMessage(msg);
+}
+
+static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ COMPtr<IWebFramePrivate> framePrivate;
+ if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
+ framePrivate->layout();
+
+ down = true;
+ MSG msg = makeMsg(webViewWindow, WM_RBUTTONDOWN, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
+ dispatchMessage(&msg);
+ down = false;
+ msg = makeMsg(webViewWindow, WM_RBUTTONUP, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
+ dispatchMessage(&msg);
+
+ return JSValueMakeUndefined(context);
+}
+
+static WPARAM buildModifierFlags(JSContextRef context, const JSValueRef modifiers)
+{
+ JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0);
+ if (!modifiersArray)
+ return 0;
+
+ WPARAM flags = 0;
+ int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, JSStringCreateWithUTF8CString("length"), 0), 0);
+ for (int i = 0; i < modifiersCount; ++i) {
+ JSValueRef value = JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0);
+ JSStringRef string = JSValueToStringCopy(context, value, 0);
+ if (JSStringIsEqualToUTF8CString(string, "ctrlKey")
+ || JSStringIsEqualToUTF8CString(string, "addSelectionKey"))
+ flags |= MK_CONTROL;
+ else if (JSStringIsEqualToUTF8CString(string, "shiftKey")
+ || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey"))
+ flags |= MK_SHIFT;
+ // No way to specifiy altKey in a MSG.
+
+ JSStringRelease(string);
+ }
+ return flags;
+}
+
+static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ COMPtr<IWebFramePrivate> framePrivate;
+ if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
+ framePrivate->layout();
+
+ down = true;
+ int mouseType = WM_LBUTTONDOWN;
+ if (argumentCount >= 1) {
+ int mouseNumber = JSValueToNumber(context, arguments[0], exception);
+ switch (mouseNumber) {
+ case 0:
+ mouseType = WM_LBUTTONDOWN;
+ break;
+ case 1:
+ mouseType = WM_MBUTTONDOWN;
+ break;
+ case 2:
+ mouseType = WM_RBUTTONDOWN;
+ break;
+ case 3:
+ // fast/events/mouse-click-events expects the 4th button has event.button = 1, so send an WM_BUTTONDOWN
+ mouseType = WM_MBUTTONDOWN;
+ break;
+ default:
+ mouseType = WM_LBUTTONDOWN;
+ break;
+ }
+ }
+
+ WPARAM wparam = 0;
+ if (argumentCount >= 2)
+ wparam |= buildModifierFlags(context, arguments[1]);
+
+ MSG msg = makeMsg(webViewWindow, mouseType, wparam, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
+ if (!msgQueue[endOfQueue].delay)
+ dispatchMessage(&msg);
+ else {
+ // replaySavedEvents has the required logic to make leapForward delays work
+ msgQueue[endOfQueue++].msg = msg;
+ replaySavedEvents();
+ }
+
+ return JSValueMakeUndefined(context);
+}
+
+static inline POINTL pointl(const POINT& point)
+{
+ POINTL result;
+ result.x = point.x;
+ result.y = point.y;
+ return result;
+}
+
+static void doMouseUp(MSG msg, HRESULT* oleDragAndDropReturnValue = 0)
+{
+ COMPtr<IWebFramePrivate> framePrivate;
+ if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
+ framePrivate->layout();
+
+ dispatchMessage(&msg);
+ down = false;
+
+ if (draggingInfo) {
+ COMPtr<IWebView> webView;
+ COMPtr<IDropTarget> webViewDropTarget;
+ if (SUCCEEDED(frame->webView(&webView)) && SUCCEEDED(webView->QueryInterface(IID_IDropTarget, (void**)&webViewDropTarget))) {
+ POINT screenPoint = msg.pt;
+ DWORD effect = 0;
+ ::ClientToScreen(webViewWindow, &screenPoint);
+ if (!didDragEnter) {
+ webViewDropTarget->DragEnter(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect);
+ didDragEnter = true;
+ }
+ HRESULT hr = draggingInfo->dropSource()->QueryContinueDrag(0, 0);
+ if (oleDragAndDropReturnValue)
+ *oleDragAndDropReturnValue = hr;
+ webViewDropTarget->DragOver(0, pointl(screenPoint), &effect);
+ if (hr == DRAGDROP_S_DROP && effect != DROPEFFECT_NONE) {
+ DWORD effect = 0;
+ webViewDropTarget->Drop(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect);
+ draggingInfo->setPerformedDropEffect(effect);
+ } else
+ webViewDropTarget->DragLeave();
+
+ // Reset didDragEnter so that another drag started within the same frame works properly.
+ didDragEnter = false;
+ }
+ }
+}
+
+static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int mouseType = WM_LBUTTONUP;
+ if (argumentCount >= 1) {
+ int mouseNumber = JSValueToNumber(context, arguments[0], exception);
+ switch (mouseNumber) {
+ case 0:
+ mouseType = WM_LBUTTONUP;
+ break;
+ case 1:
+ mouseType = WM_MBUTTONUP;
+ break;
+ case 2:
+ mouseType = WM_RBUTTONUP;
+ break;
+ case 3:
+ // fast/events/mouse-click-events expects the 4th button has event.button = 1, so send an WM_MBUTTONUP
+ mouseType = WM_MBUTTONUP;
+ break;
+ default:
+ mouseType = WM_LBUTTONUP;
+ break;
+ }
+ }
+
+ WPARAM wparam = 0;
+ if (argumentCount >= 2)
+ wparam |= buildModifierFlags(context, arguments[1]);
+
+ MSG msg = makeMsg(webViewWindow, mouseType, wparam, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
+
+ if ((dragMode && !replayingSavedEvents) || msgQueue[endOfQueue].delay) {
+ msgQueue[endOfQueue++].msg = msg;
+ replaySavedEvents();
+ } else
+ doMouseUp(msg);
+
+ return JSValueMakeUndefined(context);
+}
+
+static void doMouseMove(MSG msg)
+{
+ COMPtr<IWebFramePrivate> framePrivate;
+ if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
+ framePrivate->layout();
+
+ dispatchMessage(&msg);
+
+ if (down && draggingInfo) {
+ POINT screenPoint = msg.pt;
+ ::ClientToScreen(webViewWindow, &screenPoint);
+
+ IWebView* webView;
+ COMPtr<IDropTarget> webViewDropTarget;
+ if (SUCCEEDED(frame->webView(&webView)) && SUCCEEDED(webView->QueryInterface(IID_IDropTarget, (void**)&webViewDropTarget))) {
+ DWORD effect = 0;
+ if (didDragEnter)
+ webViewDropTarget->DragOver(MK_LBUTTON, pointl(screenPoint), &effect);
+ else {
+ webViewDropTarget->DragEnter(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect);
+ didDragEnter = true;
+ }
+ draggingInfo->dropSource()->GiveFeedback(effect);
+ }
+ }
+}
+
+static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ lastMousePosition.x = (int)JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!exception || !*exception);
+ lastMousePosition.y = (int)JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!exception || !*exception);
+
+ MSG msg = makeMsg(webViewWindow, WM_MOUSEMOVE, down ? MK_LBUTTON : 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
+
+ if (dragMode && down && !replayingSavedEvents) {
+ msgQueue[endOfQueue++].msg = msg;
+ return JSValueMakeUndefined(context);
+ }
+
+ doMouseMove(msg);
+
+ return JSValueMakeUndefined(context);
+}
+
+void replaySavedEvents(HRESULT* oleDragAndDropReturnValue)
+{
+ replayingSavedEvents = true;
+
+ MSG msg = { 0 };
+
+ while (startOfQueue < endOfQueue && !msgQueue[startOfQueue].delay) {
+ msg = msgQueue[startOfQueue++].msg;
+ switch (msg.message) {
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+ doMouseUp(msg, oleDragAndDropReturnValue);
+ break;
+ case WM_MOUSEMOVE:
+ doMouseMove(msg);
+ break;
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ dispatchMessage(&msg);
+ break;
+ default:
+ // Not reached
+ break;
+ }
+ }
+
+ int numQueuedMessages = endOfQueue - startOfQueue;
+ if (!numQueuedMessages) {
+ startOfQueue = 0;
+ endOfQueue = 0;
+ replayingSavedEvents = false;
+ ASSERT(!down);
+ return;
+ }
+
+ if (msgQueue[startOfQueue].delay) {
+ ::Sleep(msgQueue[startOfQueue].delay);
+ msgQueue[startOfQueue].delay = 0;
+ }
+
+ ::PostMessage(webViewWindow, WM_DRT_SEND_QUEUED_EVENT, 0, 0);
+ while (::GetMessage(&msg, webViewWindow, 0, 0)) {
+ // FIXME: Why do we get a WM_MOUSELEAVE? it breaks tests
+ if (msg.message == WM_MOUSELEAVE)
+ continue;
+ if (msg.message != WM_DRT_SEND_QUEUED_EVENT) {
+ dispatchMessage(&msg);
+ continue;
+ }
+ msg = msgQueue[startOfQueue++].msg;
+ switch (msg.message) {
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+ doMouseUp(msg, oleDragAndDropReturnValue);
+ break;
+ case WM_MOUSEMOVE:
+ doMouseMove(msg);
+ break;
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ dispatchMessage(&msg);
+ break;
+ default:
+ // Not reached
+ break;
+ }
+ if (startOfQueue >= endOfQueue)
+ break;
+ ::Sleep(msgQueue[startOfQueue].delay);
+ msgQueue[startOfQueue].delay = 0;
+ ::PostMessage(webViewWindow, WM_DRT_SEND_QUEUED_EVENT, 0, 0);
+ }
+ startOfQueue = 0;
+ endOfQueue = 0;
+
+ replayingSavedEvents = false;
+}
+
+static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ static const JSStringRef lengthProperty = JSStringCreateWithUTF8CString("length");
+
+ COMPtr<IWebFramePrivate> framePrivate;
+ if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
+ framePrivate->layout();
+
+ JSStringRef character = JSValueToStringCopy(context, arguments[0], exception);
+ ASSERT(!*exception);
+ int virtualKeyCode;
+ int charCode = 0;
+ int keyData = 1;
+ bool needsShiftKeyModifier = false;
+ if (JSStringIsEqualToUTF8CString(character, "leftArrow")) {
+ virtualKeyCode = VK_LEFT;
+ keyData += KF_EXTENDED << 16; // In this case, extended means "not keypad".
+ } else if (JSStringIsEqualToUTF8CString(character, "rightArrow")) {
+ virtualKeyCode = VK_RIGHT;
+ keyData += KF_EXTENDED << 16;
+ } else if (JSStringIsEqualToUTF8CString(character, "upArrow")) {
+ virtualKeyCode = VK_UP;
+ keyData += KF_EXTENDED << 16;
+ } else if (JSStringIsEqualToUTF8CString(character, "downArrow")) {
+ virtualKeyCode = VK_DOWN;
+ keyData += KF_EXTENDED << 16;
+ } else if (JSStringIsEqualToUTF8CString(character, "pageUp"))
+ virtualKeyCode = VK_PRIOR;
+ else if (JSStringIsEqualToUTF8CString(character, "pageDown"))
+ virtualKeyCode = VK_NEXT;
+ else if (JSStringIsEqualToUTF8CString(character, "home"))
+ virtualKeyCode = VK_HOME;
+ else if (JSStringIsEqualToUTF8CString(character, "end"))
+ virtualKeyCode = VK_END;
+ else if (JSStringIsEqualToUTF8CString(character, "insert"))
+ virtualKeyCode = VK_INSERT;
+ else if (JSStringIsEqualToUTF8CString(character, "delete"))
+ virtualKeyCode = VK_DELETE;
+ else if (JSStringIsEqualToUTF8CString(character, "printScreen"))
+ virtualKeyCode = VK_SNAPSHOT;
+ else if (JSStringIsEqualToUTF8CString(character, "menu"))
+ virtualKeyCode = VK_APPS;
+ else {
+ charCode = JSStringGetCharactersPtr(character)[0];
+ virtualKeyCode = LOBYTE(VkKeyScan(charCode));
+ if (WTF::isASCIIUpper(charCode))
+ needsShiftKeyModifier = true;
+ }
+ JSStringRelease(character);
+
+ BYTE keyState[256];
+ if (argumentCount > 1 || needsShiftKeyModifier) {
+ ::GetKeyboardState(keyState);
+
+ BYTE newKeyState[256];
+ memcpy(newKeyState, keyState, sizeof(keyState));
+
+ if (needsShiftKeyModifier)
+ newKeyState[VK_SHIFT] = 0x80;
+
+ if (argumentCount > 1) {
+ JSObjectRef modifiersArray = JSValueToObject(context, arguments[1], 0);
+ if (modifiersArray) {
+ int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, lengthProperty, 0), 0);
+ for (int i = 0; i < modifiersCount; ++i) {
+ JSValueRef value = JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0);
+ JSStringRef string = JSValueToStringCopy(context, value, 0);
+ if (JSStringIsEqualToUTF8CString(string, "ctrlKey") || JSStringIsEqualToUTF8CString(string, "addSelectionKey"))
+ newKeyState[VK_CONTROL] = 0x80;
+ else if (JSStringIsEqualToUTF8CString(string, "shiftKey") || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey"))
+ newKeyState[VK_SHIFT] = 0x80;
+ else if (JSStringIsEqualToUTF8CString(string, "altKey"))
+ newKeyState[VK_MENU] = 0x80;
+
+ JSStringRelease(string);
+ }
+ }
+ }
+
+ ::SetKeyboardState(newKeyState);
+ }
+
+ MSG msg = makeMsg(webViewWindow, (::GetKeyState(VK_MENU) & 0x8000) ? WM_SYSKEYDOWN : WM_KEYDOWN, virtualKeyCode, keyData);
+ if (virtualKeyCode != 255)
+ dispatchMessage(&msg);
+ else {
+ // For characters that do not exist in the active keyboard layout,
+ // ::Translate will not work, so we post an WM_CHAR event ourselves.
+ ::PostMessage(webViewWindow, WM_CHAR, charCode, 0);
+ }
+
+ // Tests expect that all messages are processed by the time keyDown() returns.
+ if (::PeekMessage(&msg, webViewWindow, WM_CHAR, WM_CHAR, PM_REMOVE) || ::PeekMessage(&msg, webViewWindow, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
+ ::DispatchMessage(&msg);
+
+ MSG msgUp = makeMsg(webViewWindow, (::GetKeyState(VK_MENU) & 0x8000) ? WM_SYSKEYUP : WM_KEYUP, virtualKeyCode, keyData);
+ ::DispatchMessage(&msgUp);
+
+ if (argumentCount > 1 || needsShiftKeyModifier)
+ ::SetKeyboardState(keyState);
+
+ return JSValueMakeUndefined(context);
+}
+
+// eventSender.dispatchMessage(message, wParam, lParam, time = currentEventTime(), x = lastMousePosition.x, y = lastMousePosition.y)
+static JSValueRef dispatchMessageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 3)
+ return JSValueMakeUndefined(context);
+
+ COMPtr<IWebFramePrivate> framePrivate;
+ if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
+ framePrivate->layout();
+
+ MSG msg = {};
+ msg.hwnd = webViewWindow;
+ msg.message = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+ msg.wParam = JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!*exception);
+ msg.lParam = static_cast<ULONG_PTR>(JSValueToNumber(context, arguments[2], exception));
+ ASSERT(!*exception);
+ if (argumentCount >= 4) {
+ msg.time = JSValueToNumber(context, arguments[3], exception);
+ ASSERT(!*exception);
+ }
+ if (!msg.time)
+ msg.time = currentEventTime();
+ if (argumentCount >= 6) {
+ msg.pt.x = JSValueToNumber(context, arguments[4], exception);
+ ASSERT(!*exception);
+ msg.pt.y = JSValueToNumber(context, arguments[5], exception);
+ ASSERT(!*exception);
+ } else
+ msg.pt = lastMousePosition;
+
+ ::DispatchMessage(&msg);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef textZoomInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return JSValueMakeUndefined(context);
+
+ COMPtr<IWebIBActions> webIBActions(Query, webView);
+ if (!webIBActions)
+ return JSValueMakeUndefined(context);
+
+ webIBActions->makeTextLarger(0);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef textZoomOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return JSValueMakeUndefined(context);
+
+ COMPtr<IWebIBActions> webIBActions(Query, webView);
+ if (!webIBActions)
+ return JSValueMakeUndefined(context);
+
+ webIBActions->makeTextSmaller(0);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef zoomPageInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return JSValueMakeUndefined(context);
+
+ COMPtr<IWebIBActions> webIBActions(Query, webView);
+ if (!webIBActions)
+ return JSValueMakeUndefined(context);
+
+ webIBActions->zoomPageIn(0);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef zoomPageOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return JSValueMakeUndefined(context);
+
+ COMPtr<IWebIBActions> webIBActions(Query, webView);
+ if (!webIBActions)
+ return JSValueMakeUndefined(context);
+
+ webIBActions->zoomPageOut(0);
+ return JSValueMakeUndefined(context);
+}
+
+static JSStaticFunction staticFunctions[] = {
+ { "contextClick", contextClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "leapForward", leapForwardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "dispatchMessage", dispatchMessageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textZoomIn", textZoomInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textZoomOut", textZoomOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "zoomPageIn", zoomPageInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "zoomPageOut", zoomPageOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+};
+
+static JSStaticValue staticValues[] = {
+ { "dragMode", getDragModeCallback, setDragModeCallback, kJSPropertyAttributeNone },
+ { "WM_KEYDOWN", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
+ { "WM_KEYUP", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
+ { "WM_CHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
+ { "WM_DEADCHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
+ { "WM_SYSKEYDOWN", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
+ { "WM_SYSKEYUP", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
+ { "WM_SYSCHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
+ { "WM_SYSDEADCHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
+ { 0, 0, 0, 0 }
+};
+
+static JSClassRef getClass(JSContextRef context)
+{
+ static JSClassRef eventSenderClass = 0;
+
+ if (!eventSenderClass) {
+ JSClassDefinition classDefinition = {0};
+ classDefinition.staticFunctions = staticFunctions;
+ classDefinition.staticValues = staticValues;
+
+ eventSenderClass = JSClassCreate(&classDefinition);
+ }
+
+ return eventSenderClass;
+}
+
+JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame)
+{
+ if (isTopFrame) {
+ down = false;
+ dragMode = true;
+ replayingSavedEvents = false;
+ timeOffset = 0;
+ lastMousePosition.x = 0;
+ lastMousePosition.y = 0;
+
+ endOfQueue = 0;
+ startOfQueue = 0;
+
+ didDragEnter = false;
+ draggingInfo = 0;
+ }
+ return JSObjectMake(context, getClass(context), 0);
+}
diff --git a/Tools/DumpRenderTree/win/EventSender.h b/Tools/DumpRenderTree/win/EventSender.h
new file mode 100644
index 000000000..a0add85eb
--- /dev/null
+++ b/Tools/DumpRenderTree/win/EventSender.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 EventSender_h
+#define EventSender_h
+
+class DraggingInfo;
+
+typedef long HRESULT;
+typedef const struct OpaqueJSContext* JSContextRef;
+typedef struct OpaqueJSValue* JSObjectRef;
+
+JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame);
+void replaySavedEvents(HRESULT* oleDragAndDropReturnValue = 0);
+
+extern DraggingInfo* draggingInfo;
+
+#endif
diff --git a/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp b/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp
new file mode 100644
index 000000000..c5b9e3396
--- /dev/null
+++ b/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "FrameLoadDelegate.h"
+
+#include "AccessibilityController.h"
+#include "DumpRenderTree.h"
+#include "EventSender.h"
+#include "GCController.h"
+#include "LayoutTestController.h"
+#include "WebCoreTestSupport.h"
+#include "WorkQueueItem.h"
+#include "WorkQueue.h"
+#include <WebCore/COMPtr.h>
+#include <JavaScriptCore/Assertions.h>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <WebKit/WebKit.h>
+#include <stdio.h>
+#include <string>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+using std::string;
+
+static FrameLoadDelegate* g_delegateWaitingOnTimer;
+
+string descriptionSuitableForTestResult(IWebFrame* webFrame)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(webFrame->webView(&webView)))
+ return string();
+
+ COMPtr<IWebFrame> mainFrame;
+ if (FAILED(webView->mainFrame(&mainFrame)))
+ return string();
+
+ BSTR frameNameBSTR;
+ if (FAILED(webFrame->name(&frameNameBSTR)) || toUTF8(frameNameBSTR).empty())
+ return (webFrame == mainFrame) ? "main frame" : string();
+
+ string frameName = (webFrame == mainFrame) ? "main frame" : "frame";
+ frameName += " \"" + toUTF8(frameNameBSTR) + "\"";
+
+ SysFreeString(frameNameBSTR);
+ return frameName;
+}
+
+FrameLoadDelegate::FrameLoadDelegate()
+ : m_refCount(1)
+ , m_gcController(adoptPtr(new GCController))
+ , m_accessibilityController(adoptPtr(new AccessibilityController))
+{
+}
+
+FrameLoadDelegate::~FrameLoadDelegate()
+{
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IsEqualGUID(riid, IID_IUnknown))
+ *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate))
+ *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate))
+ *ppvObject = static_cast<IWebFrameLoadDelegatePrivate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegatePrivate2))
+ *ppvObject = static_cast<IWebFrameLoadDelegatePrivate2*>(this);
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE FrameLoadDelegate::AddRef(void)
+{
+ return ++m_refCount;
+}
+
+ULONG STDMETHODCALLTYPE FrameLoadDelegate::Release(void)
+{
+ ULONG newRef = --m_refCount;
+ if (!newRef)
+ delete(this);
+
+ return newRef;
+}
+
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didStartProvisionalLoadForFrame(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IWebFrame* frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didStartProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
+
+ // Make sure we only set this once per test. If it gets cleared, and then set again, we might
+ // end up doing two dumps for one test.
+ if (!topLoadingFrame && !done)
+ topLoadingFrame = frame;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveServerRedirectForProvisionalLoadForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didReceiveServerRedirectForProvisionalLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailProvisionalLoadWithError(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebError *error,
+ /* [in] */ IWebFrame *frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didFailProvisionalLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
+
+ locationChangeDone(error, frame);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCommitLoadForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didCommitLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
+
+ COMPtr<IWebViewPrivate> webViewPrivate;
+ HRESULT hr = webView->QueryInterface(&webViewPrivate);
+ if (FAILED(hr))
+ return hr;
+ webViewPrivate->updateFocusedAndActiveState();
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didReceiveTitle(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR title,
+ /* [in] */ IWebFrame *frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didReceiveTitle: %S\n", descriptionSuitableForTestResult(frame).c_str(), title);
+
+ if (::gLayoutTestController->dumpTitleChanges() && !done)
+ printf("TITLE CHANGED: %S\n", title ? title : L"");
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didChangeIcons(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IWebFrame* frame)
+{
+ if (!done && gLayoutTestController->dumpIconChanges())
+ printf("%s - didChangeIcons\n", descriptionSuitableForTestResult(frame).c_str());
+
+ return S_OK;
+}
+
+void FrameLoadDelegate::processWork()
+{
+ // if another load started, then wait for it to complete.
+ if (topLoadingFrame)
+ return;
+
+ // if we finish all the commands, we're ready to dump state
+ if (WorkQueue::shared()->processWork() && !::gLayoutTestController->waitToDump())
+ dump();
+}
+
+void FrameLoadDelegate::resetToConsistentState()
+{
+ m_accessibilityController->resetToConsistentState();
+}
+
+typedef Vector<COMPtr<FrameLoadDelegate> > DelegateVector;
+static DelegateVector& delegatesWithDelayedWork()
+{
+ DEFINE_STATIC_LOCAL(DelegateVector, delegates, ());
+ return delegates;
+}
+
+static UINT_PTR processWorkTimerID;
+
+static void CALLBACK processWorkTimer(HWND hwnd, UINT, UINT_PTR id, DWORD)
+{
+ ASSERT_ARG(id, id == processWorkTimerID);
+ ::KillTimer(hwnd, id);
+ processWorkTimerID = 0;
+
+ DelegateVector delegates;
+ delegates.swap(delegatesWithDelayedWork());
+
+ for (size_t i = 0; i < delegates.size(); ++i)
+ delegates[i]->processWork();
+}
+
+void FrameLoadDelegate::locationChangeDone(IWebError*, IWebFrame* frame)
+{
+ if (frame != topLoadingFrame)
+ return;
+
+ topLoadingFrame = 0;
+ WorkQueue::shared()->setFrozen(true);
+
+ if (::gLayoutTestController->waitToDump())
+ return;
+
+ if (WorkQueue::shared()->count()) {
+ if (!processWorkTimerID)
+ processWorkTimerID = ::SetTimer(0, 0, 0, processWorkTimer);
+ delegatesWithDelayedWork().append(this);
+ return;
+ }
+
+ dump();
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishLoadForFrame(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IWebFrame* frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didFinishLoadForFrame\n", descriptionSuitableForTestResult(frame).c_str());
+
+ locationChangeDone(0, frame);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFailLoadWithError(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IWebError* error,
+ /* [in] */ IWebFrame* frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didFailLoadWithError\n", descriptionSuitableForTestResult(frame).c_str());
+
+ locationChangeDone(error, frame);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willPerformClientRedirectToURL(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR url,
+ /* [in] */ double delaySeconds,
+ /* [in] */ DATE fireDate,
+ /* [in] */ IWebFrame *frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - willPerformClientRedirectToURL: %S \n", descriptionSuitableForTestResult(frame).c_str(),
+ urlSuitableForTestResult(std::wstring(url, ::SysStringLen(url))).c_str());
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didCancelClientRedirectForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didCancelClientRedirectForFrame\n", descriptionSuitableForTestResult(frame).c_str());
+
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willCloseFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT FrameLoadDelegate::didClearWindowObject(IWebView*, JSContextRef, JSObjectRef, IWebFrame*)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT FrameLoadDelegate::didClearWindowObjectForFrameInScriptWorld(IWebView* webView, IWebFrame* frame, IWebScriptWorld* world)
+{
+ ASSERT_ARG(webView, webView);
+ ASSERT_ARG(frame, frame);
+ ASSERT_ARG(world, world);
+ if (!webView || !frame || !world)
+ return E_POINTER;
+
+ COMPtr<IWebScriptWorld> standardWorld;
+ if (FAILED(world->standardWorld(&standardWorld)))
+ return S_OK;
+
+ if (world == standardWorld)
+ didClearWindowObjectForFrameInStandardWorld(frame);
+ else
+ didClearWindowObjectForFrameInIsolatedWorld(frame, world);
+ return S_OK;
+}
+
+void FrameLoadDelegate::didClearWindowObjectForFrameInIsolatedWorld(IWebFrame* frame, IWebScriptWorld* world)
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return;
+
+ JSGlobalContextRef ctx = framePrivate->globalContextForScriptWorld(world);
+ if (!ctx)
+ return;
+
+ JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
+ if (!globalObject)
+ return;
+
+ JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
+ return;
+}
+
+void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* frame)
+{
+ JSGlobalContextRef context = frame->globalContext();
+ JSObjectRef windowObject = JSContextGetGlobalObject(context);
+
+ IWebFrame* parentFrame = 0;
+ frame->parentFrame(&parentFrame);
+
+ JSValueRef exception = 0;
+
+ ::gLayoutTestController->makeWindowObject(context, windowObject, &exception);
+ ASSERT(!exception);
+
+ m_gcController->makeWindowObject(context, windowObject, &exception);
+ ASSERT(!exception);
+
+ m_accessibilityController->makeWindowObject(context, windowObject, &exception);
+ ASSERT(!exception);
+
+ JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
+ JSValueRef eventSender = makeEventSender(context, !parentFrame);
+ JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
+ JSStringRelease(eventSenderStr);
+
+ WebCoreTestSupport::injectInternalsObject(context);
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishDocumentLoadForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didFinishDocumentLoadForFrame\n",
+ descriptionSuitableForTestResult(frame).c_str());
+ if (!done) {
+ COMPtr<IWebFramePrivate> webFramePrivate;
+ HRESULT hr = frame->QueryInterface(&webFramePrivate);
+ if (FAILED(hr))
+ return hr;
+ unsigned pendingFrameUnloadEvents;
+ hr = webFramePrivate->pendingFrameUnloadEventCount(&pendingFrameUnloadEvents);
+ if (FAILED(hr))
+ return hr;
+ if (pendingFrameUnloadEvents)
+ printf("%s - has %u onunload handler(s)\n",
+ descriptionSuitableForTestResult(frame).c_str(), pendingFrameUnloadEvents);
+ }
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didHandleOnloadEventsForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("%s - didHandleOnloadEventsForFrame\n",
+ descriptionSuitableForTestResult(frame).c_str());
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFirstVisuallyNonEmptyLayoutInFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame)
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didDisplayInsecureContent(
+ /* [in] */ IWebView *sender)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("didDisplayInsecureContent\n");
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didRunInsecureContent(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebSecurityOrigin *origin)
+{
+ if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
+ printf("didRunInsecureContent\n");
+
+ return S_OK;
+}
+
diff --git a/Tools/DumpRenderTree/win/FrameLoadDelegate.h b/Tools/DumpRenderTree/win/FrameLoadDelegate.h
new file mode 100644
index 000000000..4cd5e1148
--- /dev/null
+++ b/Tools/DumpRenderTree/win/FrameLoadDelegate.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 FrameLoadDelegate_h
+#define FrameLoadDelegate_h
+
+#include <WebKit/WebKit.h>
+#include <wtf/OwnPtr.h>
+
+class AccessibilityController;
+class GCController;
+
+class FrameLoadDelegate : public IWebFrameLoadDelegate, public IWebFrameLoadDelegatePrivate2 {
+public:
+ FrameLoadDelegate();
+ virtual ~FrameLoadDelegate();
+
+ void processWork();
+
+ void resetToConsistentState();
+
+ AccessibilityController* accessibilityController() const { return m_accessibilityController.get(); }
+
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // IWebFrameLoadDelegate
+ virtual HRESULT STDMETHODCALLTYPE didStartProvisionalLoadForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didReceiveServerRedirectForProvisionalLoadForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didFailProvisionalLoadWithError(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebError *error,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didCommitLoadForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didReceiveTitle(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR title,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didChangeIcons(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didReceiveIcon(
+ /* [in] */ IWebView *webView,
+ /* [in] */ OLE_HANDLE image,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didFinishLoadForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didFailLoadWithError(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebError *error,
+ /* [in] */ IWebFrame *forFrame);
+
+ virtual HRESULT STDMETHODCALLTYPE didChangeLocationWithinPageForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE willPerformClientRedirectToURL(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR url,
+ /* [in] */ double delaySeconds,
+ /* [in] */ DATE fireDate,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didCancelClientRedirectForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE willCloseFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE windowScriptObjectAvailable(
+ /* [in] */ IWebView *sender,
+ /* [in] */ JSContextRef context,
+ /* [in] */ JSObjectRef windowObject) { return E_NOTIMPL; }
+
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE didClearWindowObject(
+ /* [in] */ IWebView* webView,
+ /* [in] */ JSContextRef context,
+ /* [in] */ JSObjectRef windowObject,
+ /* [in] */ IWebFrame* frame);
+
+ // IWebFrameLoadDelegatePrivate
+ virtual HRESULT STDMETHODCALLTYPE didFinishDocumentLoadForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didFirstLayoutInFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didHandleOnloadEventsForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE didFirstVisuallyNonEmptyLayoutInFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame);
+
+ // IWebFrameLoadDelegatePrivate2
+ virtual HRESULT STDMETHODCALLTYPE didDisplayInsecureContent(
+ /* [in] */ IWebView *sender);
+
+ virtual HRESULT STDMETHODCALLTYPE didRunInsecureContent(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebSecurityOrigin *origin);
+
+ virtual HRESULT STDMETHODCALLTYPE didClearWindowObjectForFrameInScriptWorld(IWebView*, IWebFrame*, IWebScriptWorld*);
+
+ virtual HRESULT STDMETHODCALLTYPE didPushStateWithinPageForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didReplaceStateWithinPageForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didPopStateWithinPageForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+private:
+ void didClearWindowObjectForFrameInIsolatedWorld(IWebFrame*, IWebScriptWorld*);
+ void didClearWindowObjectForFrameInStandardWorld(IWebFrame*);
+
+ void locationChangeDone(IWebError*, IWebFrame*);
+
+ ULONG m_refCount;
+ OwnPtr<GCController> m_gcController;
+ OwnPtr<AccessibilityController> m_accessibilityController;
+};
+
+#endif // FrameLoadDelegate_h
diff --git a/Tools/DumpRenderTree/win/GCControllerWin.cpp b/Tools/DumpRenderTree/win/GCControllerWin.cpp
new file mode 100644
index 000000000..b86725086
--- /dev/null
+++ b/Tools/DumpRenderTree/win/GCControllerWin.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h"
+
+#include "DumpRenderTree.h"
+#include <WebCore/COMPtr.h>
+#include <WebKit/WebKit.h>
+#include <WebKit/WebKitCOMAPI.h>
+
+void GCController::collect() const
+{
+ COMPtr<IWebJavaScriptCollector> collector;
+ if (FAILED(WebKitCreateInstance(CLSID_WebJavaScriptCollector, 0, IID_IWebJavaScriptCollector, (void**)&collector)))
+ return;
+ collector->collect();
+}
+
+void GCController::collectOnAlternateThread(bool waitUntilDone) const
+{
+ COMPtr<IWebJavaScriptCollector> collector;
+ if (FAILED(WebKitCreateInstance(CLSID_WebJavaScriptCollector, 0, IID_IWebJavaScriptCollector, (void**)&collector)))
+ return;
+ collector->collectOnAlternateThread(waitUntilDone ? TRUE : FALSE);
+}
+
+size_t GCController::getJSObjectCount() const
+{
+ COMPtr<IWebJavaScriptCollector> collector;
+ if (FAILED(WebKitCreateInstance(CLSID_WebJavaScriptCollector, 0, IID_IWebJavaScriptCollector, (void**)&collector)))
+ return 0;
+ UINT objects = 0;
+ collector->objectCount(&objects);
+ return objects;
+}
diff --git a/Tools/DumpRenderTree/win/HistoryDelegate.cpp b/Tools/DumpRenderTree/win/HistoryDelegate.cpp
new file mode 100644
index 000000000..8a41facfc
--- /dev/null
+++ b/Tools/DumpRenderTree/win/HistoryDelegate.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HistoryDelegate.h"
+
+#include "DumpRenderTree.h"
+#include "DumpRenderTreeWin.h"
+#include "LayoutTestController.h"
+#include <string>
+#include <WebKit/WebKit.h>
+
+using std::wstring;
+
+static inline wstring wstringFromBSTR(BSTR str)
+{
+ return wstring(str, ::SysStringLen(str));
+}
+
+HistoryDelegate::HistoryDelegate()
+ : m_refCount(1)
+{
+}
+
+HistoryDelegate::~HistoryDelegate()
+{
+}
+
+ // IUnknown
+HRESULT HistoryDelegate::QueryInterface(REFIID riid, void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IsEqualGUID(riid, IID_IUnknown))
+ *ppvObject = static_cast<IWebHistoryDelegate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebHistoryDelegate))
+ *ppvObject = static_cast<IWebHistoryDelegate*>(this);
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG HistoryDelegate::AddRef(void)
+{
+ return ++m_refCount;
+}
+
+ULONG HistoryDelegate::Release(void)
+{
+ ULONG newRef = --m_refCount;
+ if (!newRef)
+ delete(this);
+
+ return newRef;
+}
+
+// IWebHistoryDelegate
+HRESULT HistoryDelegate::didNavigateWithNavigationData(IWebView* webView, IWebNavigationData* navigationData, IWebFrame* webFrame)
+{
+ if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
+ return S_OK;
+
+ BSTR urlBSTR;
+ if (FAILED(navigationData->url(&urlBSTR)))
+ return E_FAIL;
+ wstring url;
+ if (urlBSTR)
+ url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
+ SysFreeString(urlBSTR);
+
+ BSTR titleBSTR;
+ if (FAILED(navigationData->title(&titleBSTR)))
+ return E_FAIL;
+ wstring title;
+ if (titleBSTR)
+ title = wstringFromBSTR(titleBSTR);
+ SysFreeString(titleBSTR);
+
+ COMPtr<IWebURLRequest> request;
+ if (FAILED(navigationData->originalRequest(&request)))
+ return E_FAIL;
+
+ BSTR httpMethodBSTR;
+ if (FAILED(request->HTTPMethod(&httpMethodBSTR)))
+ return E_FAIL;
+ wstring httpMethod;
+ if (httpMethodBSTR)
+ httpMethod = wstringFromBSTR(httpMethodBSTR);
+ SysFreeString(httpMethodBSTR);
+
+ COMPtr<IWebURLResponse> response;
+ if (FAILED(navigationData->response(&response)))
+ return E_FAIL;
+
+ COMPtr<IWebHTTPURLResponse> httpResponse;
+ if (FAILED(response->QueryInterface(&httpResponse)))
+ return E_FAIL;
+
+ int statusCode = 0;
+ if (FAILED(httpResponse->statusCode(&statusCode)))
+ return E_FAIL;
+
+ BOOL hasSubstituteData;
+ if (FAILED(navigationData->hasSubstituteData(&hasSubstituteData)))
+ return E_FAIL;
+
+ BSTR clientRedirectSourceBSTR;
+ if (FAILED(navigationData->clientRedirectSource(&clientRedirectSourceBSTR)))
+ return E_FAIL;
+ bool hasClientRedirect = clientRedirectSourceBSTR && SysStringLen(clientRedirectSourceBSTR);
+ wstring redirectSource;
+ if (clientRedirectSourceBSTR)
+ redirectSource = urlSuitableForTestResult(wstringFromBSTR(clientRedirectSourceBSTR));
+ SysFreeString(clientRedirectSourceBSTR);
+
+ bool wasFailure = hasSubstituteData || (httpResponse && statusCode >= 400);
+
+ printf("WebView navigated to url \"%S\" with title \"%S\" with HTTP equivalent method \"%S\". The navigation was %s and was %s%S.\n",
+ url.c_str(),
+ title.c_str(),
+ httpMethod.c_str(),
+ wasFailure ? "a failure" : "successful",
+ hasClientRedirect ? "a client redirect from " : "not a client redirect",
+ redirectSource.c_str());
+
+ return S_OK;
+}
+
+HRESULT HistoryDelegate::didPerformClientRedirectFromURL(IWebView*, BSTR sourceURL, BSTR destinationURL, IWebFrame*)
+{
+ if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
+ return S_OK;
+
+ wstring source;
+ if (sourceURL)
+ source = urlSuitableForTestResult(wstringFromBSTR(sourceURL));
+
+ wstring destination;
+ if (destinationURL)
+ destination = urlSuitableForTestResult(wstringFromBSTR(destinationURL));
+
+ printf("WebView performed a client redirect from \"%S\" to \"%S\".\n", source.c_str(), destination.c_str());
+ return S_OK;
+}
+
+HRESULT HistoryDelegate::didPerformServerRedirectFromURL(IWebView* webView, BSTR sourceURL, BSTR destinationURL, IWebFrame* webFrame)
+{
+ if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
+ return S_OK;
+
+ wstring source;
+ if (sourceURL)
+ source = urlSuitableForTestResult(wstringFromBSTR(sourceURL));
+
+ wstring destination;
+ if (destinationURL)
+ destination = urlSuitableForTestResult(wstringFromBSTR(destinationURL));
+
+ printf("WebView performed a server redirect from \"%S\" to \"%S\".\n", source.c_str(), destination.c_str());
+ return S_OK;
+}
+
+HRESULT HistoryDelegate::updateHistoryTitle(IWebView* webView, BSTR titleBSTR, BSTR urlBSTR)
+{
+ if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
+ return S_OK;
+
+ wstring url;
+ if (urlBSTR)
+ url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
+
+ wstring title;
+ if (titleBSTR)
+ title = wstringFromBSTR(titleBSTR);
+
+ printf("WebView updated the title for history URL \"%S\" to \"%S\".\n", url.c_str(), title.c_str());
+ return S_OK;
+}
+
+HRESULT HistoryDelegate::populateVisitedLinksForWebView(IWebView* webView)
+{
+ if (!gLayoutTestController->dumpHistoryDelegateCallbacks())
+ return S_OK;
+
+ BSTR urlBSTR;
+ if (FAILED(webView->mainFrameURL(&urlBSTR)))
+ return E_FAIL;
+
+ wstring url;
+ if (urlBSTR)
+ url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
+ SysFreeString(urlBSTR);
+
+ if (gLayoutTestController->dumpVisitedLinksCallback())
+ printf("Asked to populate visited links for WebView \"%S\"\n", url.c_str());
+
+ return S_OK;
+}
diff --git a/Tools/DumpRenderTree/win/HistoryDelegate.h b/Tools/DumpRenderTree/win/HistoryDelegate.h
new file mode 100644
index 000000000..41be670db
--- /dev/null
+++ b/Tools/DumpRenderTree/win/HistoryDelegate.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HistoryDelegate_h
+#define HistoryDelegate_h
+
+#include <WebKit/WebKit.h>
+#include <wtf/OwnPtr.h>
+
+class HistoryDelegate : public IWebHistoryDelegate {
+public:
+ HistoryDelegate();
+ virtual ~HistoryDelegate();
+
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // IWebHistoryDelegate
+ virtual HRESULT STDMETHODCALLTYPE didNavigateWithNavigationData(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IWebNavigationData* navigationData,
+ /* [in] */ IWebFrame* webFrame);
+
+ virtual HRESULT STDMETHODCALLTYPE didPerformClientRedirectFromURL(
+ /* [in] */ IWebView* webView,
+ /* [in] */ BSTR sourceURL,
+ /* [in] */ BSTR destinationURL,
+ /* [in] */ IWebFrame* webFrame);
+
+ virtual HRESULT STDMETHODCALLTYPE didPerformServerRedirectFromURL(
+ /* [in] */ IWebView* webView,
+ /* [in] */ BSTR sourceURL,
+ /* [in] */ BSTR destinationURL,
+ /* [in] */ IWebFrame* webFrame);
+
+ virtual HRESULT STDMETHODCALLTYPE updateHistoryTitle(
+ /* [in] */ IWebView* webView,
+ /* [in] */ BSTR title,
+ /* [in] */ BSTR url);
+
+ virtual HRESULT STDMETHODCALLTYPE populateVisitedLinksForWebView(
+ /* [in] */ IWebView* webView);
+
+private:
+ ULONG m_refCount;
+};
+
+#endif // HistoryDelegate_h
diff --git a/Tools/DumpRenderTree/win/ImageDiff.vcproj b/Tools/DumpRenderTree/win/ImageDiff.vcproj
new file mode 100644
index 000000000..c3201bf21
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiff.vcproj
@@ -0,0 +1,452 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiff"
+ ProjectGUID="{59CC0547-70AC-499C-9B19-EC01C6F61137}"
+ RootNamespace="ImageDiff"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\ImageDiffDebug.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\ImageDiffRelease.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\ImageDiffDebugAll.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_Cairo_CFLite|Win32"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\ImageDiffDebugCairoCFLite.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Production|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\ImageDiffProduction.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_Cairo_CFLite|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\ImageDiffReleaseCairoCFLite.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\win\ImageDiffCairo.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Production|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cg\ImageDiffCG.cpp"
+ >
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\ImageDiffWin.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/DumpRenderTree/win/ImageDiffCairo.cpp b/Tools/DumpRenderTree/win/ImageDiffCairo.cpp
new file mode 100644
index 000000000..d10cc14c6
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffCairo.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Ben La Monica <ben.lamonica@gmail.com>. All rights reserved.
+ * Copyright (C) 2011 Brent Fulgham. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: We need to be able to include these defines from a config.h somewhere.
+#define JS_EXPORT_PRIVATE
+#define WTF_EXPORT_PRIVATE
+
+#include <cairo.h>
+#include <stdio.h>
+#include <wtf/Platform.h>
+#include <wtf/RefPtr.h>
+#include <wtf/RetainPtr.h>
+
+#if PLATFORM(WIN)
+#include <fcntl.h>
+#include <io.h>
+#include <windows.h>
+#include <wtf/MathExtras.h>
+#endif
+
+using namespace std;
+
+static const int s_bufferSize = 2048;
+static const int s_bytesPerPixel = 4;
+static cairo_user_data_key_t s_imageDataKey;
+
+
+#if PLATFORM(WIN)
+#undef min
+#undef max
+
+static inline float strtof(const char* inputString, char** endptr)
+{
+ return strtod(inputString, endptr);
+}
+#endif
+
+static cairo_status_t readFromData(void* closure, unsigned char* data, unsigned int length)
+{
+ CFMutableDataRef dataSource = reinterpret_cast<CFMutableDataRef>(closure);
+
+ CFRange range = CFRangeMake(0, length);
+ CFDataGetBytes(dataSource, range, data);
+ CFDataDeleteBytes(dataSource, range);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_surface_t* createImageFromStdin(int bytesRemaining)
+{
+ unsigned char buffer[s_bufferSize];
+ RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, bytesRemaining));
+
+ while (bytesRemaining > 0) {
+ size_t bytesToRead = min(bytesRemaining, s_bufferSize);
+ size_t bytesRead = fread(buffer, 1, bytesToRead, stdin);
+ CFDataAppendBytes(data.get(), buffer, static_cast<CFIndex>(bytesRead));
+ bytesRemaining -= static_cast<int>(bytesRead);
+ }
+
+ return cairo_image_surface_create_from_png_stream (static_cast<cairo_read_func_t>(readFromData), data.get());
+}
+
+static void releaseMallocBuffer(void* data)
+{
+ free(data);
+}
+
+static inline float pixelDifference(float expected, float actual)
+{
+ return (actual - expected) / max<float>(255 - expected, expected);
+}
+
+static inline void normalizeBuffer(float maxDistance, unsigned char* buffer, size_t length)
+{
+ if (maxDistance >= 1)
+ return;
+
+ for (size_t p = 0; p < length; ++p)
+ buffer[p] /= maxDistance;
+}
+
+static cairo_surface_t* createDifferenceImage(cairo_surface_t* baselineImage, cairo_surface_t* actualImage, float& difference)
+{
+ size_t width = cairo_image_surface_get_width(baselineImage);
+ size_t height = cairo_image_surface_get_height(baselineImage);
+
+ unsigned char* baselinePixel = cairo_image_surface_get_data(baselineImage);
+ unsigned char* actualPixel = cairo_image_surface_get_data(actualImage);
+
+ // Compare the content of the 2 bitmaps
+ void* diffBuffer = malloc(width * height);
+ unsigned char* diffPixel = reinterpret_cast<unsigned char*>(diffBuffer);
+
+ float count = 0;
+ float sum = 0;
+ float maxDistance = 0;
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ float red = pixelDifference(baselinePixel[0], actualPixel[0]);
+ float green = pixelDifference(baselinePixel[1], actualPixel[1]);
+ float blue = pixelDifference(baselinePixel[2], actualPixel[2]);
+ float alpha = pixelDifference(baselinePixel[3], actualPixel[3]);
+
+ float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0;
+
+ *diffPixel++ = static_cast<unsigned char>(distance * 255);
+
+ if (distance >= 1.0 / 255.0) {
+ ++count;
+ sum += distance;
+ if (distance > maxDistance)
+ maxDistance = distance;
+ }
+
+ baselinePixel += s_bytesPerPixel;
+ actualPixel += s_bytesPerPixel;
+ }
+ }
+
+ // Compute the difference as a percentage combining both the number of different pixels and their difference amount i.e. the average distance over the entire image
+ if (count > 0)
+ difference = 100.0f * sum / (height * width);
+ else
+ difference = 0;
+
+ if (!difference) {
+ free(diffBuffer);
+ return 0;
+ }
+
+ // Generate a normalized diff image
+ normalizeBuffer(maxDistance, reinterpret_cast<unsigned char*>(diffBuffer), height * width);
+
+ cairo_surface_t* diffImage = cairo_image_surface_create_for_data(diffPixel, CAIRO_FORMAT_ARGB32, width, height, width * s_bytesPerPixel);
+ cairo_surface_set_user_data(diffImage, &s_imageDataKey, diffBuffer, releaseMallocBuffer);
+
+ return diffImage;
+}
+
+static inline bool imageHasAlpha(cairo_surface_t* image)
+{
+ return (cairo_image_surface_get_format(image) == CAIRO_FORMAT_ARGB32);
+}
+
+static cairo_status_t writeToData(void* closure, unsigned char* data, unsigned int length)
+{
+ CFMutableDataRef dataTarget = reinterpret_cast<CFMutableDataRef>(closure);
+
+ CFDataAppendBytes(dataTarget, data, length);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+int main(int argc, const char* argv[])
+{
+#if PLATFORM(WIN)
+ _setmode(0, _O_BINARY);
+ _setmode(1, _O_BINARY);
+#endif
+
+ float tolerance = 0;
+
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) {
+ if (i >= argc - 1)
+ exit(1);
+ tolerance = strtof(argv[i + 1], 0);
+ ++i;
+ continue;
+ }
+ }
+
+ char buffer[s_bufferSize];
+ cairo_surface_t* actualImage = 0;
+ cairo_surface_t* baselineImage = 0;
+
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ char* newLineCharacter = strchr(buffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (!strncmp("Content-Length: ", buffer, 16)) {
+ strtok(buffer, " ");
+ int imageSize = strtol(strtok(0, " "), 0, 10);
+
+ if (imageSize > 0 && !actualImage)
+ actualImage = createImageFromStdin(imageSize);
+ else if (imageSize > 0 && !baselineImage)
+ baselineImage = createImageFromStdin(imageSize);
+ else
+ fputs("error, image size must be specified.\n", stdout);
+ }
+
+ if (actualImage && baselineImage) {
+ cairo_surface_t* diffImage = 0;
+ float difference = 100.0;
+
+ if ((cairo_image_surface_get_width(actualImage) == cairo_image_surface_get_width(baselineImage))
+ && (cairo_image_surface_get_height(actualImage) == cairo_image_surface_get_height(baselineImage))
+ && (imageHasAlpha(actualImage) == imageHasAlpha(baselineImage))) {
+ diffImage = createDifferenceImage(actualImage, baselineImage, difference); // difference is passed by reference
+ if (difference <= tolerance)
+ difference = 0;
+ else {
+ difference = roundf(difference * 100.0) / 100.0;
+ difference = max<float>(difference, 0.01); // round to 2 decimal places
+ }
+ } else
+ fputs("error, test and reference image have different properties.\n", stderr);
+
+ if (difference > 0.0) {
+ if (diffImage) {
+ RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0));
+ cairo_surface_write_to_png_stream(diffImage, (cairo_write_func_t)writeToData, imageData.get());
+ printf("Content-Length: %lu\n", CFDataGetLength(imageData.get()));
+ fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout);
+ cairo_surface_destroy(diffImage);
+ diffImage = 0;
+ }
+
+ fprintf(stdout, "diff: %01.2f%% failed\n", difference);
+ } else
+ fprintf(stdout, "diff: %01.2f%% passed\n", difference);
+
+ cairo_surface_destroy(actualImage);
+ cairo_surface_destroy(baselineImage);
+ actualImage = 0;
+ baselineImage = 0;
+ }
+
+ fflush(stdout);
+ }
+
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops b/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops
new file mode 100644
index 000000000..c94645956
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ConfigurationBuildDir)\include&quot;;&quot;$(ConfigurationBuildDir)\include\private&quot;;&quot;$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitLibrariesDir)\include&quot;;&quot;$(WebKitLibrariesDir)\include\private&quot;"
+ PreprocessorDefinitions="NOMINMAX"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/NXCOMPAT"
+ AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib CoreGraphics$(LibraryConfigSuffix).lib CoreFoundation$(LibraryConfigSuffix).lib"
+ OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix).dll"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffDebug.vsprops b/Tools/DumpRenderTree/win/ImageDiffDebug.vsprops
new file mode 100644
index 000000000..5b31049bc
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffDebug.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffDebug"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\ImageDiffCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffDebugAll.vsprops b/Tools/DumpRenderTree/win/ImageDiffDebugAll.vsprops
new file mode 100644
index 000000000..5a201cd6f
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffDebugAll.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffDebugAll"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\ImageDiffCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops
new file mode 100644
index 000000000..ae54939a9
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffDebugCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\ImageDiffWinCairoCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncher.vcproj b/Tools/DumpRenderTree/win/ImageDiffLauncher.vcproj
new file mode 100644
index 000000000..8ea7edf3c
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffLauncher.vcproj
@@ -0,0 +1,396 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffLauncher"
+ ProjectGUID="{DD7949B6-F2B4-47C2-9C42-E21E84CB1017}"
+ RootNamespace="ImageDiffLauncher"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\ImageDiffLauncherDebug.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\ImageDiffLauncherRelease.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_Cairo_CFLite|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\ImageDiffLauncherDebugCairoCFLite.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\ImageDiffLauncherDebugAll.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Production|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\ImageDiffLauncherProduction.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_Cairo_CFLite|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets=".\ImageDiffLauncherReleaseCairoCFLite.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\win\DLLLauncher\DLLLauncherMain.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherCommon.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherCommon.vsprops
new file mode 100644
index 000000000..bf1c4169d
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffLauncherCommon.vsprops
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffLauncherCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="USE_CONSOLE_ENTRY_POINT"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="shlwapi.lib"
+ OutputFile="$(OutDir)\ImageDiff$(WebKitConfigSuffix).exe"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName)Launcher.pdb"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherDebug.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherDebug.vsprops
new file mode 100644
index 000000000..aa8654551
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffLauncherDebug.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffLauncherDebug"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\ImageDiffLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherDebugAll.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherDebugAll.vsprops
new file mode 100644
index 000000000..685f356fe
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffLauncherDebugAll.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffLauncherDebugAll"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\ImageDiffLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherDebugCairoCFLite.vsprops
new file mode 100644
index 000000000..3f5dc5442
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffLauncherDebugCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffDebugCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherProduction.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherProduction.vsprops
new file mode 100644
index 000000000..457551023
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffLauncherProduction.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffLauncherProduction"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\ImageDiffLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherRelease.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherRelease.vsprops
new file mode 100644
index 000000000..57fb84732
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffLauncherRelease.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffLauncherRelease"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\ImageDiffLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffLauncherReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffLauncherReleaseCairoCFLite.vsprops
new file mode 100644
index 000000000..d5002e6d7
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffLauncherReleaseCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffLauncherReleaseCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\ImageDiffLauncherCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd b/Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd
new file mode 100644
index 000000000..26707cac6
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd
@@ -0,0 +1 @@
+if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed"
diff --git a/Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd b/Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd
new file mode 100644
index 000000000..a77077674
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd
@@ -0,0 +1,6 @@
+%SystemDrive%\cygwin\bin\which.exe bash
+if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
+cmd /c
+if exist "%CONFIGURATIONBUILDDIR%\buildfailed" grep XX%PROJECTNAME%XX "%CONFIGURATIONBUILDDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed"
diff --git a/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops b/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops
new file mode 100644
index 000000000..8e758b5cb
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffProduction"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops;.\ImageDiffCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops b/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops
new file mode 100644
index 000000000..acf3e525b
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffRelease"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\ImageDiffCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops
new file mode 100644
index 000000000..4125ff119
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffReleaseCairoCFLite"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\ImageDiffWinCairoCommon.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffWin.cpp b/Tools/DumpRenderTree/win/ImageDiffWin.cpp
new file mode 100644
index 000000000..01dfc0b99
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffWin.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 <windows.h>
+
+int main(int argc, const char* argv[]);
+
+extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
+{
+ return main(argc, argv);
+}
diff --git a/Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops b/Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops
new file mode 100644
index 000000000..5fa982a27
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ConfigurationBuildDir)\include&quot;;&quot;$(ConfigurationBuildDir)\include\private&quot;;&quot;$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitLibrariesDir)\include&quot;;&quot;$(WebKitLibrariesDir)\include\private&quot;"
+ PreprocessorDefinitions="NOMINMAX"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/NXCOMPAT"
+ AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib cairo$(LibraryConfigSuffix).lib libjpeg.lib libpng$(LibraryConfigSuffix).lib zdll.lib Msimg32.lib CFLite$(LibraryConfigSuffix).lib"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp b/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp
new file mode 100644
index 000000000..38c987760
--- /dev/null
+++ b/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp
@@ -0,0 +1,1563 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "LayoutTestController.h"
+
+#include "DumpRenderTree.h"
+#include "EditingDelegate.h"
+#include "PolicyDelegate.h"
+#include "WorkQueue.h"
+#include "WorkQueueItem.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <JavaScriptCore/Assertions.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRefBSTR.h>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <WebCore/COMPtr.h>
+#include <WebKit/WebKit.h>
+#include <WebKit/WebKitCOMAPI.h>
+#include <comutil.h>
+#include <shlwapi.h>
+#include <shlguid.h>
+#include <shobjidl.h>
+#include <string>
+#include <wtf/Platform.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+using std::string;
+using std::wstring;
+
+static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath);
+
+LayoutTestController::~LayoutTestController()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ // reset webview-related states back to default values in preparation for next test
+
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (SUCCEEDED(webView->QueryInterface(&viewPrivate)))
+ viewPrivate->setTabKeyCyclesThroughElements(TRUE);
+
+ COMPtr<IWebViewEditing> viewEditing;
+ if (FAILED(webView->QueryInterface(&viewEditing)))
+ return;
+ COMPtr<IWebEditingDelegate> delegate;
+ if (FAILED(viewEditing->editingDelegate(&delegate)))
+ return;
+ COMPtr<EditingDelegate> editingDelegate(Query, viewEditing.get());
+ if (editingDelegate)
+ editingDelegate->setAcceptsEditing(TRUE);
+}
+
+void LayoutTestController::addDisallowedURL(JSStringRef url)
+{
+ // FIXME: Implement!
+}
+
+void LayoutTestController::clearBackForwardList()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebBackForwardList> backForwardList;
+ if (FAILED(webView->backForwardList(&backForwardList)))
+ return;
+
+ COMPtr<IWebHistoryItem> item;
+ if (FAILED(backForwardList->currentItem(&item)))
+ return;
+
+ // We clear the history by setting the back/forward list's capacity to 0
+ // then restoring it back and adding back the current item.
+ int capacity;
+ if (FAILED(backForwardList->capacity(&capacity)))
+ return;
+
+ backForwardList->setCapacity(0);
+ backForwardList->setCapacity(capacity);
+ backForwardList->addItem(item.get());
+ backForwardList->goToItem(item.get());
+}
+
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return false;
+
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (FAILED(webView->QueryInterface(&viewPrivate)))
+ return false;
+
+ BOOL result;
+ viewPrivate->shouldClose(&result);
+ return result;
+}
+
+JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name)
+{
+ // FIXME: Implement!
+ return 0;
+}
+
+JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name)
+{
+ // FIXME: Implement!
+ return 0;
+}
+
+void LayoutTestController::disableImageLoading()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ preferences->setLoadsImagesAutomatically(FALSE);
+}
+
+void LayoutTestController::dispatchPendingLoadRequests()
+{
+ // FIXME: Implement for testing fix for 6727495
+}
+
+void LayoutTestController::display()
+{
+ displayWebView();
+}
+
+void LayoutTestController::keepWebHistory()
+{
+ COMPtr<IWebHistory> history;
+ if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
+ return;
+
+ COMPtr<IWebHistory> sharedHistory;
+ if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(sharedHistory), reinterpret_cast<void**>(&sharedHistory))))
+ return;
+
+ history->setOptionalSharedHistory(sharedHistory.get());
+}
+
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value)
+{
+ // FIXME: Implement this.
+ return JSValueMakeUndefined(context);
+}
+
+JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping)
+{
+ // FIXME: Implement this.
+ return JSValueMakeUndefined(context);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return false;
+
+ BSTR textBSTR = 0;
+ HRESULT hr = framePrivate->layerTreeAsText(&textBSTR);
+
+ wstring text(textBSTR, SysStringLen(textBSTR));
+ SysFreeString(textBSTR);
+ JSRetainPtr<JSStringRef> textValueJS(Adopt, JSStringCreateWithCharacters(text.data(), text.length()));
+ return textValueJS;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return 0;
+
+ COMPtr<IWebViewPrivate> webViewPrivate(Query, webView);
+ if (!webViewPrivate)
+ return 0;
+
+ COMPtr<IDOMElement> element;
+ if (FAILED(webViewPrivate->elementFromJS(context, nodeObject, &element)))
+ return 0;
+
+ COMPtr<IDOMElementPrivate> elementPrivate(Query, element);
+ if (!elementPrivate)
+ return 0;
+
+ BSTR textBSTR = 0;
+ if (FAILED(elementPrivate->markerTextForListItem(&textBSTR)))
+ return 0;
+
+ JSRetainPtr<JSStringRef> markerText(Adopt, JSStringCreateWithBSTR(textBSTR));
+ SysFreeString(textBSTR);
+ return markerText;
+}
+
+void LayoutTestController::waitForPolicyDelegate()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ setWaitToDump(true);
+ policyDelegate->setControllerToNotifyDone(this);
+ webView->setPolicyDelegate(policyDelegate);
+}
+
+size_t LayoutTestController::webHistoryItemCount()
+{
+ COMPtr<IWebHistory> history;
+ if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
+ return 0;
+
+ COMPtr<IWebHistory> sharedHistory;
+ if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory)
+ return 0;
+
+ COMPtr<IWebHistoryPrivate> sharedHistoryPrivate;
+ if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate)))
+ return 0;
+
+ int count;
+ if (FAILED(sharedHistoryPrivate->allItems(&count, 0)))
+ return 0;
+
+ return count;
+}
+
+unsigned LayoutTestController::workerThreadCount() const
+{
+ COMPtr<IWebWorkersPrivate> workers;
+ if (FAILED(WebKitCreateInstance(CLSID_WebWorkersPrivate, 0, __uuidof(workers), reinterpret_cast<void**>(&workers))))
+ return 0;
+ unsigned count;
+ if (FAILED(workers->workerThreadCount(&count)))
+ return 0;
+ return count;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::platformName() const
+{
+ JSRetainPtr<JSStringRef> platformName(Adopt, JSStringCreateWithUTF8CString("win"));
+ return platformName;
+}
+
+void LayoutTestController::notifyDone()
+{
+ // Same as on mac. This can be shared.
+ if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
+ dump();
+ m_waitToDump = false;
+}
+
+JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url)
+{
+ wstring input(JSStringGetCharactersPtr(url), JSStringGetLength(url));
+
+ wstring localPath;
+ if (!resolveCygwinPath(input, localPath)) {
+ printf("ERROR: Failed to resolve Cygwin path %S\n", input.c_str());
+ return 0;
+ }
+
+ return JSStringCreateWithCharacters(localPath.c_str(), localPath.length());
+}
+
+static wstring jsStringRefToWString(JSStringRef jsStr)
+{
+ size_t length = JSStringGetLength(jsStr);
+ Vector<WCHAR> buffer(length + 1);
+ memcpy(buffer.data(), JSStringGetCharactersPtr(jsStr), length * sizeof(WCHAR));
+ buffer[length] = '\0';
+
+ return buffer.data();
+}
+
+void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target)
+{
+ COMPtr<IWebDataSource> dataSource;
+ if (FAILED(frame->dataSource(&dataSource)))
+ return;
+
+ COMPtr<IWebURLResponse> response;
+ if (FAILED(dataSource->response(&response)) || !response)
+ return;
+
+ BSTR responseURLBSTR;
+ if (FAILED(response->URL(&responseURLBSTR)))
+ return;
+ wstring responseURL(responseURLBSTR, SysStringLen(responseURLBSTR));
+ SysFreeString(responseURLBSTR);
+
+ // FIXME: We should do real relative URL resolution here.
+ int lastSlash = responseURL.rfind('/');
+ if (lastSlash != -1)
+ responseURL = responseURL.substr(0, lastSlash);
+
+ wstring wURL = jsStringRefToWString(url);
+ wstring wAbsoluteURL = responseURL + TEXT("/") + wURL;
+ JSRetainPtr<JSStringRef> jsAbsoluteURL(Adopt, JSStringCreateWithCharacters(wAbsoluteURL.data(), wAbsoluteURL.length()));
+
+ WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target));
+}
+
+void LayoutTestController::setAcceptsEditing(bool acceptsEditing)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewEditing> viewEditing;
+ if (FAILED(webView->QueryInterface(&viewEditing)))
+ return;
+
+ COMPtr<IWebEditingDelegate> delegate;
+ if (FAILED(viewEditing->editingDelegate(&delegate)))
+ return;
+
+ EditingDelegate* editingDelegate = (EditingDelegate*)(IWebEditingDelegate*)delegate.get();
+ editingDelegate->setAcceptsEditing(acceptsEditing);
+}
+
+void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
+{
+ if (alwaysAcceptCookies == m_alwaysAcceptCookies)
+ return;
+
+ if (!::setAlwaysAcceptCookies(alwaysAcceptCookies))
+ return;
+ m_alwaysAcceptCookies = alwaysAcceptCookies;
+}
+
+void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (!prefsPrivate)
+ return;
+
+ prefsPrivate->setAuthorAndUserStylesEnabled(flag);
+}
+
+void LayoutTestController::setAutofilled(JSContextRef context, JSValueRef nodeObject, bool autofilled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> webViewPrivate(Query, webView);
+ if (!webViewPrivate)
+ return;
+
+ COMPtr<IDOMElement> element;
+ if (FAILED(webViewPrivate->elementFromJS(context, nodeObject, &element)))
+ return;
+
+ COMPtr<IFormsAutoFillTransition> autofillElement(Query, element);
+ if (!autofillElement)
+ return;
+
+ autofillElement->setAutofilled(autofilled);
+}
+
+void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ if (setDelegate) {
+ policyDelegate->setPermissive(permissive);
+ webView->setPolicyDelegate(policyDelegate);
+ } else
+ webView->setPolicyDelegate(0);
+}
+
+void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
+{
+ // FIXME: Implement for DeviceOrientation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=30335.
+}
+
+void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
+{
+ // FIXME: Implement for Geolocation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=28264.
+}
+
+void LayoutTestController::setMockGeolocationError(int code, JSStringRef message)
+{
+ // FIXME: Implement for Geolocation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=28264.
+}
+
+void LayoutTestController::setGeolocationPermission(bool allow)
+{
+ // FIXME: Implement for Geolocation layout tests.
+ setGeolocationPermissionCommon(allow);
+}
+
+int LayoutTestController::numberOfPendingGeolocationPermissionRequests()
+{
+ // FIXME: Implement for Geolocation layout tests.
+ return -1;
+}
+
+void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::startSpeechInput(JSContextRef inputElement)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled)
+{
+ // See also <rdar://problem/6480108>
+ COMPtr<IWebIconDatabase> iconDatabase;
+ COMPtr<IWebIconDatabase> tmpIconDatabase;
+ if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
+ return;
+ if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
+ return;
+
+ iconDatabase->setEnabled(iconDatabaseEnabled);
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
+{
+ // FIXME: Implement!
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ preferences->setPrivateBrowsingEnabled(privateBrowsingEnabled);
+}
+
+void LayoutTestController::setXSSAuditorEnabled(bool enabled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (!prefsPrivate)
+ return;
+
+ prefsPrivate->setXSSAuditorEnabled(enabled);
+}
+
+void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (!prefsPrivate)
+ return;
+
+ prefsPrivate->setFrameFlatteningEnabled(enabled);
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool enabled)
+{
+ // FIXME: Implement for SpatialNavigation layout tests.
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (!prefsPrivate)
+ return;
+
+ prefsPrivate->setAllowUniversalAccessFromFileURLs(enabled);
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (!prefsPrivate)
+ return;
+
+ prefsPrivate->setAllowFileAccessFromFileURLs(enabled);
+}
+
+void LayoutTestController::setPopupBlockingEnabled(bool enabled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ preferences->setJavaScriptCanOpenWindowsAutomatically(!enabled);
+}
+
+void LayoutTestController::setPluginsEnabled(bool flag)
+{
+ // FIXME: Implement
+}
+
+void LayoutTestController::setJavaScriptCanAccessClipboard(bool enabled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (!prefsPrivate)
+ return;
+
+ prefsPrivate->setJavaScriptCanAccessClipboard(enabled);
+}
+
+void LayoutTestController::setTabKeyCyclesThroughElements(bool shouldCycle)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (FAILED(webView->QueryInterface(&viewPrivate)))
+ return;
+
+ viewPrivate->setTabKeyCyclesThroughElements(shouldCycle ? TRUE : FALSE);
+}
+
+void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
+{
+ // FIXME: Implement!
+}
+
+void LayoutTestController::setUserStyleSheetEnabled(bool flag)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ preferences->setUserStyleSheetEnabled(flag);
+}
+
+bool appendComponentToPath(wstring& path, const wstring& component)
+{
+ WCHAR buffer[MAX_PATH];
+
+ if (path.size() + 1 > MAX_PATH)
+ return false;
+
+ memcpy(buffer, path.data(), path.size() * sizeof(WCHAR));
+ buffer[path.size()] = '\0';
+
+ if (!PathAppendW(buffer, component.c_str()))
+ return false;
+
+ path = wstring(buffer);
+ return true;
+}
+
+static bool followShortcuts(wstring& path)
+{
+ if (PathFileExists(path.c_str()))
+ return true;
+
+ // Do we have a shortcut?
+ wstring linkPath = path;
+ linkPath.append(TEXT(".lnk"));
+ if (!PathFileExists(linkPath.c_str()))
+ return true;
+
+ // We have a shortcut, find its target.
+ COMPtr<IShellLink> shortcut(Create, CLSID_ShellLink);
+ if (!shortcut)
+ return false;
+ COMPtr<IPersistFile> persistFile(Query, shortcut);
+ if (!shortcut)
+ return false;
+ if (FAILED(persistFile->Load(linkPath.c_str(), STGM_READ)))
+ return false;
+ if (FAILED(shortcut->Resolve(0, 0)))
+ return false;
+ WCHAR targetPath[MAX_PATH];
+ DWORD targetPathLen = _countof(targetPath);
+ if (FAILED(shortcut->GetPath(targetPath, targetPathLen, 0, 0)))
+ return false;
+ if (!PathFileExists(targetPath))
+ return false;
+ // Use the target path as the result path instead.
+ path = wstring(targetPath);
+
+ return true;
+}
+
+static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath)
+{
+ wstring fileProtocol = L"file://";
+ bool isFileProtocol = cygwinPath.find(fileProtocol) != string::npos;
+ if (cygwinPath[isFileProtocol ? 7 : 0] != '/') // ensure path is absolute
+ return false;
+
+ // Get the Root path.
+ WCHAR rootPath[MAX_PATH];
+ DWORD rootPathSize = _countof(rootPath);
+ DWORD keyType;
+ DWORD result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/"), TEXT("native"), &keyType, &rootPath, &rootPathSize);
+
+ if (result != ERROR_SUCCESS || keyType != REG_SZ) {
+ // Cygwin 1.7 doesn't store Cygwin's root as a mount point anymore, because mount points are now stored in /etc/fstab.
+ // However, /etc/fstab doesn't contain any information about where / is located as a Windows path, so we need to use Cygwin's
+ // new registry key that has the root.
+ result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygwin\\setup"), TEXT("rootdir"), &keyType, &rootPath, &rootPathSize);
+ if (result != ERROR_SUCCESS || keyType != REG_SZ)
+ return false;
+ }
+
+ windowsPath = wstring(rootPath, rootPathSize);
+
+ int oldPos = isFileProtocol ? 8 : 1;
+ while (1) {
+ int newPos = cygwinPath.find('/', oldPos);
+
+ if (newPos == -1) {
+ wstring pathComponent = cygwinPath.substr(oldPos);
+
+ if (!appendComponentToPath(windowsPath, pathComponent))
+ return false;
+
+ if (!followShortcuts(windowsPath))
+ return false;
+
+ break;
+ }
+
+ wstring pathComponent = cygwinPath.substr(oldPos, newPos - oldPos);
+ if (!appendComponentToPath(windowsPath, pathComponent))
+ return false;
+
+ if (!followShortcuts(windowsPath))
+ return false;
+
+ oldPos = newPos + 1;
+ }
+
+ if (isFileProtocol)
+ windowsPath = fileProtocol + windowsPath;
+
+ return true;
+}
+
+void LayoutTestController::setUserStyleSheetLocation(JSStringRef jsURL)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL));
+ RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithString(0, urlString.get(), 0));
+ if (!url)
+ return;
+
+ // Now copy the file system path, POSIX style.
+ RetainPtr<CFStringRef> pathCF(AdoptCF, CFURLCopyFileSystemPath(url.get(), kCFURLPOSIXPathStyle));
+ if (!pathCF)
+ return;
+
+ wstring path = cfStringRefToWString(pathCF.get());
+
+ wstring resultPath;
+ if (!resolveCygwinPath(path, resultPath))
+ return;
+
+ // The path has been resolved, now convert it back to a CFURL.
+ int result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, 0, 0, 0, 0);
+ Vector<char> utf8Vector(result);
+ result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, utf8Vector.data(), result, 0, 0);
+ if (!result)
+ return;
+
+ url = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)utf8Vector.data(), utf8Vector.size() - 1, false);
+ if (!url)
+ return;
+
+ resultPath = cfStringRefToWString(CFURLGetString(url.get()));
+
+ BSTR resultPathBSTR = SysAllocStringLen(resultPath.data(), resultPath.size());
+ preferences->setUserStyleSheetLocation(resultPathBSTR);
+ SysFreeString(resultPathBSTR);
+}
+
+void LayoutTestController::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setViewModeMediaFeature(JSStringRef mode)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
+{
+ RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL));
+ ::setPersistentUserStyleSheetLocation(urlString.get());
+}
+
+void LayoutTestController::clearPersistentUserStyleSheet()
+{
+ ::setPersistentUserStyleSheetLocation(0);
+}
+
+void LayoutTestController::setWindowIsKey(bool flag)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (FAILED(webView->QueryInterface(&viewPrivate)))
+ return;
+
+ HWND webViewWindow;
+ if (FAILED(viewPrivate->viewWindow((OLE_HANDLE*)&webViewWindow)))
+ return;
+
+ ::SendMessage(webViewWindow, flag ? WM_SETFOCUS : WM_KILLFOCUS, (WPARAM)::GetDesktopWindow(), 0);
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(bool flag)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewEditing> viewEditing;
+ if (FAILED(webView->QueryInterface(&viewEditing)))
+ return;
+
+ viewEditing->setSmartInsertDeleteEnabled(flag ? TRUE : FALSE);
+}
+
+void LayoutTestController::setJavaScriptProfilingEnabled(bool flag)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (FAILED(webView->QueryInterface(&viewPrivate)))
+ return;
+
+ COMPtr<IWebInspector> inspector;
+ if (FAILED(viewPrivate->inspector(&inspector)))
+ return;
+
+ setDeveloperExtrasEnabled(flag);
+ inspector->setJavaScriptProfilingEnabled(flag);
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewEditing> viewEditing;
+ if (FAILED(webView->QueryInterface(&viewEditing)))
+ return;
+
+ viewEditing->setSelectTrailingWhitespaceEnabled(flag ? TRUE : FALSE);
+}
+
+static const CFTimeInterval waitToDumpWatchdogInterval = 30.0;
+
+static void CALLBACK waitUntilDoneWatchdogFired(HWND, UINT, UINT_PTR, DWORD)
+{
+ gLayoutTestController->waitToDumpWatchdogTimerFired();
+}
+
+void LayoutTestController::setWaitToDump(bool waitUntilDone)
+{
+ m_waitToDump = waitUntilDone;
+ if (m_waitToDump && !waitToDumpWatchdog)
+ waitToDumpWatchdog = SetTimer(0, 0, waitToDumpWatchdogInterval * 1000, waitUntilDoneWatchdogFired);
+}
+
+int LayoutTestController::windowCount()
+{
+ return openWindows().size();
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef id)
+{
+ COMPtr<IDOMDocument> document;
+ if (FAILED(frame->DOMDocument(&document)))
+ return false;
+
+ wstring idWstring = jsStringRefToWString(id);
+ BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length());
+ COMPtr<IDOMElement> element;
+ HRESULT result = document->getElementById(idBSTR, &element);
+ SysFreeString(idBSTR);
+
+ if (FAILED(result))
+ return false;
+
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return false;
+
+ BOOL autoCompletes;
+ if (FAILED(framePrivate->elementDoesAutoComplete(element.get(), &autoCompletes)))
+ return false;
+
+ return autoCompletes;
+}
+
+void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
+{
+ wstring wName = jsStringRefToWString(name);
+ wstring wValue = jsStringRefToWString(value);
+
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (FAILED(webView->QueryInterface(&viewPrivate)))
+ return;
+
+ BSTR nameBSTR = SysAllocStringLen((OLECHAR*)wName.c_str(), wName.length());
+ BSTR valueBSTR = SysAllocStringLen((OLECHAR*)wValue.c_str(), wValue.length());
+ viewPrivate->executeCoreCommandByName(nameBSTR, valueBSTR);
+
+ SysFreeString(nameBSTR);
+ SysFreeString(valueBSTR);
+}
+
+bool LayoutTestController::findString(JSContextRef /* context */, JSStringRef /* target */, JSObjectRef /* optionsArray */)
+{
+ // FIXME: Implement
+ return false;
+}
+
+void LayoutTestController::setCacheModel(int)
+{
+ // FIXME: Implement
+}
+
+bool LayoutTestController::isCommandEnabled(JSStringRef /*name*/)
+{
+ printf("ERROR: LayoutTestController::isCommandEnabled() not implemented\n");
+ return false;
+}
+
+void LayoutTestController::clearAllApplicationCaches()
+{
+ // FIXME: Implement to support application cache quotas.
+}
+
+void LayoutTestController::clearApplicationCacheForOrigin(JSStringRef origin)
+{
+ // FIXME: Implement to support deleting all application cache for an origin.
+}
+
+void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota)
+{
+ // FIXME: Implement to support application cache quotas.
+}
+
+JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context)
+{
+ // FIXME: Implement to get origins that have application caches.
+ return JSValueMakeUndefined(context);
+}
+
+long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef name)
+{
+ // FIXME: Implement to get disk usage by all application caches for an origin.
+ return 0;
+}
+
+void LayoutTestController::clearAllDatabases()
+{
+ COMPtr<IWebDatabaseManager> databaseManager;
+ COMPtr<IWebDatabaseManager> tmpDatabaseManager;
+ if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager)))
+ return;
+ if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager)))
+ return;
+
+ databaseManager->deleteAllDatabases();
+}
+
+void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (!prefsPrivate)
+ return;
+
+ BSTR keyBSTR = JSStringCopyBSTR(key);
+ BSTR valueBSTR = JSStringCopyBSTR(value);
+ prefsPrivate->setPreferenceForTest(keyBSTR, valueBSTR);
+ SysFreeString(keyBSTR);
+ SysFreeString(valueBSTR);
+}
+
+void LayoutTestController::setDatabaseQuota(unsigned long long quota)
+{
+ COMPtr<IWebDatabaseManager> databaseManager;
+ COMPtr<IWebDatabaseManager> tmpDatabaseManager;
+
+ if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager)))
+ return;
+ if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager)))
+ return;
+
+ databaseManager->setQuota(TEXT("file:///"), quota);
+}
+
+void LayoutTestController::goBack()
+{
+ // FIXME: implement to enable loader/navigation-while-deferring-loads.html
+}
+
+void LayoutTestController::setDefersLoading(bool)
+{
+ // FIXME: implement to enable loader/navigation-while-deferring-loads.html
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme)
+{
+ COMPtr<IWebViewPrivate> webView;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
+ return;
+
+ BSTR schemeBSTR = JSStringCopyBSTR(scheme);
+ webView->setDomainRelaxationForbiddenForURLScheme(forbidden, schemeBSTR);
+ SysFreeString(schemeBSTR);
+}
+
+void LayoutTestController::setAppCacheMaximumSize(unsigned long long size)
+{
+ printf("ERROR: LayoutTestController::setAppCacheMaximumSize() not implemented\n");
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
+{
+ COMPtr<IDOMDocument> document;
+ if (FAILED(frame->DOMDocument(&document)))
+ return false;
+
+ BSTR idBSTR = JSStringCopyBSTR(elementId);
+ COMPtr<IDOMElement> element;
+ HRESULT hr = document->getElementById(idBSTR, &element);
+ SysFreeString(idBSTR);
+ if (FAILED(hr))
+ return false;
+
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return false;
+
+ BSTR nameBSTR = JSStringCopyBSTR(animationName);
+ BOOL wasRunning = FALSE;
+ hr = framePrivate->pauseAnimation(nameBSTR, element.get(), time, &wasRunning);
+ SysFreeString(nameBSTR);
+
+ return SUCCEEDED(hr) && wasRunning;
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId)
+{
+ COMPtr<IDOMDocument> document;
+ if (FAILED(frame->DOMDocument(&document)))
+ return false;
+
+ BSTR idBSTR = JSStringCopyBSTR(elementId);
+ COMPtr<IDOMElement> element;
+ HRESULT hr = document->getElementById(idBSTR, &element);
+ SysFreeString(idBSTR);
+ if (FAILED(hr))
+ return false;
+
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return false;
+
+ BSTR nameBSTR = JSStringCopyBSTR(propertyName);
+ BOOL wasRunning = FALSE;
+ hr = framePrivate->pauseTransition(nameBSTR, element.get(), time, &wasRunning);
+ SysFreeString(nameBSTR);
+
+ return SUCCEEDED(hr) && wasRunning;
+}
+
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
+{
+ COMPtr<IDOMDocument> document;
+ if (FAILED(frame->DOMDocument(&document)))
+ return false;
+
+ BSTR idBSTR = JSStringCopyBSTR(animationId);
+ COMPtr<IDOMElement> element;
+ HRESULT hr = document->getElementById(idBSTR, &element);
+ SysFreeString(idBSTR);
+ if (FAILED(hr))
+ return false;
+
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return false;
+
+ BSTR elementIdBSTR = JSStringCopyBSTR(elementId);
+ BOOL wasRunning = FALSE;
+ hr = framePrivate->pauseSVGAnimation(elementIdBSTR, element.get(), time, &wasRunning);
+ SysFreeString(elementIdBSTR);
+
+ return SUCCEEDED(hr) && wasRunning;
+}
+
+unsigned LayoutTestController::numberOfActiveAnimations() const
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return 0;
+
+ UINT number = 0;
+ if (FAILED(framePrivate->numberOfActiveAnimations(&number)))
+ return 0;
+
+ return number;
+}
+
+void LayoutTestController::suspendAnimations() const
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return;
+
+ framePrivate->suspendAnimations();
+}
+
+void LayoutTestController::resumeAnimations() const
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return;
+
+ framePrivate->resumeAnimations();
+}
+
+static _bstr_t bstrT(JSStringRef jsString)
+{
+ // The false parameter tells the _bstr_t constructor to adopt the BSTR we pass it.
+ return _bstr_t(JSStringCopyBSTR(jsString), false);
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+ COMPtr<IWebViewPrivate> webView;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
+ return;
+
+ webView->addOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+ COMPtr<IWebViewPrivate> webView;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
+ return;
+
+ webView->removeOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
+}
+
+void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
+{
+ COMPtr<IWebViewPrivate> webView;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
+ return;
+
+ COMPtr<IWebScriptWorld> world;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
+ return;
+
+ webView->addUserScriptToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0, runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd);
+}
+
+
+void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames)
+{
+ COMPtr<IWebViewPrivate> webView;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
+ return;
+
+ COMPtr<IWebScriptWorld> world;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
+ return;
+
+ webView->addUserStyleSheetToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0);
+}
+
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (!prefsPrivate)
+ return;
+
+ prefsPrivate->setDeveloperExtrasEnabled(enabled);
+}
+
+void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool)
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::showWebInspector()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
+ if (!viewPrivate)
+ return;
+
+ COMPtr<IWebInspector> inspector;
+ if (SUCCEEDED(viewPrivate->inspector(&inspector)))
+ inspector->show();
+}
+
+void LayoutTestController::closeWebInspector()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
+ if (!viewPrivate)
+ return;
+
+ COMPtr<IWebInspector> inspector;
+ if (FAILED(viewPrivate->inspector(&inspector)))
+ return;
+
+ inspector->close();
+}
+
+void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
+ if (!viewPrivate)
+ return;
+
+ COMPtr<IWebInspector> inspector;
+ if (FAILED(viewPrivate->inspector(&inspector)))
+ return;
+
+ COMPtr<IWebInspectorPrivate> inspectorPrivate(Query, inspector);
+ if (!inspectorPrivate)
+ return;
+
+ inspectorPrivate->evaluateInFrontend(callId, bstrT(script).GetBSTR());
+}
+
+typedef HashMap<unsigned, COMPtr<IWebScriptWorld> > WorldMap;
+static WorldMap& worldMap()
+{
+ static WorldMap& map = *new WorldMap;
+ return map;
+}
+
+unsigned worldIDForWorld(IWebScriptWorld* world)
+{
+ WorldMap::const_iterator end = worldMap().end();
+ for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
+ if (it->second == world)
+ return it->first;
+ }
+
+ return 0;
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return;
+
+ // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
+ // that is created once and cached forever.
+ COMPtr<IWebScriptWorld> world;
+ if (!worldID) {
+ if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
+ return;
+ } else {
+ COMPtr<IWebScriptWorld>& worldSlot = worldMap().add(worldID, 0).first->second;
+ if (!worldSlot && FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(worldSlot), reinterpret_cast<void**>(&worldSlot))))
+ return;
+ world = worldSlot;
+ }
+
+ BSTR result;
+ if (FAILED(framePrivate->stringByEvaluatingJavaScriptInScriptWorld(world.get(), globalObject, bstrT(script).GetBSTR(), &result)))
+ return;
+ SysFreeString(result);
+}
+
+void LayoutTestController::removeAllVisitedLinks()
+{
+ COMPtr<IWebHistory> history;
+ if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
+ return;
+
+ COMPtr<IWebHistory> sharedHistory;
+ if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory)
+ return;
+
+ COMPtr<IWebHistoryPrivate> sharedHistoryPrivate;
+ if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate)))
+ return;
+
+ sharedHistoryPrivate->removeAllVisitedLinks();
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id)
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return 0;
+
+ wstring idWstring = jsStringRefToWString(id);
+ BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length());
+ BSTR counterValueBSTR;
+ if (FAILED(framePrivate->counterValueForElementById(idBSTR, &counterValueBSTR)))
+ return 0;
+
+ wstring counterValue(counterValueBSTR, SysStringLen(counterValueBSTR));
+ SysFreeString(idBSTR);
+ SysFreeString(counterValueBSTR);
+ JSRetainPtr<JSStringRef> counterValueJS(Adopt, JSStringCreateWithCharacters(counterValue.data(), counterValue.length()));
+ return counterValueJS;
+}
+
+int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels)
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return 0;
+
+ wstring idWstring = jsStringRefToWString(id);
+ BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length());
+ int pageNumber = -1;
+ if (FAILED(framePrivate->pageNumberForElementById(idBSTR, pageWidthInPixels, pageHeightInPixels, &pageNumber)))
+ pageNumber = -1;
+ SysFreeString(idBSTR);
+ return pageNumber;
+}
+
+int LayoutTestController::numberOfPages(float pageWidthInPixels, float pageHeightInPixels)
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return 0;
+
+ int pageNumber = -1;
+ if (FAILED(framePrivate->numberOfPages(pageWidthInPixels, pageHeightInPixels, &pageNumber)))
+ pageNumber = -1;
+ return pageNumber;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const
+{
+ // FIXME: Implement this.
+ return JSRetainPtr<JSStringRef>();
+}
+
+void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL)
+{
+
+}
+
+bool LayoutTestController::isPageBoxVisible(int pageNumber) const
+{
+ // FIXME: implement
+ return false;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const
+{
+ // FIXME: implement
+ return JSRetainPtr<JSStringRef>();
+}
+
+void LayoutTestController::apiTestGoToCurrentBackForwardItem()
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebBackForwardList> backForwardList;
+ if (FAILED(webView->backForwardList(&backForwardList)))
+ return;
+
+ COMPtr<IWebHistoryItem> item;
+ if (FAILED(backForwardList->currentItem(&item)))
+ return;
+
+ BOOL success;
+ webView->goToBackForwardItem(item.get(), &success);
+}
+
+void LayoutTestController::setWebViewEditable(bool)
+{
+}
+
+void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
+{
+}
+
+void LayoutTestController::setEditingBehavior(const char* editingBehavior)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ string behaviorString(editingBehavior);
+ if (behaviorString == "mac")
+ preferences->setEditingBehavior(WebKitEditingMacBehavior);
+ else if (behaviorString == "win")
+ preferences->setEditingBehavior(WebKitEditingWinBehavior);
+ else if (behaviorString == "unix")
+ preferences->setEditingBehavior(WebKitEditingUnixBehavior);
+}
+
+void LayoutTestController::abortModal()
+{
+}
+
+bool LayoutTestController::hasSpellingMarker(int from, int length)
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return false;
+ BOOL ret = FALSE;
+ if (FAILED(framePrivate->hasSpellingMarker(from, length, &ret)))
+ return false;
+ return ret;
+}
+
+bool LayoutTestController::hasGrammarMarker(int from, int length)
+{
+ // FIXME: Implement this.
+ return false;
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int /*deviceDPI*/, int /*deviceWidth*/, int /*deviceHeight*/, int /*availableWidth*/, int /*availableHeight*/)
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::setSerializeHTTPLoads(bool)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::syncLocalStorage()
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::observeStorageTrackerNotifications(unsigned number)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::deleteAllLocalStorage()
+{
+ // FIXME: Implement.
+}
+
+JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context)
+{
+ // FIXME: Implement.
+ return JSValueMakeUndefined(context);
+}
+
+long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef originIdentifier)
+{
+ // FIXME: Implement to support getting local storage disk usage for an origin.
+ return 0;
+}
+
+void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef URL)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::setMinimumTimerInterval(double minimumTimerInterval)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
+ if (!viewPrivate)
+ return;
+
+ viewPrivate->setMinimumTimerInterval(minimumTimerInterval);
+}
+
+void LayoutTestController::setTextDirection(JSStringRef direction)
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return;
+
+ framePrivate->setTextDirection(bstrT(direction).GetBSTR());
+}
+
+void LayoutTestController::allowRoundingHacks()
+{
+}
+
+void LayoutTestController::addChromeInputField()
+{
+}
+
+void LayoutTestController::removeChromeInputField()
+{
+}
+
+void LayoutTestController::focusWebView()
+{
+}
+
+void LayoutTestController::setBackingScaleFactor(double)
+{
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title)
+{
+ // FIXME: Implement.
+}
diff --git a/Tools/DumpRenderTree/win/MD5.cpp b/Tools/DumpRenderTree/win/MD5.cpp
new file mode 100644
index 000000000..1bfc9c75f
--- /dev/null
+++ b/Tools/DumpRenderTree/win/MD5.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 Apple, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "MD5.h"
+
+#include <windows.h>
+
+typedef void (WINAPI*initPtr)(MD5_CTX*);
+typedef void (WINAPI*updatePtr)(MD5_CTX*, unsigned char*, unsigned);
+typedef void (WINAPI*finalPtr)(MD5_CTX*);
+
+static HMODULE cryptDLL()
+{
+ static HMODULE module = LoadLibraryW(L"Cryptdll.dll");
+ return module;
+}
+
+static initPtr init()
+{
+ static initPtr ptr = reinterpret_cast<initPtr>(GetProcAddress(cryptDLL(), "MD5Init"));
+ return ptr;
+}
+
+static updatePtr update()
+{
+ static updatePtr ptr = reinterpret_cast<updatePtr>(GetProcAddress(cryptDLL(), "MD5Update"));
+ return ptr;
+}
+
+static finalPtr final()
+{
+ static finalPtr ptr = reinterpret_cast<finalPtr>(GetProcAddress(cryptDLL(), "MD5Final"));
+ return ptr;
+}
+
+void MD5_Init(MD5_CTX* context)
+{
+ init()(context);
+}
+
+void MD5_Update(MD5_CTX* context, unsigned char* input, unsigned length)
+{
+ update()(context, input, length);
+}
+
+void MD5_Final(unsigned char hash[16], MD5_CTX* context)
+{
+ final()(context);
+
+ for (int i = 0; i < 16; ++i)
+ hash[i] = context->digest[i];
+}
diff --git a/Tools/DumpRenderTree/win/MD5.h b/Tools/DumpRenderTree/win/MD5.h
new file mode 100644
index 000000000..326e21d3e
--- /dev/null
+++ b/Tools/DumpRenderTree/win/MD5.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2007 Apple, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 MD5_h
+#define MD5_h
+
+typedef unsigned long ULONG;
+
+struct MD5_CTX {
+ ULONG i[2];
+ ULONG buf[4];
+ unsigned char in[64];
+ unsigned char digest[16];
+};
+
+void MD5_Init(MD5_CTX*);
+void MD5_Update(MD5_CTX*, unsigned char* input, unsigned length);
+void MD5_Final(unsigned char hash[16], MD5_CTX*);
+
+#endif // MD5_h
diff --git a/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp b/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp
new file mode 100644
index 000000000..10ca5163f
--- /dev/null
+++ b/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 Apple, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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"
+
+#if USE(CG)
+#include "PixelDumpSupportCG.h"
+#elif USE(CAIRO)
+#include "PixelDumpSupportCairo.h"
+#endif
+
+#include "DumpRenderTree.h"
+
+#if USE(CG)
+// Note: Must be included *after* DumpRenderTree.h to avoid compile error.
+#include <CoreGraphics/CGBitmapContext.h>
+#endif
+
+#include <wtf/Assertions.h>
+#include <wtf/RetainPtr.h>
+
+static void makeAlphaChannelOpaque(void* argbBits, LONG width, LONG height)
+{
+ unsigned* pixel = static_cast<unsigned*>(argbBits);
+ for (LONG row = 0; row < height; ++row) {
+ for (LONG column = 0; column < width; ++column)
+ *pixel++ |= 0xff000000;
+ }
+}
+
+PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect)
+{
+ RECT frame;
+ if (!GetWindowRect(webViewWindow, &frame))
+ return 0;
+
+ BITMAPINFO bmp = {0};
+ bmp.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmp.bmiHeader.biWidth = frame.right - frame.left;
+ bmp.bmiHeader.biHeight = -(frame.bottom - frame.top);
+ bmp.bmiHeader.biPlanes = 1;
+ bmp.bmiHeader.biBitCount = 32;
+ bmp.bmiHeader.biCompression = BI_RGB;
+
+ void* bits = 0;
+ HBITMAP bitmap = CreateDIBSection(0, &bmp, DIB_RGB_COLORS, &bits, 0, 0);
+
+ HDC memoryDC = CreateCompatibleDC(0);
+ SelectObject(memoryDC, bitmap);
+ SendMessage(webViewWindow, WM_PRINT, reinterpret_cast<WPARAM>(memoryDC), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED);
+ DeleteDC(memoryDC);
+
+ BITMAP info = {0};
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ // We create a context that has an alpha channel below so that the PNGs we generate will also
+ // have an alpha channel. But WM_PRINT doesn't necessarily write anything into the alpha
+ // channel, so we set the alpha channel to constant full opacity to make sure the resulting image is opaque.
+ makeAlphaChannelOpaque(info.bmBits, info.bmWidth, info.bmHeight);
+
+#if USE(CG)
+ RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, colorSpace.get(), kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
+#elif USE(CAIRO)
+ cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, CAIRO_FORMAT_ARGB32,
+ info.bmWidth, info.bmHeight, info.bmWidthBytes);
+ cairo_t* context = cairo_create(image);
+ cairo_surface_destroy(image);
+#endif
+
+ return BitmapContext::createByAdoptingBitmapAndContext(bitmap, context);
+}
diff --git a/Tools/DumpRenderTree/win/PolicyDelegate.cpp b/Tools/DumpRenderTree/win/PolicyDelegate.cpp
new file mode 100644
index 000000000..7d87c4539
--- /dev/null
+++ b/Tools/DumpRenderTree/win/PolicyDelegate.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "PolicyDelegate.h"
+
+#include "DumpRenderTree.h"
+#include "LayoutTestController.h"
+#include <string>
+
+using std::wstring;
+
+static wstring dumpPath(IDOMNode* node)
+{
+ ASSERT(node);
+
+ wstring result;
+
+ BSTR name;
+ if (FAILED(node->nodeName(&name)))
+ return result;
+ result.assign(name, SysStringLen(name));
+ SysFreeString(name);
+
+ COMPtr<IDOMNode> parent;
+ if (SUCCEEDED(node->parentNode(&parent)))
+ result += TEXT(" > ") + dumpPath(parent.get());
+
+ return result;
+}
+
+PolicyDelegate::PolicyDelegate()
+ : m_refCount(1)
+ , m_permissiveDelegate(false)
+ , m_controllerToNotifyDone(0)
+{
+}
+
+// IUnknown
+HRESULT STDMETHODCALLTYPE PolicyDelegate::QueryInterface(REFIID riid, void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IsEqualGUID(riid, IID_IUnknown))
+ *ppvObject = static_cast<IWebPolicyDelegate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebPolicyDelegate))
+ *ppvObject = static_cast<IWebPolicyDelegate*>(this);
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE PolicyDelegate::AddRef(void)
+{
+ return ++m_refCount;
+}
+
+ULONG STDMETHODCALLTYPE PolicyDelegate::Release(void)
+{
+ ULONG newRef = --m_refCount;
+ if (!newRef)
+ delete this;
+
+ return newRef;
+}
+
+HRESULT STDMETHODCALLTYPE PolicyDelegate::decidePolicyForNavigationAction(
+ /*[in]*/ IWebView* /*webView*/,
+ /*[in]*/ IPropertyBag* actionInformation,
+ /*[in]*/ IWebURLRequest* request,
+ /*[in]*/ IWebFrame* frame,
+ /*[in]*/ IWebPolicyDecisionListener* listener)
+{
+ BSTR url;
+ request->URL(&url);
+ wstring wurl = urlSuitableForTestResult(wstring(url, SysStringLen(url)));
+
+ int navType = 0;
+ VARIANT var;
+ if (SUCCEEDED(actionInformation->Read(WebActionNavigationTypeKey, &var, 0))) {
+ V_VT(&var) = VT_I4;
+ navType = V_I4(&var);
+ }
+
+ LPCTSTR typeDescription;
+ switch (navType) {
+ case WebNavigationTypeLinkClicked:
+ typeDescription = TEXT("link clicked");
+ break;
+ case WebNavigationTypeFormSubmitted:
+ typeDescription = TEXT("form submitted");
+ break;
+ case WebNavigationTypeBackForward:
+ typeDescription = TEXT("back/forward");
+ break;
+ case WebNavigationTypeReload:
+ typeDescription = TEXT("reload");
+ break;
+ case WebNavigationTypeFormResubmitted:
+ typeDescription = TEXT("form resubmitted");
+ break;
+ case WebNavigationTypeOther:
+ typeDescription = TEXT("other");
+ break;
+ default:
+ typeDescription = TEXT("illegal value");
+ }
+
+ wstring message = TEXT("Policy delegate: attempt to load ") + wurl + TEXT(" with navigation type '") + typeDescription + TEXT("'");
+
+ VARIANT actionElementVar;
+ if (SUCCEEDED(actionInformation->Read(WebActionElementKey, &actionElementVar, 0))) {
+ COMPtr<IPropertyBag> actionElement(Query, V_UNKNOWN(&actionElementVar));
+ VARIANT originatingNodeVar;
+ if (SUCCEEDED(actionElement->Read(WebElementDOMNodeKey, &originatingNodeVar, 0))) {
+ COMPtr<IDOMNode> originatingNode(Query, V_UNKNOWN(&originatingNodeVar));
+ message += TEXT(" originating from ") + dumpPath(originatingNode.get());
+ }
+ }
+
+ printf("%S\n", message.c_str());
+
+ SysFreeString(url);
+
+ if (m_permissiveDelegate)
+ listener->use();
+ else
+ listener->ignore();
+
+ if (m_controllerToNotifyDone) {
+ m_controllerToNotifyDone->notifyDone();
+ m_controllerToNotifyDone = 0;
+ }
+
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE PolicyDelegate::unableToImplementPolicyWithError(
+ /*[in]*/ IWebView* /*webView*/,
+ /*[in]*/ IWebError* error,
+ /*[in]*/ IWebFrame* frame)
+{
+ BSTR domainStr;
+ error->domain(&domainStr);
+ wstring domainMessage = domainStr;
+
+ int code;
+ error->code(&code);
+
+ BSTR frameName;
+ frame->name(&frameName);
+ wstring frameNameMessage = frameName;
+
+ printf("Policy delegate: unable to implement policy with error domain '%S', error code %d, in frame '%S'", domainMessage.c_str(), code, frameNameMessage.c_str());
+
+ SysFreeString(domainStr);
+ SysFreeString(frameName);
+
+ return S_OK;
+}
diff --git a/Tools/DumpRenderTree/win/PolicyDelegate.h b/Tools/DumpRenderTree/win/PolicyDelegate.h
new file mode 100644
index 000000000..c808dc9c4
--- /dev/null
+++ b/Tools/DumpRenderTree/win/PolicyDelegate.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 PolicyDelegate_h
+#define PolicyDelegate_h
+
+#include <WebKit/WebKit.h>
+
+class LayoutTestController;
+
+class PolicyDelegate : public IWebPolicyDelegate {
+public:
+ PolicyDelegate();
+
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // IWebPolicyDelegate
+ virtual HRESULT STDMETHODCALLTYPE decidePolicyForNavigationAction(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IPropertyBag *actionInformation,
+ /* [in] */ IWebURLRequest *request,
+ /* [in] */ IWebFrame *frame,
+ /* [in] */ IWebPolicyDecisionListener *listener);
+
+ virtual HRESULT STDMETHODCALLTYPE decidePolicyForNewWindowAction(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IPropertyBag *actionInformation,
+ /* [in] */ IWebURLRequest *request,
+ /* [in] */ BSTR frameName,
+ /* [in] */ IWebPolicyDecisionListener *listener){ return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE decidePolicyForMIMEType(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR type,
+ /* [in] */ IWebURLRequest *request,
+ /* [in] */ IWebFrame *frame,
+ /* [in] */ IWebPolicyDecisionListener *listener){ return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE unableToImplementPolicyWithError(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebError *error,
+ /* [in] */ IWebFrame *frame);
+
+ // PolicyDelegate
+ void setPermissive(bool permissive) { m_permissiveDelegate = permissive; }
+ void setControllerToNotifyDone(LayoutTestController* controller) { m_controllerToNotifyDone = controller; }
+
+private:
+ ULONG m_refCount;
+ bool m_permissiveDelegate;
+ LayoutTestController* m_controllerToNotifyDone;
+};
+
+#endif // PolicyDelegate_h
diff --git a/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp b/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp
new file mode 100644
index 000000000..26b722a4e
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "ResourceLoadDelegate.h"
+
+#include "DumpRenderTree.h"
+#include "LayoutTestController.h"
+#include <WebKit/WebKitCOMAPI.h>
+#include <comutil.h>
+#include <sstream>
+#include <tchar.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+static inline wstring wstringFromBSTR(BSTR str)
+{
+ return wstring(str, ::SysStringLen(str));
+}
+
+static inline wstring wstringFromInt(int i)
+{
+ wostringstream ss;
+ ss << i;
+ return ss.str();
+}
+
+static inline BSTR BSTRFromString(const string& str)
+{
+ int length = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), 0, 0);
+ BSTR result = ::SysAllocStringLen(0, length);
+ ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), result, length);
+ return result;
+}
+
+wstring ResourceLoadDelegate::descriptionSuitableForTestResult(unsigned long identifier) const
+{
+ IdentifierMap::const_iterator it = m_urlMap.find(identifier);
+
+ if (it == m_urlMap.end())
+ return L"<unknown>";
+
+ return urlSuitableForTestResult(it->second);
+}
+
+wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLRequest* request)
+{
+ if (!request)
+ return L"(null)";
+
+ BSTR urlBSTR;
+ if (FAILED(request->URL(&urlBSTR)))
+ return wstring();
+
+ wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
+ ::SysFreeString(urlBSTR);
+
+ BSTR mainDocumentURLBSTR;
+ if (FAILED(request->mainDocumentURL(&mainDocumentURLBSTR)))
+ return wstring();
+
+ wstring mainDocumentURL = urlSuitableForTestResult(wstringFromBSTR(mainDocumentURLBSTR));
+ ::SysFreeString(mainDocumentURLBSTR);
+
+ BSTR httpMethodBSTR;
+ if (FAILED(request->HTTPMethod(&httpMethodBSTR)))
+ return wstring();
+
+ wstring httpMethod = wstringFromBSTR(httpMethodBSTR);
+ ::SysFreeString(httpMethodBSTR);
+
+ return L"<NSURLRequest URL " + url + L", main document URL " + mainDocumentURL + L", http method " + httpMethod + L">";
+}
+
+wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLResponse* response)
+{
+ if (!response)
+ return L"(null)";
+
+ BSTR urlBSTR;
+ if (FAILED(response->URL(&urlBSTR)))
+ return wstring();
+
+ wstring url = urlSuitableForTestResult(wstringFromBSTR(urlBSTR));
+ ::SysFreeString(urlBSTR);
+
+ int statusCode = 0;
+ COMPtr<IWebHTTPURLResponse> httpResponse;
+ if (response && SUCCEEDED(response->QueryInterface(&httpResponse)))
+ httpResponse->statusCode(&statusCode);
+
+ return L"<NSURLResponse " + url + L", http status code " + wstringFromInt(statusCode) + L">";
+}
+
+wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebError* error, unsigned long identifier) const
+{
+ wstring result = L"<NSError ";
+
+ BSTR domainSTR;
+ if (FAILED(error->domain(&domainSTR)))
+ return wstring();
+
+ wstring domain = wstringFromBSTR(domainSTR);
+ ::SysFreeString(domainSTR);
+
+ int code;
+ if (FAILED(error->code(&code)))
+ return wstring();
+
+ if (domain == L"CFURLErrorDomain") {
+ domain = L"NSURLErrorDomain";
+
+ // Convert kCFURLErrorUnknown to NSURLErrorUnknown
+ if (code == -998)
+ code = -1;
+ } else if (domain == L"kCFErrorDomainWinSock") {
+ domain = L"NSURLErrorDomain";
+
+ // Convert the winsock error code to an NSURLError code.
+ if (code == WSAEADDRNOTAVAIL)
+ code = -1004; // NSURLErrorCannotConnectToHose;
+ }
+
+ result += L"domain " + domain;
+ result += L", code " + wstringFromInt(code);
+
+ BSTR failingURLSTR;
+ if (FAILED(error->failingURL(&failingURLSTR)))
+ return wstring();
+
+ if (failingURLSTR) {
+ result += L", failing URL \"" + urlSuitableForTestResult(wstringFromBSTR(failingURLSTR)) + L"\"";
+ ::SysFreeString(failingURLSTR);
+ }
+
+ result += L">";
+
+ return result;
+}
+
+ResourceLoadDelegate::ResourceLoadDelegate()
+ : m_refCount(1)
+{
+}
+
+ResourceLoadDelegate::~ResourceLoadDelegate()
+{
+}
+
+HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::QueryInterface(REFIID riid, void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IsEqualGUID(riid, IID_IUnknown))
+ *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegate))
+ *ppvObject = static_cast<IWebResourceLoadDelegate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegatePrivate2))
+ *ppvObject = static_cast<IWebResourceLoadDelegatePrivate2*>(this);
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE ResourceLoadDelegate::AddRef(void)
+{
+ return ++m_refCount;
+}
+
+ULONG STDMETHODCALLTYPE ResourceLoadDelegate::Release(void)
+{
+ ULONG newRef = --m_refCount;
+ if (!newRef)
+ delete(this);
+
+ return newRef;
+}
+
+HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::identifierForInitialRequest(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IWebURLRequest* request,
+ /* [in] */ IWebDataSource* dataSource,
+ /* [in] */ unsigned long identifier)
+{
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
+ BSTR urlStr;
+ if (FAILED(request->URL(&urlStr)))
+ return E_FAIL;
+
+ ASSERT(!urlMap().contains(identifier));
+ urlMap().set(identifier, wstringFromBSTR(urlStr));
+ }
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::removeIdentifierForRequest(
+ /* [in] */ IWebView* webView,
+ /* [in] */ unsigned long identifier)
+{
+ urlMap().remove(identifier);
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::willSendRequest(
+ /* [in] */ IWebView* webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebURLRequest* request,
+ /* [in] */ IWebURLResponse* redirectResponse,
+ /* [in] */ IWebDataSource* dataSource,
+ /* [retval][out] */ IWebURLRequest **newRequest)
+{
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
+ printf("%S - willSendRequest %S redirectResponse %S\n",
+ descriptionSuitableForTestResult(identifier).c_str(),
+ descriptionSuitableForTestResult(request).c_str(),
+ descriptionSuitableForTestResult(redirectResponse).c_str());
+ }
+
+ if (!done && !gLayoutTestController->deferMainResourceDataLoad()) {
+ COMPtr<IWebDataSourcePrivate> dataSourcePrivate(Query, dataSource);
+ if (!dataSourcePrivate)
+ return E_FAIL;
+ dataSourcePrivate->setDeferMainResourceDataLoad(FALSE);
+ }
+
+ if (!done && gLayoutTestController->willSendRequestReturnsNull()) {
+ *newRequest = 0;
+ return S_OK;
+ }
+
+ if (!done && gLayoutTestController->willSendRequestReturnsNullOnRedirect() && redirectResponse) {
+ printf("Returning null for this redirect\n");
+ *newRequest = 0;
+ return S_OK;
+ }
+
+ IWebMutableURLRequest* requestCopy = 0;
+ request->mutableCopy(&requestCopy);
+ const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders();
+ for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header) {
+ BSTR bstrHeader = BSTRFromString(*header);
+ requestCopy->setValue(0, bstrHeader);
+ SysFreeString(bstrHeader);
+ }
+
+ *newRequest = requestCopy;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didReceiveAuthenticationChallenge(
+ /* [in] */ IWebView *webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebURLAuthenticationChallenge *challenge,
+ /* [in] */ IWebDataSource *dataSource)
+{
+ COMPtr<IWebURLAuthenticationChallengeSender> sender;
+ if (!challenge || FAILED(challenge->sender(&sender)))
+ return E_FAIL;
+
+ if (!gLayoutTestController->handlesAuthenticationChallenges()) {
+ printf("%S - didReceiveAuthenticationChallenge - Simulating cancelled authentication sheet\n", descriptionSuitableForTestResult(identifier).c_str());
+ sender->continueWithoutCredentialForAuthenticationChallenge(challenge);
+ return S_OK;
+ }
+
+ const char* user = gLayoutTestController->authenticationUsername().c_str();
+ const char* password = gLayoutTestController->authenticationPassword().c_str();
+
+ printf("%S - didReceiveAuthenticationChallenge - Responding with %s:%s\n", descriptionSuitableForTestResult(identifier).c_str(), user, password);
+
+ COMPtr<IWebURLCredential> credential;
+ if (FAILED(WebKitCreateInstance(CLSID_WebURLCredential, 0, IID_IWebURLCredential, (void**)&credential)))
+ return E_FAIL;
+ credential->initWithUser(_bstr_t(user), _bstr_t(password), WebURLCredentialPersistenceForSession);
+
+ sender->useCredential(credential.get(), challenge);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didReceiveResponse(
+ /* [in] */ IWebView* webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebURLResponse* response,
+ /* [in] */ IWebDataSource* dataSource)
+{
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
+ printf("%S - didReceiveResponse %S\n",
+ descriptionSuitableForTestResult(identifier).c_str(),
+ descriptionSuitableForTestResult(response).c_str());
+ }
+ if (!done && gLayoutTestController->dumpResourceResponseMIMETypes()) {
+ BSTR mimeTypeBSTR;
+ if (FAILED(response->MIMEType(&mimeTypeBSTR)))
+ E_FAIL;
+
+ wstring mimeType = wstringFromBSTR(mimeTypeBSTR);
+ ::SysFreeString(mimeTypeBSTR);
+
+ BSTR urlBSTR;
+ if (FAILED(response->URL(&urlBSTR)))
+ E_FAIL;
+
+ wstring url = wstringFromBSTR(urlBSTR);
+ ::SysFreeString(urlBSTR);
+
+ printf("%S has MIME type %S\n", lastPathComponent(url).c_str(), mimeType.c_str());
+ }
+
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFinishLoadingFromDataSource(
+ /* [in] */ IWebView* webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebDataSource* dataSource)
+{
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
+ printf("%S - didFinishLoading\n",
+ descriptionSuitableForTestResult(identifier).c_str());
+ }
+
+ removeIdentifierForRequest(webView, identifier);
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFailLoadingWithError(
+ /* [in] */ IWebView* webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebError* error,
+ /* [in] */ IWebDataSource* dataSource)
+{
+ if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
+ printf("%S - didFailLoadingWithError: %S\n",
+ descriptionSuitableForTestResult(identifier).c_str(),
+ descriptionSuitableForTestResult(error, identifier).c_str());
+ }
+
+ removeIdentifierForRequest(webView, identifier);
+
+ return S_OK;
+}
diff --git a/Tools/DumpRenderTree/win/ResourceLoadDelegate.h b/Tools/DumpRenderTree/win/ResourceLoadDelegate.h
new file mode 100644
index 000000000..3f20f47c9
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ResourceLoadDelegate.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 ResourceLoadDelegate_h
+#define ResourceLoadDelegate_h
+
+#include <WebKit/WebKit.h>
+#include <string>
+#include <wtf/HashMap.h>
+
+class ResourceLoadDelegate : public IWebResourceLoadDelegate, public IWebResourceLoadDelegatePrivate2 {
+public:
+ ResourceLoadDelegate();
+ virtual ~ResourceLoadDelegate();
+
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // IWebResourceLoadDelegate
+ virtual HRESULT STDMETHODCALLTYPE identifierForInitialRequest(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebURLRequest *request,
+ /* [in] */ IWebDataSource *dataSource,
+ /* [in] */ unsigned long identifier);
+
+ virtual HRESULT STDMETHODCALLTYPE willSendRequest(
+ /* [in] */ IWebView *webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebURLRequest *request,
+ /* [in] */ IWebURLResponse *redirectResponse,
+ /* [in] */ IWebDataSource *dataSource,
+ /* [retval][out] */ IWebURLRequest **newRequest);
+
+ virtual HRESULT STDMETHODCALLTYPE didReceiveAuthenticationChallenge(
+ /* [in] */ IWebView *webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebURLAuthenticationChallenge *challenge,
+ /* [in] */ IWebDataSource *dataSource);
+
+ virtual HRESULT STDMETHODCALLTYPE didCancelAuthenticationChallenge(
+ /* [in] */ IWebView *webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebURLAuthenticationChallenge *challenge,
+ /* [in] */ IWebDataSource *dataSource) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didReceiveResponse(
+ /* [in] */ IWebView *webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebURLResponse *response,
+ /* [in] */ IWebDataSource *dataSource);
+
+ virtual HRESULT STDMETHODCALLTYPE didReceiveContentLength(
+ /* [in] */ IWebView *webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ UINT length,
+ /* [in] */ IWebDataSource *dataSource) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didFinishLoadingFromDataSource(
+ /* [in] */ IWebView *webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebDataSource *dataSource);
+
+ virtual HRESULT STDMETHODCALLTYPE didFailLoadingWithError(
+ /* [in] */ IWebView *webView,
+ /* [in] */ unsigned long identifier,
+ /* [in] */ IWebError *error,
+ /* [in] */ IWebDataSource *dataSource);
+
+ virtual HRESULT STDMETHODCALLTYPE plugInFailedWithError(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebError *error,
+ /* [in] */ IWebDataSource *dataSource) { return E_NOTIMPL; }
+
+ // IWebResourceLoadDelegatePrivate2
+ virtual HRESULT STDMETHODCALLTYPE removeIdentifierForRequest(
+ /* [in] */ IWebView *webView,
+ /* [in] */ unsigned long identifier);
+
+private:
+ static std::wstring descriptionSuitableForTestResult(IWebURLRequest*);
+ static std::wstring descriptionSuitableForTestResult(IWebURLResponse*);
+ std::wstring descriptionSuitableForTestResult(unsigned long) const;
+ std::wstring descriptionSuitableForTestResult(IWebError*, unsigned long) const;
+
+ typedef HashMap<unsigned long, std::wstring> IdentifierMap;
+ IdentifierMap& urlMap() { return m_urlMap; }
+ IdentifierMap m_urlMap;
+
+ ULONG m_refCount;
+};
+
+#endif // ResourceLoadDelegate_h
diff --git a/Tools/DumpRenderTree/win/UIDelegate.cpp b/Tools/DumpRenderTree/win/UIDelegate.cpp
new file mode 100644
index 000000000..729e3378d
--- /dev/null
+++ b/Tools/DumpRenderTree/win/UIDelegate.cpp
@@ -0,0 +1,664 @@
+/*
+ * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "UIDelegate.h"
+
+#include "DumpRenderTree.h"
+#include "DraggingInfo.h"
+#include "EventSender.h"
+#include "LayoutTestController.h"
+#include "DRTDesktopNotificationPresenter.h"
+
+#include <WebCore/COMPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Platform.h>
+#include <wtf/Vector.h>
+#include <JavaScriptCore/Assertions.h>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <WebKit/WebKit.h>
+#include <stdio.h>
+
+using std::wstring;
+
+class DRTUndoObject {
+public:
+ DRTUndoObject(IWebUndoTarget* target, BSTR actionName, IUnknown* obj)
+ : m_target(target)
+ , m_actionName(SysAllocString(actionName))
+ , m_obj(obj)
+ {
+ }
+
+ ~DRTUndoObject()
+ {
+ SysFreeString(m_actionName);
+ }
+
+ void invoke()
+ {
+ m_target->invoke(m_actionName, m_obj.get());
+ }
+
+private:
+ IWebUndoTarget* m_target;
+ BSTR m_actionName;
+ COMPtr<IUnknown> m_obj;
+};
+
+class DRTUndoStack {
+public:
+ ~DRTUndoStack() { deleteAllValues(m_undoVector); }
+
+ bool isEmpty() const { return m_undoVector.isEmpty(); }
+ void clear() { deleteAllValues(m_undoVector); m_undoVector.clear(); }
+
+ void push(DRTUndoObject* undoObject) { m_undoVector.append(undoObject); }
+ DRTUndoObject* pop() { DRTUndoObject* top = m_undoVector.last(); m_undoVector.removeLast(); return top; }
+
+private:
+ Vector<DRTUndoObject*> m_undoVector;
+};
+
+class DRTUndoManager {
+public:
+ DRTUndoManager();
+
+ void removeAllActions();
+ void registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj);
+ void redo();
+ void undo();
+ bool canRedo() { return !m_redoStack->isEmpty(); }
+ bool canUndo() { return !m_undoStack->isEmpty(); }
+
+private:
+ OwnPtr<DRTUndoStack> m_redoStack;
+ OwnPtr<DRTUndoStack> m_undoStack;
+ bool m_isRedoing;
+ bool m_isUndoing;
+};
+
+DRTUndoManager::DRTUndoManager()
+ : m_redoStack(adoptPtr(new DRTUndoStack))
+ , m_undoStack(adoptPtr(new DRTUndoStack))
+ , m_isRedoing(false)
+ , m_isUndoing(false)
+{
+}
+
+void DRTUndoManager::removeAllActions()
+{
+ m_redoStack->clear();
+ m_undoStack->clear();
+}
+
+void DRTUndoManager::registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj)
+{
+ if (!m_isUndoing && !m_isRedoing)
+ m_redoStack->clear();
+
+ DRTUndoStack* stack = m_isUndoing ? m_redoStack.get() : m_undoStack.get();
+ stack->push(new DRTUndoObject(target, actionName, obj));
+}
+
+void DRTUndoManager::redo()
+{
+ if (!canRedo())
+ return;
+
+ m_isRedoing = true;
+
+ DRTUndoObject* redoObject = m_redoStack->pop();
+ redoObject->invoke();
+ delete redoObject;
+
+ m_isRedoing = false;
+}
+
+void DRTUndoManager::undo()
+{
+ if (!canUndo())
+ return;
+
+ m_isUndoing = true;
+
+ DRTUndoObject* undoObject = m_undoStack->pop();
+ undoObject->invoke();
+ delete undoObject;
+
+ m_isUndoing = false;
+}
+
+UIDelegate::UIDelegate()
+ : m_refCount(1)
+ , m_undoManager(adoptPtr(new DRTUndoManager))
+ , m_desktopNotifications(new DRTDesktopNotificationPresenter)
+{
+ m_frame.bottom = 0;
+ m_frame.top = 0;
+ m_frame.left = 0;
+ m_frame.right = 0;
+}
+
+void UIDelegate::resetUndoManager()
+{
+ m_undoManager = adoptPtr(new DRTUndoManager);
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::QueryInterface(REFIID riid, void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IsEqualGUID(riid, IID_IUnknown))
+ *ppvObject = static_cast<IWebUIDelegate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebUIDelegate))
+ *ppvObject = static_cast<IWebUIDelegate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebUIDelegate2))
+ *ppvObject = static_cast<IWebUIDelegate2*>(this);
+ else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate))
+ *ppvObject = static_cast<IWebUIDelegatePrivate*>(this);
+ else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate2))
+ *ppvObject = static_cast<IWebUIDelegatePrivate2*>(this);
+ else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate3))
+ *ppvObject = static_cast<IWebUIDelegatePrivate3*>(this);
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE UIDelegate::AddRef()
+{
+ return ++m_refCount;
+}
+
+ULONG STDMETHODCALLTYPE UIDelegate::Release()
+{
+ ULONG newRef = --m_refCount;
+ if (!newRef)
+ delete(this);
+
+ return newRef;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::hasCustomMenuImplementation(
+ /* [retval][out] */ BOOL *hasCustomMenus)
+{
+ *hasCustomMenus = TRUE;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::trackCustomPopupMenu(
+ /* [in] */ IWebView *sender,
+ /* [in] */ OLE_HANDLE menu,
+ /* [in] */ LPPOINT point)
+{
+ // Do nothing
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::registerUndoWithTarget(
+ /* [in] */ IWebUndoTarget* target,
+ /* [in] */ BSTR actionName,
+ /* [in] */ IUnknown* actionArg)
+{
+ m_undoManager->registerUndoWithTarget(target, actionName, actionArg);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::removeAllActionsWithTarget(
+ /* [in] */ IWebUndoTarget*)
+{
+ m_undoManager->removeAllActions();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::setActionTitle(
+ /* [in] */ BSTR actionTitle)
+{
+ // It is not neccessary to implement this for DRT because there is
+ // menu to write out the title to.
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::undo()
+{
+ m_undoManager->undo();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::redo()
+{
+ m_undoManager->redo();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::canUndo(
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result)
+ return E_POINTER;
+
+ *result = m_undoManager->canUndo();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::canRedo(
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result)
+ return E_POINTER;
+
+ *result = m_undoManager->canRedo();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::printFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::ftpDirectoryTemplatePath(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ BSTR *path)
+{
+ if (!path)
+ return E_POINTER;
+ *path = 0;
+ return E_NOTIMPL;
+}
+
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewHeaderHeight(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ float *result)
+{
+ if (!result)
+ return E_POINTER;
+ *result = 0;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewFooterHeight(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ float *result)
+{
+ if (!result)
+ return E_POINTER;
+ *result = 0;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::drawHeaderInRect(
+ /* [in] */ IWebView *webView,
+ /* [in] */ RECT *rect,
+ /* [in] */ OLE_HANDLE drawingContext)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::drawFooterInRect(
+ /* [in] */ IWebView *webView,
+ /* [in] */ RECT *rect,
+ /* [in] */ OLE_HANDLE drawingContext,
+ /* [in] */ UINT pageIndex,
+ /* [in] */ UINT pageCount)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewPrintingMarginRect(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ RECT *rect)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::canRunModal(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ BOOL *canRunBoolean)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::createModalDialog(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebURLRequest *request,
+ /* [retval][out] */ IWebView **newWebView)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::runModal(
+ /* [in] */ IWebView *webView)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::isMenuBarVisible(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ BOOL *visible)
+{
+ if (!visible)
+ return E_POINTER;
+ *visible = false;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::setMenuBarVisible(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BOOL visible)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::runDatabaseSizeLimitPrompt(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR displayName,
+ /* [in] */ IWebFrame *initiatedByFrame,
+ /* [retval][out] */ BOOL *allowed)
+{
+ if (!allowed)
+ return E_POINTER;
+ *allowed = false;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollbar(
+ /* [in] */ IWebView *webView,
+ /* [in] */ HDC hDC,
+ /* [in] */ RECT rect,
+ /* [in] */ WebScrollBarControlSize size,
+ /* [in] */ WebScrollbarControlState state,
+ /* [in] */ WebScrollbarControlPart pressedPart,
+ /* [in] */ BOOL vertical,
+ /* [in] */ float value,
+ /* [in] */ float proportion,
+ /* [in] */ WebScrollbarControlPartMask parts)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollCorner(
+ /* [in] */ IWebView *webView,
+ /* [in] */ HDC hDC,
+ /* [in] */ RECT rect)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::setFrame(
+ /* [in] */ IWebView* /*sender*/,
+ /* [in] */ RECT* frame)
+{
+ m_frame = *frame;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewFrame(
+ /* [in] */ IWebView* /*sender*/,
+ /* [retval][out] */ RECT* frame)
+{
+ *frame = m_frame;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptAlertPanelWithMessage(
+ /* [in] */ IWebView* /*sender*/,
+ /* [in] */ BSTR message)
+{
+ printf("ALERT: %S\n", message ? message : L"");
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptConfirmPanelWithMessage(
+ /* [in] */ IWebView* sender,
+ /* [in] */ BSTR message,
+ /* [retval][out] */ BOOL* result)
+{
+ printf("CONFIRM: %S\n", message ? message : L"");
+ *result = TRUE;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptTextInputPanelWithPrompt(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BSTR message,
+ /* [in] */ BSTR defaultText,
+ /* [retval][out] */ BSTR *result)
+{
+ printf("PROMPT: %S, default text: %S\n", message ? message : L"", defaultText ? defaultText : L"");
+ *result = SysAllocString(defaultText);
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::runBeforeUnloadConfirmPanelWithMessage(
+ /* [in] */ IWebView* /*sender*/,
+ /* [in] */ BSTR message,
+ /* [in] */ IWebFrame* /*initiatedByFrame*/,
+ /* [retval][out] */ BOOL* result)
+{
+ if (!result)
+ return E_POINTER;
+ printf("CONFIRM NAVIGATION: %S\n", message ? message : L"");
+ *result = !gLayoutTestController->shouldStayOnPageAfterHandlingBeforeUnload();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewAddMessageToConsole(
+ /* [in] */ IWebView* sender,
+ /* [in] */ BSTR message,
+ /* [in] */ int lineNumber,
+ /* [in] */ BSTR url,
+ /* [in] */ BOOL isError)
+{
+ wstring newMessage;
+ if (message) {
+ newMessage = message;
+ size_t fileProtocol = newMessage.find(L"file://");
+ if (fileProtocol != wstring::npos)
+ newMessage = newMessage.substr(0, fileProtocol) + lastPathComponent(newMessage.substr(fileProtocol));
+ }
+
+ printf("CONSOLE MESSAGE: line %d: %s\n", lineNumber, toUTF8(newMessage).c_str());
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::doDragDrop(
+ /* [in] */ IWebView* sender,
+ /* [in] */ IDataObject* object,
+ /* [in] */ IDropSource* source,
+ /* [in] */ DWORD okEffect,
+ /* [retval][out] */ DWORD* performedEffect)
+{
+ if (!performedEffect)
+ return E_POINTER;
+
+ *performedEffect = 0;
+
+ draggingInfo = new DraggingInfo(object, source);
+ HRESULT oleDragAndDropReturnValue = DRAGDROP_S_CANCEL;
+ replaySavedEvents(&oleDragAndDropReturnValue);
+ if (draggingInfo) {
+ *performedEffect = draggingInfo->performedDropEffect();
+ delete draggingInfo;
+ draggingInfo = 0;
+ }
+ return oleDragAndDropReturnValue;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewGetDlgCode(
+ /* [in] */ IWebView* /*sender*/,
+ /* [in] */ UINT /*keyCode*/,
+ /* [retval][out] */ LONG_PTR *code)
+{
+ if (!code)
+ return E_POINTER;
+ *code = 0;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::createWebViewWithRequest(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebURLRequest *request,
+ /* [retval][out] */ IWebView **newWebView)
+{
+ if (!::gLayoutTestController->canOpenWindows())
+ return E_FAIL;
+ *newWebView = createWebViewAndOffscreenWindow();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewClose(
+ /* [in] */ IWebView *sender)
+{
+ HWND hostWindow;
+ sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow));
+ DestroyWindow(hostWindow);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewFocus(
+ /* [in] */ IWebView *sender)
+{
+ HWND hostWindow;
+ sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow));
+ SetForegroundWindow(hostWindow);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewUnfocus(
+ /* [in] */ IWebView *sender)
+{
+ SetForegroundWindow(GetDesktopWindow());
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewPainted(
+ /* [in] */ IWebView *sender)
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::exceededDatabaseQuota(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame,
+ /* [in] */ IWebSecurityOrigin *origin,
+ /* [in] */ BSTR databaseIdentifier)
+{
+ BSTR protocol;
+ BSTR host;
+ unsigned short port;
+
+ origin->protocol(&protocol);
+ origin->host(&host);
+ origin->port(&port);
+
+ if (!done && gLayoutTestController->dumpDatabaseCallbacks())
+ printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%S, %S, %i} database:%S\n", protocol, host, port, databaseIdentifier);
+
+ SysFreeString(protocol);
+ SysFreeString(host);
+
+ static const unsigned long long defaultQuota = 5 * 1024 * 1024;
+ origin->setQuota(defaultQuota);
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::embeddedViewWithArguments(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame,
+ /* [in] */ IPropertyBag *arguments,
+ /* [retval][out] */ IWebEmbeddedView **view)
+{
+ if (!view)
+ return E_POINTER;
+ *view = 0;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewClosing(
+ /* [in] */ IWebView *sender)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewSetCursor(
+ /* [in] */ IWebView *sender,
+ /* [in] */ OLE_HANDLE cursor)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::webViewDidInvalidate(
+ /* [in] */ IWebView *sender)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::setStatusText(IWebView*, BSTR text)
+{
+ if (gLayoutTestController->dumpStatusCallbacks())
+ printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text ? toUTF8(text).c_str() : "");
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::desktopNotificationsDelegate(IWebDesktopNotificationsDelegate** result)
+{
+ m_desktopNotifications.copyRefTo(result);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::createWebViewWithRequest(IWebView* sender, IWebURLRequest* request, IPropertyBag* windowFeatures, IWebView** newWebView)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::drawBackground(IWebView* sender, OLE_HANDLE hdc, const RECT* dirtyRect)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::decidePolicyForGeolocationRequest(IWebView* sender, IWebFrame* frame, IWebSecurityOrigin* origin, IWebGeolocationPolicyListener* listener)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE UIDelegate::didPressMissingPluginButton(IDOMElement* element)
+{
+ printf("MISSING PLUGIN BUTTON PRESSED\n");
+ return S_OK;
+}
+
diff --git a/Tools/DumpRenderTree/win/UIDelegate.h b/Tools/DumpRenderTree/win/UIDelegate.h
new file mode 100644
index 000000000..0c9fdaf63
--- /dev/null
+++ b/Tools/DumpRenderTree/win/UIDelegate.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 UIDelegate_h
+#define UIDelegate_h
+
+#include <WebCore/COMPtr.h>
+#include <WebKit/WebKit.h>
+#include <wtf/OwnPtr.h>
+#include <windef.h>
+
+class DRTUndoManager;
+class DRTDesktopNotificationPresenter;
+
+class UIDelegate : public IWebUIDelegate2, IWebUIDelegatePrivate3 {
+public:
+ UIDelegate();
+
+ void resetUndoManager();
+
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // IWebUIDelegate
+ virtual HRESULT STDMETHODCALLTYPE createWebViewWithRequest(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebURLRequest *request,
+ /* [retval][out] */ IWebView **newWebView);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewShow(
+ /* [in] */ IWebView *sender) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE webViewClose(
+ /* [in] */ IWebView *sender);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewFocus(
+ /* [in] */ IWebView *sender);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewUnfocus(
+ /* [in] */ IWebView *sender);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewFirstResponder(
+ /* [in] */ IWebView *sender,
+ /* [retval][out] */ OLE_HANDLE *responder) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE makeFirstResponder(
+ /* [in] */ IWebView *sender,
+ /* [in] */ OLE_HANDLE responder) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE setStatusText(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BSTR text);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewStatusText(
+ /* [in] */ IWebView *sender,
+ /* [retval][out] */ BSTR *text) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE webViewAreToolbarsVisible(
+ /* [in] */ IWebView *sender,
+ /* [retval][out] */ BOOL *visible) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE setToolbarsVisible(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BOOL visible) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE webViewIsStatusBarVisible(
+ /* [in] */ IWebView *sender,
+ /* [retval][out] */ BOOL *visible) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE setStatusBarVisible(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BOOL visible) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE webViewIsResizable(
+ /* [in] */ IWebView *sender,
+ /* [retval][out] */ BOOL *resizable) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE setResizable(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BOOL resizable) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE setFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ RECT *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewFrame(
+ /* [in] */ IWebView *sender,
+ /* [retval][out] */ RECT *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE setContentRect(
+ /* [in] */ IWebView *sender,
+ /* [in] */ RECT *contentRect) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE webViewContentRect(
+ /* [in] */ IWebView *sender,
+ /* [retval][out] */ RECT *contentRect) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE runJavaScriptAlertPanelWithMessage(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BSTR message);
+
+ virtual HRESULT STDMETHODCALLTYPE runJavaScriptConfirmPanelWithMessage(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BSTR message,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE runJavaScriptTextInputPanelWithPrompt(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BSTR message,
+ /* [in] */ BSTR defaultText,
+ /* [retval][out] */ BSTR *result);
+
+ virtual HRESULT STDMETHODCALLTYPE runBeforeUnloadConfirmPanelWithMessage(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BSTR message,
+ /* [in] */ IWebFrame *initiatedByFrame,
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE runOpenPanelForFileButtonWithResultListener(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebOpenPanelResultListener *resultListener) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE mouseDidMoveOverElement(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IPropertyBag *elementInformation,
+ /* [in] */ UINT modifierFlags) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE contextMenuItemsForElement(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IPropertyBag *element,
+ /* [in] */ OLE_HANDLE defaultItems,
+ /* [retval][out] */ OLE_HANDLE *resultMenu) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE validateUserInterfaceItem(
+ /* [in] */ IWebView *webView,
+ /* [in] */ UINT itemCommandID,
+ /* [in] */ BOOL defaultValidation,
+ /* [retval][out] */ BOOL *isValid) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE shouldPerformAction(
+ /* [in] */ IWebView *webView,
+ /* [in] */ UINT itemCommandID,
+ /* [in] */ UINT sender) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE dragDestinationActionMaskForDraggingInfo(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IDataObject *draggingInfo,
+ /* [retval][out] */ WebDragDestinationAction *action) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE willPerformDragDestinationAction(
+ /* [in] */ IWebView *webView,
+ /* [in] */ WebDragDestinationAction action,
+ /* [in] */ IDataObject *draggingInfo) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE dragSourceActionMaskForPoint(
+ /* [in] */ IWebView *webView,
+ /* [in] */ LPPOINT point,
+ /* [retval][out] */ WebDragSourceAction *action) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE willPerformDragSourceAction(
+ /* [in] */ IWebView *webView,
+ /* [in] */ WebDragSourceAction action,
+ /* [in] */ LPPOINT point,
+ /* [in] */ IDataObject *pasteboard,
+ /* [retval][out] */ IDataObject **newPasteboard) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE contextMenuItemSelected(
+ /* [in] */ IWebView *sender,
+ /* [in] */ void *item,
+ /* [in] */ IPropertyBag *element) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE hasCustomMenuImplementation(
+ /* [retval][out] */ BOOL *hasCustomMenus);
+
+ virtual HRESULT STDMETHODCALLTYPE trackCustomPopupMenu(
+ /* [in] */ IWebView *sender,
+ /* [in] */ OLE_HANDLE menu,
+ /* [in] */ LPPOINT point);
+
+ virtual HRESULT STDMETHODCALLTYPE measureCustomMenuItem(
+ /* [in] */ IWebView *sender,
+ /* [in] */ void *measureItem) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE drawCustomMenuItem(
+ /* [in] */ IWebView *sender,
+ /* [in] */ void *drawItem) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE addCustomMenuDrawingData(
+ /* [in] */ IWebView *sender,
+ /* [in] */ OLE_HANDLE menu) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE cleanUpCustomMenuDrawingData(
+ /* [in] */ IWebView *sender,
+ /* [in] */ OLE_HANDLE menu) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE canTakeFocus(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BOOL forward,
+ /* [out] */ BOOL *result) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE takeFocus(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BOOL forward) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE registerUndoWithTarget(
+ /* [in] */ IWebUndoTarget *target,
+ /* [in] */ BSTR actionName,
+ /* [in] */ IUnknown *actionArg);
+
+ virtual HRESULT STDMETHODCALLTYPE removeAllActionsWithTarget(
+ /* [in] */ IWebUndoTarget *target);
+
+ virtual HRESULT STDMETHODCALLTYPE setActionTitle(
+ /* [in] */ BSTR actionTitle);
+
+ virtual HRESULT STDMETHODCALLTYPE undo();
+
+ virtual HRESULT STDMETHODCALLTYPE redo();
+
+ virtual HRESULT STDMETHODCALLTYPE canUndo(
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE canRedo(
+ /* [retval][out] */ BOOL *result);
+
+ virtual HRESULT STDMETHODCALLTYPE printFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame);
+
+ virtual HRESULT STDMETHODCALLTYPE ftpDirectoryTemplatePath(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ BSTR *path);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewHeaderHeight(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ float *result);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewFooterHeight(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ float *result);
+
+ virtual HRESULT STDMETHODCALLTYPE drawHeaderInRect(
+ /* [in] */ IWebView *webView,
+ /* [in] */ RECT *rect,
+ /* [in] */ OLE_HANDLE drawingContext);
+
+ virtual HRESULT STDMETHODCALLTYPE drawFooterInRect(
+ /* [in] */ IWebView *webView,
+ /* [in] */ RECT *rect,
+ /* [in] */ OLE_HANDLE drawingContext,
+ /* [in] */ UINT pageIndex,
+ /* [in] */ UINT pageCount);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewPrintingMarginRect(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ RECT *rect);
+
+ virtual HRESULT STDMETHODCALLTYPE canRunModal(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ BOOL *canRunBoolean);
+
+ virtual HRESULT STDMETHODCALLTYPE createModalDialog(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebURLRequest *request,
+ /* [retval][out] */ IWebView **newWebView);
+
+ virtual HRESULT STDMETHODCALLTYPE runModal(
+ /* [in] */ IWebView *webView);
+
+ virtual HRESULT STDMETHODCALLTYPE isMenuBarVisible(
+ /* [in] */ IWebView *webView,
+ /* [retval][out] */ BOOL *visible);
+
+ virtual HRESULT STDMETHODCALLTYPE setMenuBarVisible(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BOOL visible);
+
+ virtual HRESULT STDMETHODCALLTYPE runDatabaseSizeLimitPrompt(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR displayName,
+ /* [in] */ IWebFrame *initiatedByFrame,
+ /* [retval][out] */ BOOL *allowed);
+
+ virtual HRESULT STDMETHODCALLTYPE paintCustomScrollbar(
+ /* [in] */ IWebView *webView,
+ /* [in] */ HDC hDC,
+ /* [in] */ RECT rect,
+ /* [in] */ WebScrollBarControlSize size,
+ /* [in] */ WebScrollbarControlState state,
+ /* [in] */ WebScrollbarControlPart pressedPart,
+ /* [in] */ BOOL vertical,
+ /* [in] */ float value,
+ /* [in] */ float proportion,
+ /* [in] */ WebScrollbarControlPartMask parts);
+
+ virtual HRESULT STDMETHODCALLTYPE paintCustomScrollCorner(
+ /* [in] */ IWebView *webView,
+ /* [in] */ HDC hDC,
+ /* [in] */ RECT rect);
+
+ virtual HRESULT STDMETHODCALLTYPE createWebViewWithRequest(IWebView* sender, IWebURLRequest* request, IPropertyBag* windowFeatures, IWebView** newWebView);
+
+ virtual HRESULT STDMETHODCALLTYPE drawBackground(IWebView* sender, OLE_HANDLE hdc, const RECT* dirtyRect);
+
+ virtual HRESULT STDMETHODCALLTYPE decidePolicyForGeolocationRequest(IWebView* sender, IWebFrame* frame, IWebSecurityOrigin* origin, IWebGeolocationPolicyListener* listener);
+
+ virtual HRESULT STDMETHODCALLTYPE didPressMissingPluginButton(IDOMElement*);
+
+protected:
+ // IWebUIDelegatePrivate
+
+ virtual HRESULT STDMETHODCALLTYPE unused1() { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE unused2() { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE unused3() { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE webViewScrolled(
+ /* [in] */ IWebView *sender) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE webViewAddMessageToConsole(
+ /* [in] */ IWebView *sender,
+ /* [in] */ BSTR message,
+ /* [in] */ int lineNumber,
+ /* [in] */ BSTR url,
+ /* [in] */ BOOL isError);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewShouldInterruptJavaScript(
+ /* [in] */ IWebView *sender,
+ /* [retval][out] */ BOOL *result) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE webViewReceivedFocus(
+ /* [in] */ IWebView *sender) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE webViewLostFocus(
+ /* [in] */ IWebView *sender,
+ /* [in] */ OLE_HANDLE loseFocusTo) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE doDragDrop(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IDataObject *dataObject,
+ /* [in] */ IDropSource *dropSource,
+ /* [in] */ DWORD okEffect,
+ /* [retval][out] */ DWORD *performedEffect);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewGetDlgCode(
+ /* [in] */ IWebView *sender,
+ /* [in] */ UINT keyCode,
+ /* [retval][out] */ LONG_PTR *code);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewPainted(
+ /* [in] */ IWebView *sender);
+
+ virtual HRESULT STDMETHODCALLTYPE exceededDatabaseQuota(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame,
+ /* [in] */ IWebSecurityOrigin *origin,
+ /* [in] */ BSTR databaseIdentifier);
+
+ virtual HRESULT STDMETHODCALLTYPE embeddedViewWithArguments(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame,
+ /* [in] */ IPropertyBag *arguments,
+ /* [retval][out] */ IWebEmbeddedView **view);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewClosing(
+ /* [in] */ IWebView *sender);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewSetCursor(
+ /* [in] */ IWebView *sender,
+ /* [in] */ OLE_HANDLE cursor);
+
+ virtual HRESULT STDMETHODCALLTYPE webViewDidInvalidate(
+ /* [in] */ IWebView *sender);
+
+ virtual HRESULT STDMETHODCALLTYPE desktopNotificationsDelegate(
+ /* [out] */ IWebDesktopNotificationsDelegate** result);
+
+ ULONG m_refCount;
+
+private:
+ RECT m_frame;
+ OwnPtr<DRTUndoManager> m_undoManager;
+
+ COMPtr<IWebDesktopNotificationsDelegate> m_desktopNotifications;
+};
+
+#endif
diff --git a/Tools/DumpRenderTree/win/WorkQueueItemWin.cpp b/Tools/DumpRenderTree/win/WorkQueueItemWin.cpp
new file mode 100644
index 000000000..49f0667d2
--- /dev/null
+++ b/Tools/DumpRenderTree/win/WorkQueueItemWin.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "WorkQueueItem.h"
+
+#include "DumpRenderTree.h"
+#include <WebCore/COMPtr.h>
+#include <WebKit/WebKit.h>
+#include <WebKit/WebKitCOMAPI.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <JavaScriptCore/JSStringRefCF.h>
+#include <JavaScriptCore/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <string>
+
+using std::wstring;
+
+static wstring jsStringRefToWString(JSStringRef jsStr)
+{
+ size_t length = JSStringGetLength(jsStr);
+ Vector<WCHAR> buffer(length + 1);
+ memcpy(buffer.data(), JSStringGetCharactersPtr(jsStr), length * sizeof(WCHAR));
+ buffer[length] = '\0';
+
+ return buffer.data();
+}
+
+bool LoadItem::invoke() const
+{
+ wstring targetString = jsStringRefToWString(m_target.get());
+
+ COMPtr<IWebFrame> targetFrame;
+ if (targetString.empty())
+ targetFrame = frame;
+ else {
+ BSTR targetBSTR = SysAllocString(targetString.c_str());
+ bool failed = FAILED(frame->findFrameNamed(targetBSTR, &targetFrame));
+ SysFreeString(targetBSTR);
+ if (failed)
+ return false;
+ }
+
+ COMPtr<IWebURLRequest> request;
+ if (FAILED(WebKitCreateInstance(CLSID_WebURLRequest, 0, IID_IWebURLRequest, (void**)&request)))
+ return false;
+
+ wstring urlString = jsStringRefToWString(m_url.get());
+ BSTR urlBSTR = SysAllocString(urlString.c_str());
+ bool failed = FAILED(request->initWithURL(urlBSTR, WebURLRequestUseProtocolCachePolicy, 60));
+ SysFreeString(urlBSTR);
+ if (failed)
+ return false;
+
+ targetFrame->loadRequest(request.get());
+ return true;
+}
+
+bool LoadHTMLStringItem::invoke() const
+{
+ wstring content = jsStringRefToWString(m_content.get());
+ wstring baseURL = jsStringRefToWString(m_baseURL.get());
+
+ BSTR contentBSTR = SysAllocString(content.c_str());
+ BSTR baseURLBSTR = SysAllocString(baseURL.c_str());
+
+ if (m_unreachableURL) {
+ wstring unreachableURL = jsStringRefToWString(m_unreachableURL.get());
+ BSTR unreachableURLBSTR = SysAllocString(unreachableURL.c_str());
+ frame->loadAlternateHTMLString(contentBSTR, baseURLBSTR, unreachableURLBSTR);
+ SysFreeString(contentBSTR);
+ SysFreeString(baseURLBSTR);
+ SysFreeString(unreachableURLBSTR);
+ return true;
+ }
+
+ frame->loadHTMLString(contentBSTR, baseURLBSTR);
+
+ SysFreeString(contentBSTR);
+ SysFreeString(baseURLBSTR);
+
+ return true;
+}
+
+bool ReloadItem::invoke() const
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return false;
+
+ COMPtr<IWebIBActions> webActions;
+ if (FAILED(webView->QueryInterface(&webActions)))
+ return false;
+
+ webActions->reload(0);
+ return true;
+}
+
+bool ScriptItem::invoke() const
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return false;
+
+ wstring scriptString = jsStringRefToWString(m_script.get());
+
+ BSTR result;
+ BSTR scriptBSTR = SysAllocString(scriptString.c_str());
+ webView->stringByEvaluatingJavaScriptFromString(scriptBSTR, &result);
+ SysFreeString(result);
+ SysFreeString(scriptBSTR);
+
+ return true;
+}
+
+bool BackForwardItem::invoke() const
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return false;
+
+ BOOL result;
+ if (m_howFar == 1) {
+ webView->goForward(&result);
+ return true;
+ }
+
+ if (m_howFar == -1) {
+ webView->goBack(&result);
+ return true;
+ }
+
+ COMPtr<IWebBackForwardList> bfList;
+ if (FAILED(webView->backForwardList(&bfList)))
+ return false;
+
+ COMPtr<IWebHistoryItem> item;
+ if (FAILED(bfList->itemAtIndex(m_howFar, &item)))
+ return false;
+
+ webView->goToBackForwardItem(item.get(), &result);
+ return true;
+}
diff --git a/Tools/DumpRenderTree/wscript b/Tools/DumpRenderTree/wscript
new file mode 100644
index 000000000..67efe9f0b
--- /dev/null
+++ b/Tools/DumpRenderTree/wscript
@@ -0,0 +1,65 @@
+#! /usr/bin/env python
+
+# Copyright (C) 2009 Kevin Ollivier All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# wxBrowser sample app build script for the waf build system
+
+import sys
+
+from settings import *
+
+include_paths = [
+ os.path.join(output_dir),
+ os.path.join(wk_root, 'Source', 'JavaScriptCore'),
+ os.path.join(wk_root, 'Source', 'WebCore'),
+ os.path.join(wk_root, 'Source', 'WebCore', 'bindings', 'wx'),
+ os.path.join(wk_root, 'Source', 'WebKit', 'wx'),
+ '.',
+ 'wx'
+ ]
+sources = [
+ 'LayoutTestController.cpp',
+ 'WorkQueue.cpp',
+ 'wx/DumpRenderTreeWx.cpp',
+ 'wx/LayoutTestControllerWx.cpp',
+ 'wx/WorkQueueItemWx.cpp'
+ ]
+
+def set_options(opt):
+ common_set_options(opt)
+
+def configure(conf):
+ common_configure(conf)
+
+def build(bld):
+ obj = bld.new_task_gen(
+ features = 'cxx cprogram',
+ includes = ' '.join(include_paths),
+ source = sources,
+ target = 'DumpRenderTree',
+ uselib = 'ICU WX ' + get_config(),
+ libpath = [output_dir],
+ uselib_local = 'jscore wxwebkit',
+ install_path = output_dir)
+
diff --git a/Tools/DumpRenderTree/wx/DumpRenderTreeWx.cpp b/Tools/DumpRenderTree/wx/DumpRenderTreeWx.cpp
new file mode 100644
index 000000000..92840d3cf
--- /dev/null
+++ b/Tools/DumpRenderTree/wx/DumpRenderTreeWx.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "DumpRenderTree.h"
+
+#include "LayoutTestController.h"
+#include "WorkQueue.h"
+#include "WorkQueueItem.h"
+
+#include <JavaScriptCore/JavaScript.h>
+
+#include <wx/wx.h>
+#include "WebView.h"
+#include "WebFrame.h"
+#include "WebBrowserShell.h"
+
+#include <wtf/Assertions.h>
+
+#include <cassert>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+volatile bool done = true;
+volatile bool notified = false;
+static bool printSeparators = true;
+static int dumpPixels;
+static int dumpTree = 1;
+time_t startTime; // to detect timeouts / failed tests
+
+using namespace std;
+
+FILE* logOutput;
+
+RefPtr<LayoutTestController> gLayoutTestController;
+static wxWebView* webView;
+static wxTimer* idleTimer;
+
+const unsigned timeOut = 10;
+const unsigned maxViewHeight = 600;
+const unsigned maxViewWidth = 800;
+
+class LayoutWebViewEventHandler : public wxEvtHandler {
+
+public:
+ LayoutWebViewEventHandler(wxWebView* webView)
+ : m_webView(webView)
+ {
+ }
+
+ void bindEvents()
+ {
+ m_webView->Connect(wxEVT_WEBVIEW_LOAD, wxWebViewLoadEventHandler(LayoutWebViewEventHandler::OnLoadEvent), NULL, this);
+ m_webView->Connect(wxEVT_WEBVIEW_JS_ALERT, wxWebViewAlertEventHandler(LayoutWebViewEventHandler::OnAlertEvent), NULL, this);
+ m_webView->Connect(wxEVT_WEBVIEW_JS_CONFIRM, wxWebViewConfirmEventHandler(LayoutWebViewEventHandler::OnConfirmEvent), NULL, this);
+ m_webView->Connect(wxEVT_WEBVIEW_JS_PROMPT, wxWebViewPromptEventHandler(LayoutWebViewEventHandler::OnPromptEvent), NULL, this);
+ m_webView->Connect(wxEVT_WEBVIEW_CONSOLE_MESSAGE, wxWebViewConsoleMessageEventHandler(LayoutWebViewEventHandler::OnConsoleMessageEvent), NULL, this);
+ m_webView->Connect(wxEVT_WEBVIEW_RECEIVED_TITLE, wxWebViewReceivedTitleEventHandler(LayoutWebViewEventHandler::OnReceivedTitleEvent), NULL, this);
+ m_webView->Connect(wxEVT_WEBVIEW_WINDOW_OBJECT_CLEARED, wxWebViewWindowObjectClearedEventHandler(LayoutWebViewEventHandler::OnWindowObjectClearedEvent), NULL, this);
+ }
+
+ void OnLoadEvent(wxWebViewLoadEvent& event)
+ {
+
+ if (event.GetState() == wxWEBVIEW_LOAD_FAILED || event.GetState() == wxWEBVIEW_LOAD_STOPPED)
+ done = true;
+
+ if (event.GetState() == wxWEBVIEW_LOAD_ONLOAD_HANDLED) {
+ done = true;
+
+ if (!gLayoutTestController->waitToDump() || notified) {
+ dump();
+ }
+ }
+ }
+
+ void OnAlertEvent(wxWebViewAlertEvent& event)
+ {
+ fprintf(stdout, "ALERT: %S\n", event.GetMessage().c_str());
+ }
+
+ void OnConfirmEvent(wxWebViewConfirmEvent& event)
+ {
+ fprintf(stdout, "CONFIRM: %S\n", event.GetMessage().c_str());
+ event.SetReturnCode(1);
+ }
+
+ void OnPromptEvent(wxWebViewPromptEvent& event)
+ {
+ fprintf(stdout, "PROMPT: %S, default text: %S\n", event.GetMessage().c_str(), event.GetResponse().c_str());
+ event.SetReturnCode(1);
+ }
+
+ void OnConsoleMessageEvent(wxWebViewConsoleMessageEvent& event)
+ {
+ fprintf(stdout, "CONSOLE MESSAGE: line %d: %S\n", event.GetLineNumber(), event.GetMessage().c_str());
+ }
+
+ void OnReceivedTitleEvent(wxWebViewReceivedTitleEvent& event)
+ {
+ if (gLayoutTestController->dumpTitleChanges() && !done) {
+ const char* title = event.GetTitle().mb_str(wxConvUTF8);
+ printf("TITLE CHANGED: %S\n", title ? title : "");
+ }
+ }
+
+ void OnWindowObjectClearedEvent(wxWebViewWindowObjectClearedEvent& event)
+ {
+ JSValueRef exception = 0;
+ gLayoutTestController->makeWindowObject(event.GetJSContext(), event.GetWindowObject(), &exception);
+ }
+
+private:
+ wxWebView* m_webView;
+
+};
+
+void notifyDoneFired()
+{
+ notified = true;
+ if (done)
+ dump();
+}
+
+LayoutWebViewEventHandler* eventHandler = NULL;
+
+static wxString dumpFramesAsText(wxWebFrame* frame)
+{
+ // TODO: implement this. leaving this here so we don't forget this case.
+ if (gLayoutTestController->dumpChildFramesAsText()) {
+ }
+
+ return frame->GetInnerText();
+}
+
+void dump()
+{
+ if (!done)
+ return;
+
+ if (gLayoutTestController->waitToDump() && !notified)
+ return;
+
+ if (dumpTree) {
+ const char* result = 0;
+
+ bool dumpAsText = gLayoutTestController->dumpAsText();
+ wxString str;
+ if (gLayoutTestController->dumpAsText())
+ str = dumpFramesAsText(webView->GetMainFrame());
+ else
+ str = webView->GetMainFrame()->GetExternalRepresentation();
+
+ result = str.ToUTF8();
+ if (!result) {
+ const char* errorMessage;
+ if (gLayoutTestController->dumpAsText())
+ errorMessage = "WebFrame::GetInnerText";
+ else
+ errorMessage = "WebFrame::GetExternalRepresentation";
+ printf("ERROR: NULL result from %s", errorMessage);
+ } else {
+ printf("%s\n", result);
+ }
+
+ if (gLayoutTestController->dumpBackForwardList()) {
+ // FIXME: not implemented
+ }
+
+ if (printSeparators) {
+ puts("#EOF");
+ fputs("#EOF\n", stderr);
+ fflush(stdout);
+ fflush(stderr);
+ }
+ }
+
+ if (dumpPixels
+ && gLayoutTestController->generatePixelResults()
+ && !gLayoutTestController->dumpDOMAsWebArchive()
+ && !gLayoutTestController->dumpSourceAsWebArchive()) {
+ // FIXME: Add support for dumping pixels
+ fflush(stdout);
+ }
+
+ puts("#EOF");
+ fflush(stdout);
+ fflush(stderr);
+
+ gLayoutTestController.clear();
+}
+
+static void runTest(const wxString testPathOrURL)
+{
+ done = false;
+ time(&startTime);
+ string pathOrURLString(testPathOrURL.char_str());
+ string pathOrURL(pathOrURLString);
+ string expectedPixelHash;
+
+ size_t separatorPos = pathOrURL.find("'");
+ if (separatorPos != string::npos) {
+ pathOrURL = string(pathOrURLString, 0, separatorPos);
+ expectedPixelHash = string(pathOrURLString, separatorPos + 1);
+ }
+
+ // CURL isn't happy if we don't have a protocol.
+ size_t http = pathOrURL.find("http://");
+ if (http == string::npos)
+ pathOrURL.insert(0, "file://");
+
+ gLayoutTestController = LayoutTestController::create(pathOrURL, expectedPixelHash);
+ if (!gLayoutTestController) {
+ wxTheApp->ExitMainLoop();
+ }
+
+ WorkQueue::shared()->clear();
+ WorkQueue::shared()->setFrozen(false);
+
+ webView->LoadURL(wxString(pathOrURL.c_str(), wxConvUTF8));
+
+ // wait until load completes and the results are dumped
+ while (!done)
+ wxSafeYield();
+}
+
+class MyApp : public wxApp
+{
+public:
+
+ virtual bool OnInit();
+
+private:
+ wxLog* logger;
+};
+
+
+IMPLEMENT_APP(MyApp)
+
+bool MyApp::OnInit()
+{
+ logOutput = fopen("output.txt", "ab");
+ if (logOutput) {
+ logger = new wxLogStderr(logOutput);
+ wxLog::SetActiveTarget(logger);
+ }
+
+ wxLogMessage(wxT("Starting DumpRenderTool, %d args.\n"), argc);
+
+ for (int i = 1; i < argc; ++i) {
+ wxString option = wxString(argv[i]);
+ if (!option.CmpNoCase(_T("--notree"))) {
+ dumpTree = false;
+ continue;
+ }
+
+ if (!option.CmpNoCase(_T("--pixel-tests"))) {
+ dumpPixels = true;
+ continue;
+ }
+
+ if (!option.CmpNoCase(_T("--tree"))) {
+ dumpTree = true;
+ continue;
+ }
+ }
+ wxInitAllImageHandlers();
+
+ // create the main application window
+ wxWebBrowserShell* webFrame = new wxWebBrowserShell(_T("wxWebKit DumpRenderTree App"), "about:blank");
+ SetTopWindow(webFrame);
+ webView = webFrame->webview;
+ webView->SetSize(wxSize(maxViewWidth, maxViewHeight));
+
+ if (!eventHandler) {
+ eventHandler = new LayoutWebViewEventHandler(webView);
+ eventHandler->bindEvents();
+ }
+
+ int optind = 1;
+ time(&startTime);
+ wxString option_str = wxString(argv[optind]);
+ if (argc == optind+1 && option_str.Find(_T("-")) == 0) {
+ char filenameBuffer[2048];
+ while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
+ wxString filename = wxString::FromUTF8(filenameBuffer);
+ char* newLineCharacter = strchr(filenameBuffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (strlen(filenameBuffer) == 0)
+ return 0;
+ wxLogMessage(wxT("Running test %S.\n"), filenameBuffer);
+ runTest(filename);
+ }
+
+ } else {
+ printSeparators = (optind < argc-1 || (dumpPixels && dumpTree));
+ for (int i = optind; i != argc; ++i) {
+ runTest(wxTheApp->argv[1]);
+ }
+ }
+
+ webFrame->Close();
+ delete eventHandler;
+
+ wxLog::SetActiveTarget(NULL);
+ delete logger;
+ fclose(logOutput);
+
+ // returning false shuts the app down
+ return false;
+}
diff --git a/Tools/DumpRenderTree/wx/DumpRenderTreeWx.h b/Tools/DumpRenderTree/wx/DumpRenderTreeWx.h
new file mode 100644
index 000000000..99092b845
--- /dev/null
+++ b/Tools/DumpRenderTree/wx/DumpRenderTreeWx.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 DumpRenderTreeWx_h
+#define DumpRenderTreeWx_h
+
+extern void notifyDoneFired();
+
+#endif // DumpRenderTreeWx_h
diff --git a/Tools/DumpRenderTree/wx/GCControllerWx.cpp b/Tools/DumpRenderTree/wx/GCControllerWx.cpp
new file mode 100644
index 000000000..bddf62ffb
--- /dev/null
+++ b/Tools/DumpRenderTree/wx/GCControllerWx.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "GCController.h"
+
+void GCController::collect() const
+{
+}
+
+void GCController::collectOnAlternateThread(bool waitUntilDone) const
+{
+}
+
+size_t GCController::getJSObjectCount() const
+{
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp b/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
new file mode 100644
index 000000000..cfd1f6dd6
--- /dev/null
+++ b/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "LayoutTestController.h"
+
+#include "DumpRenderTree.h"
+#include "WorkQueue.h"
+#include "WorkQueueItem.h"
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+
+#include <stdio.h>
+
+
+
+LayoutTestController::~LayoutTestController()
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::addDisallowedURL(JSStringRef url)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::clearBackForwardList()
+{
+}
+
+JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name)
+{
+ // FIXME: implement
+ return 0;
+}
+
+JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name)
+{
+ // FIXME: implement
+ return 0;
+}
+
+void LayoutTestController::dispatchPendingLoadRequests()
+{
+ // FIXME: Implement for testing fix for 6727495
+}
+
+void LayoutTestController::display()
+{
+}
+
+void LayoutTestController::keepWebHistory()
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::notifyDone()
+{
+ if (m_waitToDump && !WorkQueue::shared()->count())
+ notifyDoneFired();
+ m_waitToDump = false;
+}
+
+JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url)
+{
+ // Function introduced in r28690. This may need special-casing on Windows.
+ return JSStringRetain(url); // Do nothing on Unix.
+}
+
+void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target)
+{
+ // FIXME: We need to resolve relative URLs here
+ WorkQueue::shared()->queue(new LoadItem(url, target));
+}
+
+void LayoutTestController::setAcceptsEditing(bool acceptsEditing)
+{
+}
+
+void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
+{
+ // FIXME: Implement this (and restore the default value before running each test in DumpRenderTree.cpp).
+}
+
+void LayoutTestController::setCustomPolicyDelegate(bool, bool)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setUserStyleSheetEnabled(bool flag)
+{
+}
+
+void LayoutTestController::setUserStyleSheetLocation(JSStringRef path)
+{
+}
+
+void LayoutTestController::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setViewModeMediaFeature(JSStringRef mode)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setWindowIsKey(bool windowIsKey)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(bool flag)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setJavaScriptProfilingEnabled(bool flag)
+{
+}
+
+void LayoutTestController::setWaitToDump(bool waitUntilDone)
+{
+ static const int timeoutSeconds = 10;
+
+ m_waitToDump = waitUntilDone;
+}
+
+int LayoutTestController::windowCount()
+{
+ // FIXME: implement
+ return 1;
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setJavaScriptCanAccessClipboard(bool enabled)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setXSSAuditorEnabled(bool enabled)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setAutofilled(JSContextRef, JSValueRef element, bool isAutofilled)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setPopupBlockingEnabled(bool popupBlockingEnabled)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setPluginsEnabled(bool flag)
+{
+ // FIXME: Implement
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef id)
+{
+ // FIXME: implement
+ return false;
+}
+
+void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::clearPersistentUserStyleSheet()
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::clearAllApplicationCaches()
+{
+ // FIXME: Implement to support application cache quotas.
+}
+
+void LayoutTestController::clearApplicationCacheForOrigin(JSStringRef url)
+{
+ // FIXME: Implement to support deleting all application cache for an origin.
+}
+
+long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef originIdentifier)
+{
+ // FIXME: Implement to support getting disk usage in bytes for an origin.
+ return 0;
+}
+
+void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota)
+{
+ // FIXME: Implement to support application cache quotas.
+}
+
+long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef origin)
+{
+ // FIXME: Implement to support getting disk usage by all application caches for an origin.
+ return 0;
+}
+
+
+JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context)
+{
+ // FIXME: Implement to get origins that have application caches.
+ return 0;
+}
+
+void LayoutTestController::clearAllDatabases()
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setDatabaseQuota(unsigned long long quota)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::goBack()
+{
+ // FIXME: implement to enable loader/navigation-while-deferring-loads.html
+}
+
+void LayoutTestController::setDefersLoading(bool)
+{
+ // FIXME: implement to enable loader/navigation-while-deferring-loads.html
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool, JSStringRef)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setAppCacheMaximumSize(unsigned long long size)
+{
+ // FIXME: implement
+}
+
+unsigned LayoutTestController::numberOfActiveAnimations() const
+{
+ // FIXME: implement
+ return 0;
+}
+
+void LayoutTestController::suspendAnimations() const
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::resumeAnimations() const
+{
+ // FIXME: implement
+}
+
+unsigned LayoutTestController::workerThreadCount() const
+{
+ // FIXME: implement
+ return 0;
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag)
+{
+ // FIXME: implement
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId)
+{
+ // FIXME: implement
+ return false;
+}
+
+void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
+{
+ // FIXME: Implement for DeviceOrientation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=30335.
+}
+
+void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
+{
+ // FIXME: Implement for Geolocation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=28264.
+}
+
+void LayoutTestController::setMockGeolocationError(int code, JSStringRef message)
+{
+ // FIXME: Implement for Geolocation layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=28264.
+}
+
+void LayoutTestController::setGeolocationPermission(bool allow)
+{
+ // FIXME: Implement for Geolocation layout tests.
+ setGeolocationPermissionCommon(allow);
+}
+
+int LayoutTestController::numberOfPendingGeolocationPermissionRequests()
+{
+ // FIXME: Implement for Geolocation layout tests.
+ return -1;
+}
+
+void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::startSpeechInput(JSContextRef inputElement)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled)
+{
+ // FIXME: implement
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
+{
+ // FIXME: implement
+ return false;
+}
+
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
+{
+ // FIXME: implement
+ return false;
+}
+
+void LayoutTestController::setCacheModel(int)
+{
+ // FIXME: implement
+}
+
+bool LayoutTestController::isCommandEnabled(JSStringRef /*name*/)
+{
+ // FIXME: implement
+ return false;
+}
+
+size_t LayoutTestController::webHistoryItemCount()
+{
+ // FIXME: implement
+ return 0;
+}
+
+void LayoutTestController::waitForPolicyDelegate()
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::overridePreference(JSStringRef /* key */, JSStringRef /* value */)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
+{
+ printf("LayoutTestController::addUserScript not implemented.\n");
+}
+
+void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames)
+{
+ printf("LayoutTestController::addUserStyleSheet not implemented.\n");
+}
+
+void LayoutTestController::showWebInspector()
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::closeWebInspector()
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script)
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::removeAllVisitedLinks()
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
+{
+
+}
+
+void LayoutTestController::disableImageLoading()
+{
+
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
+{
+ // FIXME: implement
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id)
+{
+ return 0;
+}
+
+int LayoutTestController::pageNumberForElementById(JSStringRef, float, float)
+{
+ // FIXME: implement
+ return -1;
+}
+
+int LayoutTestController::numberOfPages(float, float)
+{
+ // FIXME: implement
+ return -1;
+}
+
+void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL)
+{
+
+}
+
+void LayoutTestController::apiTestGoToCurrentBackForwardItem()
+{
+
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool)
+{
+
+}
+
+void LayoutTestController::setWebViewEditable(bool)
+{
+}
+
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ return false;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ return 0;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const
+{
+ return 0;
+}
+
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef, JSValueRef)
+{
+ return 0;
+}
+
+JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping)
+{
+ // FIXME: Implement this.
+ return 0;
+}
+
+void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
+{
+}
+
+void LayoutTestController::setEditingBehavior(const char* editingBehavior)
+{
+ // FIXME: Implement
+}
+
+void LayoutTestController::abortModal()
+{
+}
+
+bool LayoutTestController::hasSpellingMarker(int, int)
+{
+ // FIXME: Implement
+ return false;
+}
+
+bool LayoutTestController::hasGrammarMarker(int, int)
+{
+ // FIXME: Implement
+ return false;
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int /*deviceDPI*/, int /*deviceWidth*/, int /*deviceHeight*/, int /*availableWidth*/, int /*availableHeight*/)
+{
+ // FIXME: Implement
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const
+{
+ // FIXME: Implement
+ return 0;
+}
+
+bool LayoutTestController::isPageBoxVisible(int pageNumber) const
+{
+ // FIXME: Implement
+ return true;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const
+{
+ // FIXME: Implement
+ return 0;
+}
+
+void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool)
+{
+ // FIXME: Implement this.
+}
+
+bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray)
+{
+ // FIXME: Implement
+ return false;
+}
+
+void LayoutTestController::setSerializeHTTPLoads(bool)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::setMinimumTimerInterval(double interval) {
+
+}
+
+void LayoutTestController::syncLocalStorage()
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::observeStorageTrackerNotifications(unsigned number)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::deleteAllLocalStorage()
+{
+ // FIXME: Implement.
+}
+
+JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context)
+{
+ // FIXME: Implement.
+ return 0;
+}
+
+void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef URL)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::setTextDirection(JSStringRef direction)
+{
+ // FIXME: Implement.
+}
+
+void LayoutTestController::allowRoundingHacks()
+{
+}
+
+void LayoutTestController::addChromeInputField()
+{
+}
+
+void LayoutTestController::removeChromeInputField()
+{
+}
+
+void LayoutTestController::focusWebView()
+{
+}
+
+void LayoutTestController::setBackingScaleFactor(double)
+{
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title)
+{
+ // FIXME: Implement.
+}
diff --git a/Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp b/Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp
new file mode 100644
index 000000000..e6ecb752b
--- /dev/null
+++ b/Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "WorkQueueItem.h"
+
+#include "DumpRenderTree.h"
+
+bool LoadItem::invoke() const
+{
+ return false;
+}
+
+bool LoadHTMLStringItem::invoke() const
+{
+ return false;
+}
+
+bool ReloadItem::invoke() const
+{
+ return false;
+}
+
+bool ScriptItem::invoke() const
+{
+ return false;
+}
+
+bool BackForwardItem::invoke() const
+{
+ return false;
+}